赞
踩
本文主要涉及OLED显示原理的讲解以及OLED显示汉字与图片的代码。
OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display,OELD) 。
OLED由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。OLED显示技术具有自发光的特性,采用非常薄的有机材料涂层和玻璃基板,当有电流通过时,这些有机材料就会发光,而且OLED显示屏幕可视角度大,并且能够节省电能,从2003年开始这种显示设备在MP3播放器上得到了应用。
LCD都需要背光,而OLED不需要,因为它是自发光的。这样同样的显示,OLED效果要来得好一些。以目前的技术, OLED的尺寸还难以大型化,但是分辨率确可以做到很高。
1、0.96 寸OLED 有黄蓝,白,蓝三种颜色可选;其中黄蓝是屏上1/4部分为黄光,下3/4 为蓝;而且是固定区域显示固定颜色,颜色和显示区域均不能修改;白光则为纯白,也就是黑底白字;蓝色则为纯蓝,也就是黑底蓝字。
2、分辨率为128*64
。
3、多种接口方式;OLED 裸屏总共种接口包括:6800、8080 两种并行接口方式、4线串行SPI 接口方式、IIC 接口方式(只需要2根线就可以控制 OLED 了!),这五种接口是通过屏上的BS0~BS2 来配置的。
CS
:OLED片选信号。WR
:向OLED写入数据。RD
:从OLED读取数据。D[7:0]
:8位双向数据线。RST(RES)
:硬复位 OLED。 DC
: 命令/数据标志(0,读写命令;1,读写数据模块的8080并口读/写的过程为:
先根据要写入/读取的数据的类型,设置DC为高(数据)/低(命令),然后拉低片选,选中SSD1306,接着我们根据是读数据,还是要写数据置RD/WR为低,然后:
<1>、读数据
:在RD
的上升沿
,使数据锁存
到数据线(D[7:0])上;
<2>、写数据
:在WR
的上升沿
,使数据写入
到SSD1306里面;
并口写时序图:
并口读时序图:
OLED 模块显存:
SSD1306的显存总共为 12864bit 大小,SSD1306将这些显存分为8页 。每页包含了128个字节,总共8页,这样刚好是12804的点阵大小。
在STM32的内部建立一个 缓存 (共128*8个字节),在每次修改的时候,只是修改STM32上的缓存
(实际上就是SRAM),在修改完了之后,一次性把STM32上的缓存数据写入到OLED的GRAM。
该方法也有坏处,就是对于那些SRAM很小的单片机(比如51系列)就比较麻烦了。
SSD1306 的命令
1、命令0X81:设置对比度。包含两个字节,第一个0X81为命令,随后发送的一个字节为要设置的对比度的值。这个值设置得越大屏幕就越亮。
2、命令0XAE/0XAF::0XAE为关闭显示命令;0XAF为开启显示命令。
3、命令0X8D:包含2个字节,第一个为命令字,第二个为设置值,第二个字节的BIT2表示电荷泵的开关状态,该位为1,则开启电荷泵,为0则关闭、在模块初始化的时候,这个必须要开启,否则是看不到屏幕显示的。
4、命令0XBO~B7:用于设置贡地址,其低三位的值对应着GRAM的页地址。
5、命令0X00~0X0F:用于设置显示时的起始列地址低四位。
6、命令0×10~0X1F:用于设置显示时的起始列地址高四位。
/********通过IIC向OLED发送一个字节命令*********/ //参数:cmd 需要发送的命令 //返回值 :0 发送成功 非0发送失败 uint8_t Oled_Send_One_Byte_Cmd(uint8_t cmd) { //1、发送起始信号 Software_IIC_Start(); //2、发送设备地址 Software_IIC_Send_One_Byte_Data(OLED_SLAVE_ADDR); //设备地址最低位是0 表示写操作 //3、等待从机响应 读应答 if(Software_IIC_Read_ACK()) //如果从机没有应答 直接退出 { Software_IIC_Stop();//退出之前 发送停止信号 结束总线占用 return 1; } //4、指令模式 Software_IIC_Send_One_Byte_Data(OLED_SLAVE_CMD); //5、读应答 if(Software_IIC_Read_ACK()) //如果从机没有应答 直接退出 { Software_IIC_Stop();//退出之前 发送停止信号 结束总线占用 return 2; } //6、发送指令模式 Software_IIC_Send_One_Byte_Data(cmd); //5、读应答 if(Software_IIC_Read_ACK()) //如果从机没有应答 直接退出 { Software_IIC_Stop();//退出之前 发送停止信号 结束总线占用 return 3; } //8、发送停止信号 结束通信 Software_IIC_Stop(); return 0;//成功 } /********通过IIC向OLED发送一个字节数据*********/ //参数:Dat 需要发送的数据 //返回值 :0 发送成功 非0发送失败 uint8_t Oled_Send_One_Byte_DATA(uint8_t Dat) { //1、发送起始信号 Software_IIC_Start(); //2、发送设备地址 Software_IIC_Send_One_Byte_Data(OLED_SLAVE_ADDR); //设备地址最低位是0 表示写操作 //3、等待从机响应 读应答 if(Software_IIC_Read_ACK()) //如果从机没有应答 直接退出 { Software_IIC_Stop();//退出之前 发送停止信号 结束总线占用 return 1; } //4、数据模式 Software_IIC_Send_One_Byte_Data(OLED_SLAVE_DATA); //5、读应答 if(Software_IIC_Read_ACK()) //如果从机没有应答 直接退出 { Software_IIC_Stop();//退出之前 发送停止信号 结束总线占用 return 2; } //6、发送数据 Software_IIC_Send_One_Byte_Data(Dat); //5、读应答 if(Software_IIC_Read_ACK()) //如果从机没有应答 直接退出 { Software_IIC_Stop();//退出之前 发送停止信号 结束总线占用 return 3; } //8、发送停止信号 结束通信 Software_IIC_Stop(); return 0;//成功 } //填充缓存区中的数据 void OLed_Fill(unsigned char bmp_data) { unsigned char y,x; for(y=0;y<8;y++) { //设置PAGE地址 //b0 ~ b7 Oled_Send_One_Byte_Cmd(0xb0+y); //页寻址只有最低三位有效 因为只有8页 //然后就是B开头 多以第一页起始地址为b0 //设置列地址 Oled_Send_One_Byte_Cmd(0x00); //列地址低位 Oled_Send_One_Byte_Cmd(0x10); //列地址高位 for(x=0;x<128;x++) { Oled_Send_One_Byte_DATA(bmp_data); } } } //给OLED发送命令 初始化 void Oled_Init(void) { Oled_Send_One_Byte_Cmd(0xAE);//--turn off oled panel Oled_Send_One_Byte_Cmd(0x00);//---set low column address Oled_Send_One_Byte_Cmd(0x10);//---set high column address Oled_Send_One_Byte_Cmd(0x40);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F) Oled_Send_One_Byte_Cmd(0x81);//--set contrast control register Oled_Send_One_Byte_Cmd(0xCF); // Set SEG Output Current Brightness Oled_Send_One_Byte_Cmd(0xA1);//--Set SEG/Column Mapping 0xa0???? 0xa1?? Oled_Send_One_Byte_Cmd(0xC8);//Set COM/Row Scan Direction 0xc0???? 0xc8?? Oled_Send_One_Byte_Cmd(0xA6);//--set normal display Oled_Send_One_Byte_Cmd(0xA8);//--set multiplex ratio(1 to 64) Oled_Send_One_Byte_Cmd(0x3f);//--1/64 duty Oled_Send_One_Byte_Cmd(0xD3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F) Oled_Send_One_Byte_Cmd(0x00);//-not offset Oled_Send_One_Byte_Cmd(0xd5);//--set display clock divide ratio/oscillator frequency Oled_Send_One_Byte_Cmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec Oled_Send_One_Byte_Cmd(0xD9);//--set pre-charge period Oled_Send_One_Byte_Cmd(0xF1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock Oled_Send_One_Byte_Cmd(0xDA);//--set com pins hardware configuration Oled_Send_One_Byte_Cmd(0x12); Oled_Send_One_Byte_Cmd(0xDB);//--set vcomh Oled_Send_One_Byte_Cmd(0x40);//Set VCOM Deselect Level Oled_Send_One_Byte_Cmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02) Oled_Send_One_Byte_Cmd(0x02);// Oled_Send_One_Byte_Cmd(0x8D);//--set Charge Pump enable/disable Oled_Send_One_Byte_Cmd(0x14);//--set(0x10) disable Oled_Send_One_Byte_Cmd(0xA4);// Disable Entire Display On (0xa4/0xa5) Oled_Send_One_Byte_Cmd(0xA6);// Disable Inverse Display On (0xa6/a7) Oled_Send_One_Byte_Cmd(0xAF);//--turn on oled panel Oled_Send_One_Byte_Cmd(0xAF); /*display ON*/ OLed_Fill(0x00);//缓存区数据全为0 } //取消OLED初始化 void off_Init_OLed(void) { Oled_Send_One_Byte_Cmd(0xAE);//--turn off oled panel Oled_Send_One_Byte_Cmd(0x00);//---set low column address Oled_Send_One_Byte_Cmd(0x10);//---set high column address Oled_Send_One_Byte_Cmd(0x40);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F) Oled_Send_One_Byte_Cmd(0x81);//--set contrast control register Oled_Send_One_Byte_Cmd(0xCF); // Set SEG Output Current Brightness Oled_Send_One_Byte_Cmd(0xA1);//--Set SEG/Column Mapping 0xa0???? 0xa1?? Oled_Send_One_Byte_Cmd(0xC8);//Set COM/Row Scan Direction 0xc0???? 0xc8?? Oled_Send_One_Byte_Cmd(0xA6);//--set normal display Oled_Send_One_Byte_Cmd(0xA8);//--set multiplex ratio(1 to 64) Oled_Send_One_Byte_Cmd(0x3f);//--1/64 duty Oled_Send_One_Byte_Cmd(0xD3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F) Oled_Send_One_Byte_Cmd(0x00);//-not offset Oled_Send_One_Byte_Cmd(0xd5);//--set display clock divide ratio/oscillator frequency Oled_Send_One_Byte_Cmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec Oled_Send_One_Byte_Cmd(0xD9);//--set pre-charge period Oled_Send_One_Byte_Cmd(0xF1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock Oled_Send_One_Byte_Cmd(0xDA);//--set com pins hardware configuration Oled_Send_One_Byte_Cmd(0x12); Oled_Send_One_Byte_Cmd(0xDB);//--set vcomh Oled_Send_One_Byte_Cmd(0x40);//Set VCOM Deselect Level Oled_Send_One_Byte_Cmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02) Oled_Send_One_Byte_Cmd(0x02);// Oled_Send_One_Byte_Cmd(0x8D);//--set Charge Pump enable/disable Oled_Send_One_Byte_Cmd(0x14);//--set(0x10) disable Oled_Send_One_Byte_Cmd(0xA4);// Disable Entire Display On (0xa4/0xa5) Oled_Send_One_Byte_Cmd(0xA6);// Disable Inverse Display On (0xa6/a7) Oled_Send_One_Byte_Cmd(0xAF);//--turn on oled panel }
/*********** 设置显示字符位置的函数 参数: x--> 列地址 y--> 页地址 相当于行的(0-7) 返回值:无 ************/ void OLed_SetPos(unsigned char x, unsigned char y) { Oled_Send_One_Byte_Cmd((0xb0+y)); //页的首地址 + y 偏移单位 Oled_Send_One_Byte_Cmd(((x&0xf0)>>4)|0x10); //列地址高位 Oled_Send_One_Byte_Cmd((x&0x0f)|0x00); //列地址低位 } /**************** 在指定位置显示一个汉字,显示一个汉字时, 参数: x 显示位置,每次递增16个bit y 显示位置,每次递增2页 16bit buf 需要显示的字符字模 返回值:无 ****************/ void OLed_ShowChina(uint8_t x,uint8_t y,uint8_t *buf) { uint8_t i = 0; OLed_SetPos(x,y); for(i=0;i<16;i++) { Oled_Send_One_Byte_DATA(buf[i]); } OLed_SetPos(x,(y+1)); for(i=0;i<16;i++) { Oled_Send_One_Byte_DATA(buf[i+16]); } } //在指定位置显示ASCLL字符 void OLed_ShowASCII(uint8_t x, uint8_t y,char *str) { uint8_t i = 0; char *pstr = str; while(*pstr) { OLed_SetPos(x,y); for(i=0;i<8;i++) { Oled_Send_One_Byte_DATA(F8X16[((*pstr)-32)*16+i]); } OLed_SetPos(x,y+1); for(i=0;i<8;i++) { Oled_Send_One_Byte_DATA(F8X16[((*pstr)-32)*16+8+i]); } pstr++; x +=8; } } /******* 在指定的位置显示连续的文字 "中国" *******/ void OLed_ShowTest(unsigned char x,unsigned char y) { uint8_t i = 0; OLed_SetPos(x,y); for(i=0;i<16;i++) { Oled_Send_One_Byte_DATA(fbuf1[i]); } OLed_SetPos(x,(y+1)); for(i=0;i<16;i++) { Oled_Send_One_Byte_DATA(fbuf2[i]); } OLed_SetPos((x+16),y); for(i=0;i<16;i++) { Oled_Send_One_Byte_DATA(fbuf3[i]); } OLed_SetPos((x+16),(y+1)); for(i=0;i<16;i++) { Oled_Send_One_Byte_DATA(fbuf4[i]); } } //显示温度和 湿度 void OLed_ShowTemp(void) { //第1行显示温度 OLed_ShowChina(0,0,HZ1); OLed_ShowChina(16,0,HZ2); //第2行显示湿度 OLed_ShowChina(0,2,HZ3); OLed_ShowChina(16,2,HZ2); } //显示 距离 void OLed_ShowDist(void) { //第二行显示距离 OLed_ShowChina(0,4,HZ4); OLed_ShowChina(16,4,HZ5); } //显示 关照 void OLed_ShowLight(void) { //第二行显示光照 OLed_ShowChina(0,6,HZ6); OLed_ShowChina(16,6,HZ7); }
//显示一张图片 HQYJ void Oled_Show_BGM_HQYJ(void) { unsigned char y,x; unsigned char *str = HQYJ; for(y=0;y<8;y++) { //设置PAGE地址 //b0 ~ b7 Oled_Send_One_Byte_Cmd(0xb0+y); //页寻址只有最低三位有效 因为只有8页 //然后就是B开头 多以第一页起始地址为b0 //设置列地址 Oled_Send_One_Byte_Cmd(0x00); //列地址低位 Oled_Send_One_Byte_Cmd(0x10); //列地址高位 for(x=0;x<128;x++) { Oled_Send_One_Byte_DATA(*str); str++; } } }
关于上面的工程,大家可以在我的gitee上面去拉,在master分支下的单片机课设工程中04-OLED显示DHT11的数据,工程下载地址
工程实现效果图:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。