你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32学习笔记——OLED的使用

[复制链接]
STMCU小助手 发布时间:2022-8-15 21:25
前言
OLED作为STM32的一个较为重要的外设,其作用也是为了方便调试代码。OLED模块的驱动可以使用8080、SPI四线、SPI3线、I2C的方法进行驱动。本文主要根据OLED的数据手册分析8080、SPI四线、I2C的使用。

一、配置OLED的IO口

因为OLED模块分为8080串行、SPI四线、I2C,不同的数据传输模式导致了其不同的接线方法以及配置方法。

1.8080并口模式
对于8080并口的配置,参考正点原子的例程。
其中8080并口,总共需要13根信号线通信,
这些信号线如下:


  1. CS: OLED 片选信号。
  2. WR(RW):向 OLED 写入数据。
  3. RD:从 OLED 读取数据。
  4. D[7:0]: 8 位双向数据线。
  5. RST(RES):硬复位 OLED。
  6. DC:命令/数据标志(0,读写命令; 1,读写数据)
复制代码

在知道了接线之后,我们必须将所使用到的IO口使能:


  1. //初始化SSD1306                                            
  2. void OLED_Init(void)
  3. {         

  4.          GPIO_InitTypeDef  GPIO_InitStructure;
  5.          
  6.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOG, ENABLE);         //使能PC,D,G端口时钟

  7.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_6;         //PD3,PD6推挽输出  
  8.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出
  9.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
  10.          GPIO_Init(GPIOD, &GPIO_InitStructure);          //初始化GPIOD3,6
  11.          GPIO_SetBits(GPIOD,GPIO_Pin_3|GPIO_Pin_6);        //PD3,PD6 输出高


  12.          GPIO_InitStructure.GPIO_Pin =0xFF; //PC0~7 OUT推挽输出
  13.          GPIO_Init(GPIOC, &GPIO_InitStructure);
  14.          GPIO_SetBits(GPIOC,0xFF); //PC0~7输出高

  15.          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;                                 //PG13,14,15 OUT推挽输出
  16.          GPIO_Init(GPIOG, &GPIO_InitStructure);
  17.          GPIO_SetBits(GPIOG,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);                                                 //PG13,14,15 OUT  输出高
复制代码

在将IO口初始化之后,我们需要做的第三件事情便是如何写入命令或者数据到OLED中,因为使用OLED的时候,需要配置,而那些配置的命令是每个OLED出厂的已经存在了,属于命令范畴,我们所要了解的就是如何使用8080并口模式向OLED中写入命令。
如正点原子里写的,



  1. #define DATAOUT(x) GPIO_Write(GPIOC,x);//输出  

  2. void OLED_WR_Byte(u8 dat,u8 cmd)
  3. {
  4.         DATAOUT(dat);            
  5.          OLED_RS=cmd;   //DC位
  6.         OLED_CS=0;           
  7.         OLED_WR=0;         
  8.         OLED_WR=1;                //只有在WR由低变高的时候才能传入数据
  9.         OLED_CS=1;         
  10.         OLED_RS=1;         
  11. }  
复制代码

代码分析:根据之前的相应IO口连接,同时在OLED的数据手册中有提及到的,只有当OLED的片选CS拉低后以及WR拉低后,才可以开始往OLED中写入数据。后续的OLED初始化配置都是基于这个函数所进行的操作的。

2.SPI四线
SPI四线的OLED也只是万变不离其宗,一样的初始化过程,先确认接线,相比于8080串口接线方法,SPI四线极大的缩小了IO口的使用数量,更加便于使用。


  1. /*
  2.         OLED0.96                                                                          STM32
  3.         GND                                        <----------->                                        GND
  4.         VCC                                        <----------->                                        3.3V
  5.         SCL                         <----------->                                        PE3
  6.         SDA                                        <----------->                                        PE4
  7.         DC(Data/Command)            <----------->                                        PE0
  8.         RST                                                <----------->                                        PE2
  9. */

复制代码

这里拿我之前所使用过的一个串口配置为主,来讲解。

首先也是不变的初始化各个IO口:

  1. void OLED_Init()
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStructure;

  4.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
  5.         
  6.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 ;
  7.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  8.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  9.         GPIO_Init(GPIOE, &GPIO_InitStructure);
  10.         
  11.         GPIO_SetBits(GPIOE, GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4);
复制代码

初始化完成后,也是需要进行判断,判断用户是打算写入数据还是写入命令:


  1. //dat:要写入的数据/命令
  2. //cmd:数据/命令标志 0,表示命令;1,表示数据;
  3. void OLED_WR_Byte(u8 dat,u8 cmd)
  4. {        
  5.         u8 i;                          
  6.         if(cmd)
  7.           OLED_RS_Set();
  8.         else
  9.           OLED_RS_Clr();                  
  10.         for(i=0;i<8;i++)
  11.         {                          
  12.                 OLED_SCLK_Clr();
  13.                 if(dat&0x80)
  14.                    OLED_SDIN_Set();
  15.                 else
  16.                    OLED_SDIN_Clr();
  17.                 OLED_SCLK_Set();
  18.                 dat<<=1;   
  19.         }                                                   
  20.         OLED_RS_Set();            
  21. }
复制代码

有了这个主要的函数之后,便可以对OLED进行配置,如同上文所提到的8080串口配置一样,

  1.         OLED_RST_Set();
  2.         delay_us(100000);
  3.         OLED_RST_Clr();
  4.         delay_us(20);
  5.         OLED_RST_Set();
  6.         
  7.         OLED_WR_Byte(0xA8, OLED_CMD);
  8.         OLED_WR_Byte(0x3F, OLED_CMD);
  9.         OLED_WR_Byte(0xD3, OLED_CMD);
  10.         OLED_WR_Byte(0x00, OLED_CMD);
  11.         OLED_WR_Byte(0x40, OLED_CMD);
  12.         OLED_WR_Byte(0xA1, OLED_CMD);   //A0/A1:控制屏幕显示左右映射翻转的
  13.         OLED_WR_Byte(0xC0, OLED_CMD);   //C0/C8:控制屏幕上下映射翻转的
  14.         OLED_WR_Byte(0xDA, OLED_CMD);
  15.         OLED_WR_Byte(0x12, OLED_CMD);   //02h:隔行显示  12h:逐行显示
  16.         OLED_WR_Byte(0x81, OLED_CMD);
  17.         OLED_WR_Byte(0x7F, OLED_CMD);
  18.         OLED_WR_Byte(0xA4, OLED_CMD);
  19.         OLED_WR_Byte(0xA6, OLED_CMD);
  20.         OLED_WR_Byte(0xD5, OLED_CMD);
  21.         OLED_WR_Byte(0x80, OLED_CMD);
  22.         OLED_WR_Byte(0x8D, OLED_CMD);
  23.         OLED_WR_Byte(0x14, OLED_CMD);
  24.         OLED_WR_Byte(0xAF, OLED_CMD);
  25.         
  26.         OLED_Clear();
复制代码

3.I2C
这里I2C和上文提到的OLED的初始化以及功能实现都大致相同,就不做太多的语言描述。

  1. /*
  2.         OLED0.96                                                                          STM32
  3.         GND                                        <----------->                                        GND
  4.         VCC                                        <----------->                                        3.3V
  5.         D0(SCLK)                    <----------->                                        PA0                        
  6.         D1SDIN()                      <----------->                                        PA1
  7.         RES                                         <----------->                                        PA2
  8.         DC(Data/Command)           <----------->                                        PA3
  9.         CS                                                <----------->                                        PA4
  10. */
复制代码

OLED的初始化和配置如下:

  1. void OLED_Init(void)
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStructure;

  4.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
  5.         
  6.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;
  7.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  8.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  9.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  10.         
  11.         GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4);
  12.         
  13.         OLED_RST_Set();
  14.         delay_us(100000);
  15.         OLED_RST_Clr();
  16.         delay_us(20);
  17.         OLED_RST_Set();
  18.         
  19.         OLED_WR_Byte(0xA8, OLED_CMD);
  20.         OLED_WR_Byte(0x3F, OLED_CMD);
  21.         OLED_WR_Byte(0xD3, OLED_CMD);
  22.         OLED_WR_Byte(0x00, OLED_CMD);
  23.         OLED_WR_Byte(0x40, OLED_CMD);
  24.         OLED_WR_Byte(0xA1, OLED_CMD);   //A0/A1:控制屏幕显示左右映射翻转的
  25.         OLED_WR_Byte(0xC0, OLED_CMD);   //C0/C8:控制屏幕上下映射翻转的
  26.         OLED_WR_Byte(0xDA, OLED_CMD);
  27.         OLED_WR_Byte(0x12, OLED_CMD);   //02h:隔行显示  12h:逐行显示
  28.         OLED_WR_Byte(0x81, OLED_CMD);
  29.         OLED_WR_Byte(0x7F, OLED_CMD);
  30.         OLED_WR_Byte(0xA4, OLED_CMD);
  31.         OLED_WR_Byte(0xA6, OLED_CMD);
  32.         OLED_WR_Byte(0xD5, OLED_CMD);
  33.         OLED_WR_Byte(0x80, OLED_CMD);
  34.         OLED_WR_Byte(0x8D, OLED_CMD);
  35.         OLED_WR_Byte(0x14, OLED_CMD);
  36.         OLED_WR_Byte(0xAF, OLED_CMD);
  37.         
  38.         OLED_Clear();
  39. }
复制代码

也是照着本文提到的第二种方法能完成的。这里就不太多描述。
但是,与上文提到的第二种方法不同,在数据/命令选择中,与上文不同

  1. //dat:要写入的数据/命令
  2. //cmd:0表示命令,1表示数据
  3. void OLED_WR_Byte(u8 dat,u8 cmd)
  4. {
  5.         u8 i;
  6.         
  7.         if(cmd)
  8.                 OLED_DC_Set();
  9.         else
  10.                 OLED_DC_Clr();   
  11.         
  12.         OLED_CS_Clr();  //拉低CS
  13.         
  14.         for(i = 0; i < 8; i++)
  15.         {
  16.                 OLED_SCLK_Clr();
  17.                 if(dat & 0x80)
  18.                         OLED_SDIN_Set();
  19.                 else
  20.                         OLED_SDIN_Clr();
  21.                 OLED_SCLK_Set();
  22.                
  23.                 dat <<= 1;
  24.         }
  25.         
  26.         OLED_CS_Set();
  27. }
复制代码

代码分析:
与上面不同的是,使用此方法驱动的OLED的IO多了SDIN这一个IO口,而这个IO的存在,导致其OLED_WR_ Byte()的写法不太一样。需要注意一下即可。

二、阅读datasheet(数据手册)
OLED可以传输命令(cmd)或者是数据(data),而传输命令或者传输数据,都需要依靠之前提到的函数,以8080串口方式为例的OLED初始化,正点原子的代码中也很明确的注释了:


  1.         OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示
  2.         OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率
  3.         OLED_WR_Byte(80,OLED_CMD);   //[3:0],分频因子;[7:4],震荡频率
  4.         OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数
  5.         OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64)
  6.         OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移
  7.         OLED_WR_Byte(0X00,OLED_CMD); //默认为0

  8.         OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数.
  9.                                                                                                             
  10.         OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置
  11.         OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭
  12.         OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式
  13.         OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
  14.         OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127;
  15.         OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
  16.         OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置
  17.         OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置
  18.                  
  19.         OLED_WR_Byte(0x81,OLED_CMD); //对比度设置
  20.         OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮)
  21.         OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期
  22.         OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2;
  23.         OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率
  24.         OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

  25.         OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
  26.         OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示                                                               
  27.         OLED_WR_Byte(0xAF,OLED_CMD); //开启显示         
  28.         OLED_Clear();
复制代码

由于使用的同一厂家的OLED屏幕,所以往OLED中写入的命令字符也是大致的相同,SPI四线写入的命令为:
  1.       
  2.         OLED_WR_Byte(0xA8, OLED_CMD);
  3.         OLED_WR_Byte(0x3F, OLED_CMD);
  4.         OLED_WR_Byte(0xD3, OLED_CMD);
  5.         OLED_WR_Byte(0x00, OLED_CMD);
  6.         OLED_WR_Byte(0x40, OLED_CMD);
  7.         OLED_WR_Byte(0xA1, OLED_CMD);   //A0/A1:控制屏幕显示左右映射翻转的
  8.         OLED_WR_Byte(0xC0, OLED_CMD);   //C0/C8:控制屏幕上下映射翻转的
  9.         OLED_WR_Byte(0xDA, OLED_CMD);
  10.         OLED_WR_Byte(0x12, OLED_CMD);   //02h:隔行显示  12h:逐行显示
  11.         OLED_WR_Byte(0x81, OLED_CMD);
  12.         OLED_WR_Byte(0x7F, OLED_CMD);
  13.         OLED_WR_Byte(0xA4, OLED_CMD);
  14.         OLED_WR_Byte(0xA6, OLED_CMD);
  15.         OLED_WR_Byte(0xD5, OLED_CMD);
  16.         OLED_WR_Byte(0x80, OLED_CMD);
  17.         OLED_WR_Byte(0x8D, OLED_CMD);
  18.         OLED_WR_Byte(0x14, OLED_CMD);
  19.         OLED_WR_Byte(0xAF, OLED_CMD);
  20.         
  21.         OLED_Clear();
复制代码

不难发现,也是万变不离其宗。

总结
在这三种OLED的驱动方式中,最重要的还是需要了解OLED_WR_Byte()这个函数后续的显示操作也是和此函数息息相关。而对于一些OLED屏幕的描点函数和显示数字和字符函数,如果后续有时间的话,我会逐渐完善的。

(SPI驱动OLED的方法和I2C驱动OLED的方法我在上文好像混淆了,准确的说第二种方法应该叫六针OLED,而第三种应该是七针OLED)

对于该篇文章的话,我也不太敢打包票说我能讲清楚OLED不同驱动方式下的详细步骤以及为什么,我只能尽我所能。如果有什么不足以及不对的地方希望大家指正。


收藏 评论0 发布时间:2022-8-15 21:25

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版