【硬件模块】SSD1306 OLED屏幕(含GD32ESP32驱动代码)

news2025/2/28 6:45:14

OLED屏幕

最近在写GD32的文章,之前STM32有OLED屏幕来展示数据,ESP32可以直接打印到电脑屏幕上,GD32的话手上就没有办法了。

虽然是可以直接把STM32的OLED屏幕的驱动代码改改移植到GD32上面,不过想了想干脆写一个文章来说说如何驱动,也当是锻炼一下看文档的能力了。

没错,SSD1306也是只有英文文档,找网站直接翻译中文的效果不太好,不过我还是把译文结合原文再看看江科大的STM32的OLED驱动代码给啃了啃,因此这很考验我的耐心。

OLED,全称为Organic Light-Emitting Diode,中文名称为有机发光显示器或有机电激光显示。它属于一种电流型的有机发光器件,工作原理主要是通过载流子的注入和复合来实现发光现象,发光强度与注入的电流成正比。

OLED的基本结构包括ITO透明电极和金属电极,分别作为器件的阳极和阴极。在一定的电压驱动下,电子和空穴分别从阴极和阳极注入到电子和空穴传输层,然后经过各自的传输层迁移到发光层。在发光层中,电子和空穴相遇并产生能量激子,这些激子激发发光分子,最终发出可见光。

OLED具有许多显著的优势。首先,它的厚度可以小于1毫米,仅为LCD屏幕的1/3,并且重量也更轻。其次,由于其固态结构,没有液体物质,因此抗震性能更好,不怕摔。此外,OLED几乎没有可视角度的问题,即使在很大的视角下观看,画面仍然不失真。它的响应时间也非常快,是LCD的千分之一,因此在显示运动画面时绝对不会有拖影的现象。同时,OLED的低温特性好,在零下40度时仍能正常显示,而LCD则无法做到。再者,OLED的发光效率更高,能耗比LCD还要低。最后,OLED还能够在不同材质的基板上制造,因此可以做成能弯曲的柔软显示器。

然而,OLED也存在一些缺点。例如,其寿命通常只有5000小时,要低于LCD至少1万小时的寿命。此外,目前的技术还不能实现大尺寸屏幕的量产,因此,目前OLED主要适用于便携类的数码类产品。同时,OLED还存在色彩纯度不够的问题,不容易显示出鲜艳、浓郁的色彩。

目前,OLED已经广泛应用于多个领域。在移动设备中,如智能手机、平板电脑和可穿戴设备,OLED屏幕的应用非常普遍。在汽车领域,OLED技术被用于车载显示屏、仪表盘和车内照明等,提供清晰、生动的车载信息显示。在数字广告领域,OLED屏幕的透明度和灵活性使其成为理想的广告展示工具。在医疗设备中,OLED屏幕的高对比度和细腻的图像质量使得医疗专业人员能够清晰地观察和分析相关数据和图像。此外,OLED还在航空航天、智能家居、游戏设备和虚拟现实等领域得到了应用。

总的来说,OLED作为一种先进的显示技术,具有许多独特的优势,并在多个领域得到了广泛的应用。随着技术的不断进步,相信OLED在未来会有更加广阔的发展前景。

以上介绍来自文心一言。

看看文档

SSD1306支持SPI和I2C,不过我们买的基本上都是封装好的模块,具体用SPI还是I2C就得看模块的引脚了。四个引脚的就是I2C,七个引脚(也不一定)的是SPI。

我手上的是I2C的,因此就主要看看I2C的部分。

STM32的I2C的软件驱动可以参考我之前的文章,我直接贴下面(小改了一点,删了一部分用不到的),复制粘贴即可使用。

#define SCL_Pin GPIO_Pin_0
#define SDA_Pin GPIO_Pin_1
 
void Z_I2C_Init(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_Out_OD;        
    itd.GPIO_Pin=SCL_Pin|SDA_Pin;    
    itd.GPIO_Speed=GPIO_Speed_50MHz;                   
    GPIO_Init(GPIOA,&itd);
 
    GPIO_WriteBit(GPIOA,SCL_Pin,Bit_SET);       //SCL和SDA默认都是高电平
    GPIO_WriteBit(GPIOA,SDA_Pin,Bit_SET);       //因此初始化后设为高电平
}
    
void Z_I2C_SetSCL(uint8_t signal){
    if(signal==1) GPIO_WriteBit(GPIOA,SCL_Pin,Bit_SET);
    else GPIO_WriteBit(GPIOA,SCL_Pin,Bit_RESET);
}
 
void Z_I2C_SetSDA(uint8_t signal){
    if(signal==1) GPIO_WriteBit(GPIOA,SDA_Pin,Bit_SET);
    else GPIO_WriteBit(GPIOA,SDA_Pin,Bit_RESET);
}
 
uint8_t Z_I2C_GetSDA(void){
    return GPIO_ReadInputDataBit(GPIOA,SDA_Pin);
}
 
void Z_I2C_Start(void){
    Z_I2C_SetSDA(1);
    Z_I2C_SetSCL(1);
    Z_I2C_SetSDA(0);
    Z_I2C_SetSCL(0);
}
 
void Z_I2C_End(){
    Z_I2C_SetSDA(0);
    Z_I2C_SetSCL(1);
    Z_I2C_SetSDA(1);
}
 
void Z_I2C_SendByte(uint8_t byte){
    Z_I2C_SetSCL(0);
    for(int i=0;i<8;++i){
        if((byte&0x80)==0) Z_I2C_SetSDA(0);
        else Z_I2C_SetSDA(1);
        byte<<=1;
        Z_I2C_SetSCL(1);
        Z_I2C_SetSCL(0);
    }
    //多一个时钟时序,跳过ACK应答
    Z_I2C_SetSCL(1);
    Z_I2C_SetSCL(0);
}

获取到了从机地址,可以是0111100(七位地址,0x78),也可以是0111101(0x7A),这个需要先记下,一会通信的时候需要。

下一个是数据的格式。

首先是I2C的起始时序,接着是发送Control byte(我这里理解为控制位)和数据,最后再一个I2C的结束时序。这是很标准的I2C时序。

另外关于Control byte中的C0和D/C#是什么意思我们还需要接着往下看。

主要看红框框出来的就行,因为我们基本上不需要向SSD1306读取数据。

当D/C#为0以及R/W#为0时属于写命令的模式,当D/C#为1以及R/W#为0时属于写数据的模式。

根据上面几点我们就可以封装一下向SSD1306写命令和写数据的函数了。

#define Z_OLED_COMMAND  0
#define Z_OLED_DATA     1

void Z_OLED_Write(uint8_t Data,uint8_t command)
{
    Z_I2C_Start();
    Z_I2C_SendByte(0x78);       //0111 1000
    Z_I2C_SendByte( command == Z_OLED_COMMAND ? 0x00 : 0x40);   //根据参数来决定是写命令还是写数据
    Z_I2C_SendByte(Data);
    Z_I2C_End();
}

命令

了解了上面的时序以及如何发送命令或数据之后,接下来最重要的就是了解我们能用哪些命令去让OLED屏幕亮起来了。

参考一下我们之前是如何让ST7735S驱动TFT屏幕亮起来的。

我们首先是框选出了一个区域,然后再传入要塞满这个区域的数据,因此我们首先是要框选区域。

使用上面这俩命令可以指定我们我们选定区域的列。

这边我们需要先回头看看SSD1306是怎么划分整个屏幕的。

我们屏幕大小是64*128像素的。

其中128就是每一行都有128个像素,而其中的64分为了8个页,也就是说每个页都是8*128像素的。

上面两个命令就是指定从哪一列(128像素中的)开始框选区域的。

两个命令它们都不是单纯的指令,它们的命令是一个范围,第一次碰到的小伙伴可能会迷糊。我们可以理解成它们不只是命令,而是命令加数据的。

这俩命令的前四位才是指令,后四位是传递的数据。

比如说我现在要指定第100列(0110 0100)为起始列。

那么我需要发送上面两条指令来指定这个100列为起始列。

首先是数据低4位,100的二进制低四位是(0100),那么我配合上上面的命令就是需要发送0x04(0x00 | 0x04(0100))。

同理,发送数据高四位则是0x16(0x10 | 0x06(0110))。

这样,发送了两条命令我们就指定好了框选区域的起始列。

那么接下来我们还需要指定结束列才可以选择一段范围对吧。不过实际上我们不需要指定,因为每次写入数据,都会写8列。

指定完列范围,接下来就是指定行范围了。

首先我们需要知道SSD1306的三种寻址模式。

第一个,也是默认的。每次都是只写入一页,换页的话需要额外发送指定列的命令。 

第二个,写完一页会自动换到下一页。 

 第三个,从列开始写,写完一列就换下一列(基本不用)。

我们默认是第一个,通常也不需要修改。第一种寻址模式一次写入一页。那么对应到我们选取区域,我们就选择一个页号即可,因为一页是高8像素的,指定了页号就算是把起始行和结束行都指定了。

我们使用下面这个命令。

那么了解了上面几个命令之后我们就可以去显示一些东西了。

只需要先发送命令来指定区域,然后再发送数据(像素点数据)去塞满这区域即可。

不过在此之前我们还有一个步骤需要完成,那就是初始化代码,一般来说卖屏幕的都会提供给咱,我们直接拿来用,把对应的函数名改改就行。那么我这边就不展示了,我直接把江科大的初始化命令拿过来用。

STM32实操代码

下面代码非常简略,只有显示一个大写字符的功能(因为我懒,并且其他功能都可以由写一个字符延伸来开,因此没有写其他的函数了)。

并且写的非常不规范,比如说字模数组我直接放在了.c文件里(还是因为懒)。

很大一部分是抄的江科大的,因为这类模块驱动我们基本上不需要自己写,大概率早有先驱给我们写好了,商家一般不止提供初始化命令的代码,甚至驱动都会直接给我们,这边写一写主要还是以了解、学习模块为主要目的,因此写个大概意思意思就行了。

 STM32的代码我就写一点,完整的可以去b站找江科大,下面GD32和ESP32的代码我就直接把江科大的代码完整移植过去了。全部代码包括取字模的软件我都会打包放公众号,关注公众号“折途想要敲代码”回复关键词“OLED”即可免费下载。

Z_OLED.c

#include "Z_OLED.h"
const uint8_t Z_OLED_FONT_CHAR[][16] ={
    0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,
	0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 
	
	0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,
	0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 
	
	0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,
	0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 
	
	0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,
	0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 
	
	0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
	0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 
	
	0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
	0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 
	
	0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,
	0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 
	
	0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
	0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H
	
	0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,
	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 
	
	0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,
	0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 
	
	0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,
	0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 
	
	0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,
	0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 
	
	0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,
	0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 
	
	0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,
	0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 
	
	0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
	0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 
	
	0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,
	0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 
	
	0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
	0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 
	
	0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,
	0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 
	
	0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,
	0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 
	
	0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,
	0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 
	
	0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
	0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 
	
	0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,
	0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 
	
	0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,
	0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 
	
	0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,
	0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 
	
	0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,
	0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 
	
	0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,
	0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 
};

#define SCL_Pin GPIO_Pin_8
#define SDA_Pin GPIO_Pin_9
#define OLED_GPIO   GPIOB 

void Z_I2C_Init(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_Out_OD;        
    itd.GPIO_Pin=SCL_Pin|SDA_Pin;    
    itd.GPIO_Speed=GPIO_Speed_50MHz;                   
    GPIO_Init(OLED_GPIO,&itd);
 
    GPIO_WriteBit(OLED_GPIO,SCL_Pin,Bit_SET);       //SCL和SDA默认都是高电平
    GPIO_WriteBit(OLED_GPIO,SDA_Pin,Bit_SET);       //因此初始化后设为高电平
}
    
void Z_I2C_SetSCL(uint8_t signal){
    if(signal==1) GPIO_WriteBit(OLED_GPIO,SCL_Pin,Bit_SET);
    else GPIO_WriteBit(OLED_GPIO,SCL_Pin,Bit_RESET);
}
 
void Z_I2C_SetSDA(uint8_t signal){
    if(signal==1) GPIO_WriteBit(OLED_GPIO,SDA_Pin,Bit_SET);
    else GPIO_WriteBit(OLED_GPIO,SDA_Pin,Bit_RESET);
}

 
void Z_I2C_Start(void){
    Z_I2C_SetSDA(1);
    Z_I2C_SetSCL(1);
    Z_I2C_SetSDA(0);
    Z_I2C_SetSCL(0);
}
 
void Z_I2C_End(){
    Z_I2C_SetSDA(0);
    Z_I2C_SetSCL(1);
    Z_I2C_SetSDA(1);
}
 
void Z_I2C_SendByte(uint8_t byte){
    Z_I2C_SetSCL(0);
    for(int i=0;i<8;++i){
        if((byte&0x80)==0) Z_I2C_SetSDA(0);
        else Z_I2C_SetSDA(1);
        byte<<=1;
        Z_I2C_SetSCL(1);
        Z_I2C_SetSCL(0);
    }
    //多一个时钟时序,跳过ACK应答
    Z_I2C_SetSCL(1);
    Z_I2C_SetSCL(0);
}
 
 
void Z_I2C_SendACK(uint8_t ack){
    if(ack==0) Z_I2C_SetSDA(0);
    else Z_I2C_SetSDA(1);
    Z_I2C_SetSCL(1);
    Z_I2C_SetSCL(0);
}

#define Z_OLED_COMMAND  0
#define Z_OLED_DATA     1

void Z_OLED_Write(uint8_t Data,uint8_t command)
{
    Z_I2C_Start();
    Z_I2C_SendByte(0x78);       //0111 1000
    Z_I2C_SendByte( command == Z_OLED_COMMAND ? 0x00 : 0x40);   //根据参数来决定是写命令还是写数据
    Z_I2C_SendByte(Data);
    Z_I2C_End();
}

void Z_OLED_SpecifyScope(uint8_t page,uint8_t col){
    Z_OLED_Write(0xB0|page,Z_OLED_COMMAND);
    Z_OLED_Write(0x00|(col&0x0F),Z_OLED_COMMAND);
    Z_OLED_Write(0x10|((col&0xF0)>>4),Z_OLED_COMMAND);
}


void Z_OLED_Clear(void){
    for (uint8_t j=0;j<8;j++){
        Z_OLED_SpecifyScope(j, 0);
        for(uint8_t i=0;i < 128; i++){
            Z_OLED_Write(0x00,Z_OLED_DATA);
        }
    }
}

void Z_OLED_ShowChar(uint8_t row,uint8_t col,char ch){
    Z_OLED_SpecifyScope((row-1)*2,col);
    for (uint8_t i=0;i<8;i++){
        Z_OLED_Write(Z_OLED_FONT_CHAR[ch-'A'][i],Z_OLED_DATA);
    }
    Z_OLED_SpecifyScope((row-1)*2+1,col);
    for (uint8_t i=0;i<8;i++){
        Z_OLED_Write(Z_OLED_FONT_CHAR[ch-'A'][i+8],Z_OLED_DATA);
    }    
}

void Z_OLED_Init(void){
    Z_I2C_Init();			//端口初始化
    
    Z_OLED_Write(0xAE,Z_OLED_COMMAND);	//关闭显示
    
    Z_OLED_Write(0xD5,Z_OLED_COMMAND);	//设置显示时钟分频比/振荡器频率
    Z_OLED_Write(0x80,Z_OLED_COMMAND);
    
    Z_OLED_Write(0xA8,Z_OLED_COMMAND);	//设置多路复用率
    Z_OLED_Write(0x3F,Z_OLED_COMMAND);
    
    Z_OLED_Write(0xD3,Z_OLED_COMMAND);	//设置显示偏移
    Z_OLED_Write(0x00,Z_OLED_COMMAND);
    
    Z_OLED_Write(0x40,Z_OLED_COMMAND);	//设置显示开始行
    
    Z_OLED_Write(0xA1,Z_OLED_COMMAND);	//设置左右方向,0xA1正常 0xA0左右反置
    
    Z_OLED_Write(0xC8,Z_OLED_COMMAND);	//设置上下方向,0xC8正常 0xC0上下反置

    Z_OLED_Write(0xDA,Z_OLED_COMMAND);	//设置COM引脚硬件配置
    Z_OLED_Write(0x12,Z_OLED_COMMAND);
    
    Z_OLED_Write(0x81,Z_OLED_COMMAND);	//设置对比度控制
    Z_OLED_Write(0xCF,Z_OLED_COMMAND);

    Z_OLED_Write(0xD9,Z_OLED_COMMAND);	//设置预充电周期
    Z_OLED_Write(0xF1,Z_OLED_COMMAND);

    Z_OLED_Write(0xDB,Z_OLED_COMMAND);	//设置VCOMH取消选择级别
    Z_OLED_Write(0x30,Z_OLED_COMMAND);

    Z_OLED_Write(0xA4,Z_OLED_COMMAND);	//设置整个显示打开/关闭

    Z_OLED_Write(0xA6,Z_OLED_COMMAND);	//设置正常/倒转显示

    Z_OLED_Write(0x8D,Z_OLED_COMMAND);	//设置充电泵
    Z_OLED_Write(0x14,Z_OLED_COMMAND);

    Z_OLED_Write(0xAF,Z_OLED_COMMAND);	//开启显示
        
    Z_OLED_Clear();				//OLED清屏
}





Z_OLED.h

#ifndef Z_OLED_H
#define Z_OLED_H

#include "stm32f10x.h" 

void Z_OLED_Init(void);
void Z_OLED_ShowChar(uint8_t row,uint8_t col,char ch);
void Z_OLED_Clear(void);

#endif


main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Z_OLED.h"

int main(void){
    Z_OLED_Init();
    
    while(1){
        Z_OLED_ShowChar(1,0,'A');
        Delay_ms(500);
        Z_OLED_ShowChar(1,10,'B');
        Delay_ms(500);
        Z_OLED_ShowChar(1,20,'C');
    }
    
}

 

GD32驱动移植代码

OLED.h

#ifndef __OLED_H
#define __OLED_H

void OLED_Init(void);
void OLED_Clear(void);
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);

#endif

OLED.c

#include "gd32e23x.h"
#include "systick.h"
#include "OLED_Font.h"

#define OLED_SCL_GPIO   GPIO_PIN_0
#define OLED_SDA_GPIO   GPIO_PIN_1
/*引脚配置*/
#define OLED_W_SCL(x)       gpio_bit_write(GPIOA,OLED_SCL_GPIO,x)
#define OLED_W_SDA(x)       gpio_bit_write(GPIOA,OLED_SDA_GPIO,x)

/*引脚初始化*/
void OLED_I2C_Init(void){
    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_mode_set(GPIOA,GPIO_MODE_OUTPUT,GPIO_PUPD_NONE,OLED_SCL_GPIO);
    gpio_mode_set(GPIOA,GPIO_MODE_OUTPUT,GPIO_PUPD_NONE,OLED_SDA_GPIO);
    gpio_output_options_set(GPIOA,GPIO_OTYPE_OD,GPIO_OSPEED_50MHZ,OLED_SCL_GPIO);
    gpio_output_options_set(GPIOA,GPIO_OTYPE_OD,GPIO_OSPEED_50MHZ,OLED_SDA_GPIO);
    
    OLED_W_SCL(1);
    OLED_W_SDA(1);
}

/**
  * @brief  I2C开始
  * @param  无
  * @retval 无
  */
void OLED_I2C_Start(void)
{
	OLED_W_SDA(1);
	OLED_W_SCL(1);
	OLED_W_SDA(0);
	OLED_W_SCL(0);
}

/**
  * @brief  I2C停止
  * @param  无
  * @retval 无
  */
void OLED_I2C_Stop(void)
{
	OLED_W_SDA(0);
	OLED_W_SCL(1);
	OLED_W_SDA(1);
}

/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的一个字节
  * @retval 无
  */
void OLED_I2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		OLED_W_SDA(Byte & (0x80 >> i));
		OLED_W_SCL(1);
		OLED_W_SCL(0);
	}
	OLED_W_SCL(1);	//额外的一个时钟,不处理应答信号
	OLED_W_SCL(0);
}

/**
  * @brief  OLED写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void OLED_WriteCommand(uint8_t Command)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78);		//从机地址
	OLED_I2C_SendByte(0x00);		//写命令
	OLED_I2C_SendByte(Command); 
	OLED_I2C_Stop();
}

/**
  * @brief  OLED写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void OLED_WriteData(uint8_t Data)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78);		//从机地址
	OLED_I2C_SendByte(0x40);		//写数据
	OLED_I2C_SendByte(Data);
	OLED_I2C_Stop();
}

/**
  * @brief  OLED设置光标位置
  * @param  Y 以左上角为原点,向下方向的坐标,范围:0~7
  * @param  X 以左上角为原点,向右方向的坐标,范围:0~127
  * @retval 无
  */
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
	OLED_WriteCommand(0xB0 | Y);					//设置Y位置
	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));	//设置X位置高4位
	OLED_WriteCommand(0x00 | (X & 0x0F));			//设置X位置低4位
}

/**
  * @brief  OLED清屏
  * @param  无
  * @retval 无
  */
void OLED_Clear(void)
{  
	uint8_t i, j;
	for (j = 0; j < 8; j++)
	{
		OLED_SetCursor(j, 0);
		for(i = 0; i < 128; i++)
		{
			OLED_WriteData(0x00);
		}
	}
}

/**
  * @brief  OLED显示一个字符
  * @param  Line 行位置,范围:1~4
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的一个字符,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{      	
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i]);			//显示上半部分内容
	}
	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//显示下半部分内容
	}
}

/**
  * @brief  OLED显示字符串
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i++)
	{
		OLED_ShowChar(Line, Column + i, String[i]);
	}
}

/**
  * @brief  OLED次方函数
  * @retval 返回值等于X的Y次方
  */
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y--)
	{
		Result *= X;
	}
	return Result;
}

/**
  * @brief  OLED显示数字(十进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~4294967295
  * @param  Length 要显示数字的长度,范围:1~10
  * @retval 无
  */
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
  * @brief  OLED显示数字(十进制,带符号数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-2147483648~2147483647
  * @param  Length 要显示数字的长度,范围:1~10
  * @retval 无
  */
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
	uint8_t i;
	uint32_t Number1;
	if (Number >= 0)
	{
		OLED_ShowChar(Line, Column, '+');
		Number1 = Number;
	}
	else
	{
		OLED_ShowChar(Line, Column, '-');
		Number1 = -Number;
	}
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
  * @brief  OLED显示数字(十六进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFFFFFF
  * @param  Length 要显示数字的长度,范围:1~8
  * @retval 无
  */
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i, SingleNumber;
	for (i = 0; i < Length; i++)							
	{
		SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
		if (SingleNumber < 10)
		{
			OLED_ShowChar(Line, Column + i, SingleNumber + '0');
		}
		else
		{
			OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
		}
	}
}

/**
  * @brief  OLED显示数字(二进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
	}
}

/**
  * @brief  OLED初始化
  * @param  无
  * @retval 无
  */
void OLED_Init(void)
{
	uint32_t i, j;
	
	for (i = 0; i < 1000; i++)			//上电延时
	{
		for (j = 0; j < 1000; j++);
	}
	
	OLED_I2C_Init();			//端口初始化
	
	OLED_WriteCommand(0xAE);	//关闭显示
	
	OLED_WriteCommand(0xD5);	//设置显示时钟分频比/振荡器频率
	OLED_WriteCommand(0x80);
	
	OLED_WriteCommand(0xA8);	//设置多路复用率
	OLED_WriteCommand(0x3F);
	
	OLED_WriteCommand(0xD3);	//设置显示偏移
	OLED_WriteCommand(0x00);
	
	OLED_WriteCommand(0x40);	//设置显示开始行
	
	OLED_WriteCommand(0xA1);	//设置左右方向,0xA1正常 0xA0左右反置
	
	OLED_WriteCommand(0xC8);	//设置上下方向,0xC8正常 0xC0上下反置

	OLED_WriteCommand(0xDA);	//设置COM引脚硬件配置
	OLED_WriteCommand(0x12);
	
	OLED_WriteCommand(0x81);	//设置对比度控制
	OLED_WriteCommand(0xCF);

	OLED_WriteCommand(0xD9);	//设置预充电周期
	OLED_WriteCommand(0xF1);

	OLED_WriteCommand(0xDB);	//设置VCOMH取消选择级别
	OLED_WriteCommand(0x30);

	OLED_WriteCommand(0xA4);	//设置整个显示打开/关闭

	OLED_WriteCommand(0xA6);	//设置正常/倒转显示

	OLED_WriteCommand(0x8D);	//设置充电泵
	OLED_WriteCommand(0x14);

	OLED_WriteCommand(0xAF);	//开启显示
		
	OLED_Clear();				//OLED清屏
}

main.c

#include "gd32e23x.h"
#include "OLED.h"

int main(void){
    OLED_Init();
    OLED_ShowString(1,1,"Hello World!");
    while(1){

    }
}

移植成功。其实改动不大,主要就是把GPIO的初始化和GPIO的电平操作适配一下就行。

ESP32驱动移植代码

这边只贴一个OLED.c的代码,因为其他的和上面GD32的一样。 

OLED.c

#include "driver/gpio.h"
#include "OLED_Font.h"

#define OLED_SCL_GPIO 18
#define OLED_SDA_GPIO 17

/*引脚配置*/
#define OLED_W_SCL(x)		gpio_set_level(OLED_SCL_GPIO,x)
#define OLED_W_SDA(x)		gpio_set_level(OLED_SDA_GPIO,x)

/*引脚初始化*/
void OLED_I2C_Init(void){
    gpio_config_t init={
        .intr_type=GPIO_INTR_DISABLE,             //失能中断;
        .mode=GPIO_MODE_OUTPUT_OD,                //开漏输出模式
        .pin_bit_mask=(1ULL<<OLED_SCL_GPIO),    
        .pull_down_en=GPIO_PULLDOWN_DISABLE,      //失能下拉模式
        .pull_up_en=GPIO_PULLUP_ENABLE,           //使能上拉模式
    };
    gpio_config(&init);
	
    init.pin_bit_mask=(1ULL<<OLED_SDA_GPIO);
    gpio_config(&init);

	OLED_W_SCL(1);
	OLED_W_SDA(1);
	
}

/**
  * @brief  I2C开始
  * @param  无
  * @retval 无
  */
void OLED_I2C_Start(void)
{
	OLED_W_SDA(1);
	OLED_W_SCL(1);
	OLED_W_SDA(0);
	OLED_W_SCL(0);
}

/**
  * @brief  I2C停止
  * @param  无
  * @retval 无
  */
void OLED_I2C_Stop(void)
{
	OLED_W_SDA(0);
	OLED_W_SCL(1);
	OLED_W_SDA(1);
}

/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的一个字节
  * @retval 无
  */
void OLED_I2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		OLED_W_SDA(Byte & (0x80 >> i));
		OLED_W_SCL(1);
		OLED_W_SCL(0);
	}
	OLED_W_SCL(1);	//额外的一个时钟,不处理应答信号
	OLED_W_SCL(0);
}

/**
  * @brief  OLED写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void OLED_WriteCommand(uint8_t Command)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78);		//从机地址
	OLED_I2C_SendByte(0x00);		//写命令
	OLED_I2C_SendByte(Command); 
	OLED_I2C_Stop();
}

/**
  * @brief  OLED写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void OLED_WriteData(uint8_t Data)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78);		//从机地址
	OLED_I2C_SendByte(0x40);		//写数据
	OLED_I2C_SendByte(Data);
	OLED_I2C_Stop();
}

/**
  * @brief  OLED设置光标位置
  * @param  Y 以左上角为原点,向下方向的坐标,范围:0~7
  * @param  X 以左上角为原点,向右方向的坐标,范围:0~127
  * @retval 无
  */
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
	OLED_WriteCommand(0xB0 | Y);					//设置Y位置
	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));	//设置X位置高4位
	OLED_WriteCommand(0x00 | (X & 0x0F));			//设置X位置低4位
}

/**
  * @brief  OLED清屏
  * @param  无
  * @retval 无
  */
void OLED_Clear(void)
{  
	uint8_t i, j;
	for (j = 0; j < 8; j++)
	{
		OLED_SetCursor(j, 0);
		for(i = 0; i < 128; i++)
		{
			OLED_WriteData(0x00);
		}
	}
}

/**
  * @brief  OLED显示一个字符
  * @param  Line 行位置,范围:1~4
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的一个字符,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{      	
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i]);			//显示上半部分内容
	}
	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//显示下半部分内容
	}
}

/**
  * @brief  OLED显示字符串
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i++)
	{
		OLED_ShowChar(Line, Column + i, String[i]);
	}
}

/**
  * @brief  OLED次方函数
  * @retval 返回值等于X的Y次方
  */
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y--)
	{
		Result *= X;
	}
	return Result;
}

/**
  * @brief  OLED显示数字(十进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~4294967295
  * @param  Length 要显示数字的长度,范围:1~10
  * @retval 无
  */
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
  * @brief  OLED显示数字(十进制,带符号数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-2147483648~2147483647
  * @param  Length 要显示数字的长度,范围:1~10
  * @retval 无
  */
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
	uint8_t i;
	uint32_t Number1;
	if (Number >= 0)
	{
		OLED_ShowChar(Line, Column, '+');
		Number1 = Number;
	}
	else
	{
		OLED_ShowChar(Line, Column, '-');
		Number1 = -Number;
	}
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
  * @brief  OLED显示数字(十六进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFFFFFF
  * @param  Length 要显示数字的长度,范围:1~8
  * @retval 无
  */
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i, SingleNumber;
	for (i = 0; i < Length; i++)							
	{
		SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
		if (SingleNumber < 10)
		{
			OLED_ShowChar(Line, Column + i, SingleNumber + '0');
		}
		else
		{
			OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
		}
	}
}

/**
  * @brief  OLED显示数字(二进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
	}
}

/**
  * @brief  OLED初始化
  * @param  无
  * @retval 无
  */
void OLED_Init(void)
{
	uint32_t i, j;
	
	for (i = 0; i < 1000; i++)			//上电延时
	{
		for (j = 0; j < 1000; j++);
	}
	
	OLED_I2C_Init();			//端口初始化
	
	OLED_WriteCommand(0xAE);	//关闭显示
	
	OLED_WriteCommand(0xD5);	//设置显示时钟分频比/振荡器频率
	OLED_WriteCommand(0x80);
	
	OLED_WriteCommand(0xA8);	//设置多路复用率
	OLED_WriteCommand(0x3F);
	
	OLED_WriteCommand(0xD3);	//设置显示偏移
	OLED_WriteCommand(0x00);
	
	OLED_WriteCommand(0x40);	//设置显示开始行
	
	OLED_WriteCommand(0xA1);	//设置左右方向,0xA1正常 0xA0左右反置
	
	OLED_WriteCommand(0xC8);	//设置上下方向,0xC8正常 0xC0上下反置

	OLED_WriteCommand(0xDA);	//设置COM引脚硬件配置
	OLED_WriteCommand(0x12);
	
	OLED_WriteCommand(0x81);	//设置对比度控制
	OLED_WriteCommand(0xCF);

	OLED_WriteCommand(0xD9);	//设置预充电周期
	OLED_WriteCommand(0xF1);

	OLED_WriteCommand(0xDB);	//设置VCOMH取消选择级别
	OLED_WriteCommand(0x30);

	OLED_WriteCommand(0xA4);	//设置整个显示打开/关闭

	OLED_WriteCommand(0xA6);	//设置正常/倒转显示

	OLED_WriteCommand(0x8D);	//设置充电泵
	OLED_WriteCommand(0x14);

	OLED_WriteCommand(0xAF);	//开启显示
		
	OLED_Clear();				//OLED清屏
}

也移植成功啦。 

全部代码包括取字模的软件我都会打包放公众号,关注公众号“折途想要敲代码”回复关键词“OLED”即可免费下载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1823387.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

苍穹外卖笔记-13-导入地址簿功能代码、用户下单、订单支付

文章目录 1. 导入地址簿功能代码1.1 需求分析和设计1.1.1 产品原型1.1.2 接口设计1.1.3 表设计 1.2 代码导入1.2.1 Mapper层1.2.2 Service层1.2.3 Controller层 1.3 功能测试 2. 用户下单2.1 需求分析和设计2.1.1 产品原型2.1.2 接口设计2.1.3 表设计 2.2 代码开发2.2.1 DTO设计…

「动态规划」买卖股票的最佳时机,如何处理多笔交易?

188. 买卖股票的最佳时机 IVhttps://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iv/description/ 给你一个整数数组prices和一个整数k&#xff0c;其中prices[i]是某支给定的股票在第i天的价格。设计一个算法来计算你所能获取的最大利润。你最多可以完成k笔交易。…

嵌入式linux中内存管理基本原理

各位开发者,大家好,今天主要给大家分享一下,如何使用linux系统中的内存管理。 前面我们学习了很多Linux内存方面的知识,比如:虚拟地址空间,进程空间,内存映射,页表机制等,我们学了这么多知识,似乎对Linux内存似懂非懂,为什么会出现这样的问题?原因在于我们缺…

关于FPGA对 DDR4 (MT40A256M16)的读写控制 2

关于FPGA对 DDR4 &#xff08;MT40A256M16&#xff09;的读写控制 2 语言 &#xff1a;Verilg HDL EDA工具&#xff1a;ISE、Vivado、Quartus II 关于FPGA对 DDR4 &#xff08;MT40A256M16&#xff09;的读写控制 2一、引言二、DDR4的简介四、DDR4 SDRAM状态框图 关键词&#x…

Java多线程学习笔记

文章目录 1. 引言1.1 多线程的重要性 2. 什么是多线程2.1 线程的定义和基本概念2.2 线程与进程的区别 3. 创建线程的方式3.1 继承Thread类3.2 实现Runnable接口&#xff0c;重写run方法3.3 实现Runnable接口&#xff0c;重写call方法3.4 匿名内部类创建Thread子类对象3.5 使用匿…

ROS中Twist消息类型

Twist消息类型在Robot Operating System (ROS)中是一个常见的数据结构&#xff0c;主要用于描述物体的线性速度和角速度。这种消息类型在ROS的geometry_msgs包中定义&#xff0c;常用于机器人运动控制&#xff0c;尤其是当需要向机器人发布速度指令时。 Twist消息由两个Vector…

21.1 文件-文件的重要性、ioutil包

1. 文件的重要性 文件的本质就是硬盘中的数据&#xff0c;包括各种程序、文档、多媒体甚至系统配置。 各种类UNIX操作系统的一个重要特征就是将一切皆视为文件。 可以象访问文件一样访问键盘、打印机等硬件设备可以象访问文件一样访问管道、套接字等内核资源 各种类UNIX操作…

网络基础OSI国际互联

这里所指的网络是计算机网络&#xff0c;由许许多多的不同的网络设备以及电子设备构建的一个ip的网络&#xff0c;这个就是工作对象 网络是随着计算机的出现&#xff0c;军事沟通 出现的问题&#xff1a;物理层设备&#xff0c;总线&#xff0c;共享设备&#xff0c;会产生冲突…

用 C 语言实现求补码的运算

缘起 前两天程序中需要求一堆参数的补码&#xff0c;一时犯懒&#xff0c;想从CSDN上搜一个勉强能用的代码借鉴一下&#xff0c;结果几乎没有搜到一个靠谱的&#xff01;这种求补码的操作&#xff0c;用脚趾头想想也应该知道要用C或者C的位运算来实现呀。结果搜到的一些实现方…

MyBatis-Plus整合达梦数据库

文章目录 1. 环境准备2. 创建Spring Boot项目3. 引入依赖4. 配置数据源5. 配置MyBatis-Plus6. 创建实体类7. 创建Mapper接口8. 创建Service类9. 创建Controller类10. 创建Mapper XML文件11. 测试12. 进一步优化12.1 配置分页插件12.2 配置乐观锁插件13. 总结🎉欢迎来到Java学…

vue+elementui+springboot图片上传

1、前端代码 <template><div><el-uploadclass"avatar-uploader"action"http://localhost:8081/ch06/demo/uploadAvatar":show-file-list"false":on-success"handleAvatarSuccess":before-upload"beforeAvatarUpl…

SIGMOD 2024 | 时空数据(Spatial-Temporal)和时间序列(Time Series)论文总结

SIGMOD2024于6月9号-6月14号正在智利圣地亚戈举行&#xff08;Santiago Chile&#xff09; 本文总结了SIGMOD 2024有关时间序列&#xff08;time series&#xff09;,包括时序数据库&#xff0c;查询优化等内容。以及时空数据&#xff08;spatial-temporal data&#xff09;的…

【Vue】自学笔记(四)

上一篇&#xff1a;Vue笔记&#xff08;三&#xff09;-CSDN博客 1.VueCli自定义搭建项目 先确保安装了全局工具VueCli 如果没有&#xff0c;则先运行命令 npm i vue/cli -g 选择最后一个自定义搭建项目 选择需要自动搭建的功能 这里我需要router和css预处理器就空格勾选上&…

干货!电脑如何录屏?6款win10录屏大师软件深度测评

电脑如何录屏&#xff1f;在2024年&#xff0c;截图或屏幕录制可以说是一种无价的工具。它是捕捉重要信息、与朋友和同事分享说明&#xff0c;或者只是存储您最喜爱的游戏和应用程序中的记忆的好方法。在 Windows 上录制屏幕非常简单。在本篇文章中&#xff0c;我们将讨论在win…

Node入门以及express创建项目

前言 记录学习NodeJS 一、NodeJS是什么&#xff1f; Node.js 是一个开源和跨平台的 JavaScript 运行时环境 二、下载NodeJs 1.下载地址(一直点击next即可&#xff0c;记得修改安装地址) https://nodejs.p2hp.com/download/ 2.查看是否安装成功&#xff0c;打开命令行 nod…

InfoComm 2024 直击:千视新品P3和KiloLink技术闪耀亮相

InfoComm 2024 直击&#xff1a;千视新品P3和KiloLink技术闪耀亮相&#xff0c;现场亮点不断 北京时间2024年6月13日&#xff0c;UTC-7时间6月12日&#xff0c;美国视听显示与系统集成展览会InfoComm 2024在美国拉斯维加斯正式开幕。作为全美规模最大、最具影响力的展会&#…

电脑数字键被锁住不能输入数字

情况: 反复点击数字键盘的NumLock,看它的灯是否能正常启动 1.如果NumLock灯可以正常的打开和关闭,并且无法输入内容 1.1打开控制面板 1.2 进入轻松使用中选择更改键盘的工作方式 1.3找到并点击设置鼠标键 1.4 赵到NumLock设置为关闭,然后确定即可

辽宁省食品安全管理人员精选模拟试题

新增(食品安全法实施条例)相关真题16道&#xff0c;具体如下: 1.食品生产企业可以制定低于食品安全标准或者地方标准要求的企业标准。(X) 2.食品生产者应当建立食品安全追溯体系&#xff0c;保证食品可追溯。(√) 3.食品生产企业的主要负责人对本企业的食品安全工作全面负责&am…

Java注解Annotation机制说明和基础使用(为什么Annotation直接促进了框架的繁荣发展?)

一、注解解决的问题【可忽略】 软件开发过程中&#xff0c;如何配置一直是一个重要的问题&#xff0c;对于一个框架&#xff0c;如果你不为它提供初始结构&#xff0c;它就无法理解你要做什么&#xff0c;自然无法工作。 1.问题&#xff1a;紧密贴合的代码和配置 在很久之前…

One能聊天接入百度千帆AppBuilder

One能聊天介绍:基于ChatGPT实现的微信小程序,适配H5和WEB端。包含前后端,支持打字效果输出流式输出,支持AI聊天次数限制,支持分享增加次数等功能One能聊天开源地址:https://github.com/oldinaction/ChatGPT-MPOne能聊天演示环境:可关注【阿壹族】公众号,并回复【One能聊…