在本次活动中,使用OLED屏幕对数据进行显示,这里和大家分享一下,屏幕的驱动经验:
一:OLED屏幕知识简单分享
OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display, OELD)。因为具备轻薄、省电等特性,因此从 2003 年开始,这种显示设备在 MP3 播放器上得到了广泛应用,而对于同属数码类产品的 DC 与手机,此前只是在一些展会上展示过采用 OLED 屏幕的工程样品。自 2007 年后,寿命得 到很大提高,具备了许多 LCD 不可比拟的优势。
GND:电源地 VCC:2.2V~5.5V SCL(D0):CLK 时钟 (高电平 2.2V~5.5V) SDA(D1):MOSI 数据(高电平 2.2V~5.5V) RST:复位(高电平 2.2V~5.5V) D/C:数据/命令(高电平 2.2V~5.5V) 兼容 3.3V 和 5V 控制芯片的 I/O 电平(无需任何设置,直接兼容)。
这是本次活动使用的OLED屏幕,虽然背面标识的时SSD1315,但是和驱动SSD1306的方式大体相同,驱动的时候可以参考SSD1306的驱动方式进行驱动;
二:IIC协议的知识分享:
IIC通讯协议的了解
IIC(Inter-Integrated Circuit)是一种串行通信协议,主控制器和从器件间的主从通信。它使用两根线:SDA(数据线)和SCL(时钟线)。SDA(SerialData Line):用于传输数据。SCL(Serial Clock Line):用于同步数据传输的时钟信号。
注意:1.1C不同于485和CAN可长距离通讯,IIC只能短距离,常用干IC与IC通讯。例如存储芯片:24C02;传感器模块:ST30,气压模块MPL MPU6050,温度模块ATH20等等,有很多的模块,当时我们熟悉了IIC 的通讯方式,可以外扩很多模块,适用于电子爱好者和DIY;
2.IIC电路设计时,建议在SDA和SCL两根线外加上拉电阻,以保证时序通讯的稳定性。不过在本次的活动电路板上面并没有外接上拉电阻,也不知道是不是模块上面焊接好了。
2.1 IIC类型
IIC 总线在传送数据过程中共有三种类型信号,分别是:
1.开始信号:SCL 为高电平时,SDA由高电平向低电平跳变,开始传送数据。
2.结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。
3.应答信号:从机 在接收到 8bit 数据后,向发送数据的主机发出特定的低电平脉冲,表示已收到数据。主机向从机发出一个信号后等待从机发出一个应答信号,主机接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
2.2 IIC的总时序图
起始条件是SCL保持高电平,SDA由高电平变为低电平后,延时(最少4us,这个和线长有关系),SCL变为低电平。只有当SCL线上的时钟信号为低时,数据线上的“高”或“低”状态才可以改变。输出到SDA线上的每个字节必须是8位,数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。当传输完SDA马上拉低,接着输出低电平信号主机进而产生停止信号,结束传送过程。
2.3 IIC的 发送时序
1主机首先产生起开始信号,然后紧跟着发送一个从机地址,这个地址共有7位,紧接着的第8位是数据方向位(R/W),0表示主机发送数据(写),1表示主机接收数据(读)。
2.主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,若相同,则认为自已正在被主机寻址,根据R/T位将自己确定为发送器和接收器。这时候主机等待从机的应答信号,当主机收到应答信号时,发送要访问从机的那个地址,继续等待从机的应答信号,当主机收到应答信号时,发送N个字节的数据,继续等待从机的N次应答信号,主机产生停止信号,结束传送过程。
2.4 IIC的读时序
三:STM32 cube MX 软件配置
3.1 这里我是用硬件IIC 进行驱动
使用PB8 PB9 引脚作为IIC1的引脚,需要重映射到该引脚;
这里注意下,IIC的参数配置:
同时开启,硬件IIC的中断函数功能。
四:字库的制作:
4.1这里根据驱动函数,设置字体的大小即可,
4.2 图片的制作
这里我们需要在PS中绘制一张图片,然后再软件中打开
五:底层代码如下所示:
/*********************************************************************************************** * @brief static unsigned char OLED_send_byteS(unsigned char *data, unsigned char length) * @param data:输入的数据 length:长度值,使用硬件IIC底层驱动函数 * @retval 无 * @author 聪聪哥哥 * @version V1.1.0 * @date 25-5-2025 *************************************************************************************************/ static unsigned char OLED_send_byteS(unsigned char *data, unsigned char length) { if (HAL_I2C_Master_Transmit(&hi2c1, 0x78, data, length, 2) != HAL_OK) { return 0; } return 1; } /*********************************************************************************************** * @brief static void I2C_WriteByte(uint8_t addr, uint8_t value) * @param addr:IIC模块的地址,value :写入的数据 * @retval 无 * @author 聪聪哥哥 * @version V1.1.0 * @date 25-5-2025 *************************************************************************************************/ static void I2C_WriteByte(uint8_t addr, uint8_t value) { unsigned char dta[2] = {0}; dta[0] = addr; dta[1] = value; OLED_send_byteS(dta, 2); } /*********************************************************************************************** * @brief void WriteCmd(unsigned char I2C_Command) * @param I2C_Command : IIC的命令 * @retval 无 * @author 聪聪哥哥 * @version V1.1.0 * @date 25-5-2025 *************************************************************************************************/ void WriteCmd(unsigned char I2C_Command) { I2C_WriteByte(0x00, I2C_Command); } /*********************************************************************************************** * @brief void WriteDat(unsigned char I2C_Data) * @param I2C_Data : IIC的数据 * @retval 无 * @author 聪聪哥哥 * @version V1.1.0 * @date 25-5-2025 *************************************************************************************************/ void WriteDat(unsigned char I2C_Data)//写数据 { I2C_WriteByte(0x40, I2C_Data); }
对于屏幕的驱动,我们仅仅需要修改上述底层驱动代码,就可以对OLED进行显示。
显示数字汉字如下所示:
//-------------------------------------------------------------- // Prototype : void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N) // Calls : // Parameters : x,y -- 起始点坐标(x:0~127, y:0~7); N:汉字在codetab.h中的索引 // Description : 显示codetab.h中的汉字,16*16点阵 //-------------------------------------------------------------- void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N) { unsigned char wm=0; unsigned int adder=32*N; OLED_SetPos(x , y); for(wm = 0;wm < 16;wm++) { WriteDat(F16x16[adder]); adder += 1; } OLED_SetPos(x,y + 1); for(wm = 0;wm < 16;wm++) { WriteDat(F16x16[adder]); adder += 1; } }
显示图片的函数如下所示:
void OLED_ShowPicture(uint8_t x,uint8_t y,uint8_t sizex,uint8_t sizey,uint8_t BMP[]) { uint32_t j=0; uint8_t x1=0,y1=0; if(y1%8==0)y1=0; else y1+=1; for(y1=y;y1<sizey;y1++) { OLED_DrawPoint(x,y1); for(x1=x;x1<sizex;x1++) { WriteDat(BMP[j]); j++; } } }
界面显示函数如下:
extern unsigned char BMP1[]; /*********************************************************************************************** * @brief void StartDisPlay(void) * @param 开机界面显示 * @retval 无 * @author 聪聪哥哥 * @version V1.1.0 * @date 25-5-2025 *************************************************************************************************/ void StartDisPlay(void) { OLED_ShowPicture(0,0,128,8,BMP1); HAL_Delay(2000); OLED_Clear(); } /*********************************************************************************************** * @brief void WorkPageImmobility(void) * @param 工作界面固定显示 * @retval 无 * @author 聪聪哥哥 * @version V1.1.0 * @date 25-5-2025 *************************************************************************************************/ void WorkPageImmobility(void) { OLED_ShowCN(0, 2, 6); OLED_ShowCN(16, 2, 7); OLED_ShowCN(0, 4, 8); OLED_ShowCN(16, 4, 9); OLED_ShowCN(0, 6, 10); OLED_ShowCN(16, 6, 11); OLED_ShowStr(100, 2, (uint8_t *)"MV", 2); OLED_ShowStr(100, 4, (uint8_t *)"MA", 2); OLED_ShowStr(100, 6, (uint8_t *)"MW", 2); } /*********************************************************************************************** * @brief void WorkPageDataDisplay(void) * @param 工作界面数据显示 * @retval 无 * @author 聪聪哥哥 * @version V1.1.0 * @date 25-5-2025 *************************************************************************************************/ const uint8_t test[] = "Hello world"; void WorkPageDataDisplay(void) { uint16_t TempStr[16]; sprintf((char*)TempStr,"%3d",iOriginalVoltageData); OLED_ShowStr(40, 2, (uint8_t *)TempStr, 2); OLED_ShowNum(50,4,iOriginalElectriData,5,16); OLED_ShowNum(50,6,iOriginalPowerData,5,16); }
主程序如下:
OLED_Init(); OLED_ColorTurn(0);//0?????????1 ?????? OLED_DisplayTurn(0);//0??????? 1 ????????? OLED_Refresh(); OLED_Clear(); StartDisPlay(); WorkPageImmobility();
实物测试图如下:
顺便说声,为了方便调试使用EDA绘制乐一个STM32F411的拓展板
由于开发的功能还没测试好,等测试好,将PCB的文件上传。
程序代码: