找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 11719|回复: 12
打印 上一主题 下一主题
收起左侧

STM8S驱动OLED12864

  [复制链接]
跳转到指定楼层
楼主
ID:145459 发表于 2016-11-15 01:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

这种OLED的液晶屏似乎很受电子爱好者的欢迎,原因大概是:
①这种屏小巧玲珑,同样是128*64点阵的液晶屏,这种屏的体积比以前那种LCD12864小了四分之一,作为DIY手表的屏幕刚刚好。
②功耗低,由于OLED是有机发光材料制作成的,没有使用背光,所以功耗比使用LED作为背光的液晶屏,功耗要低很多。所以这块液晶屏适合用于手表之类的手持设备。
③可以选择的接口很多。接口和使用的液晶屏驱动芯片有关,大多数OLED12864使用的驱动芯片是SSD1306,这款驱动芯片提供给MCU的接口有5种,如下图。本文使用I2C接口来驱动OLED,主要是因为I2C占用MCU的IO少,当然用SPI接口驱动OLED的也很多。

使用I2C接口时,D0脚作为I2C的SCLK时钟信号线,D1,D2作为SDA数据信号线。D/C#引脚做为地址设定引脚,该引脚接地,OLED器件地址为0x78,该引脚上拉,OLED器件地址为0x7A。

当使用I2C时,SCLK和SDA引脚要加上拉电阻,关于上拉电阻要注意:
①如果I2C的速度很低,使用10K的上拉电阻是可以的,这个低速大概是100KHz
②如果I2C的速度很高,要达到300KHz左右,这个上拉电阻的阻值应该为4.7K

在淘宝上买的OLED模块,有的直接焊接了10K的上拉电阻,这样对于需要I2C高速通信的用户来说,很不方便,不查看电路还以为是程序出了问题,很浪费时间。今天我就遇到了这个问题,查找了好长时间,手头上又没4.7K的电阻,只好又并了个10K的电阻。


上图是SSD1306的显存分布,y轴范围是0~7,分为8个页,x轴坐标是0~127.


上图是对OLED写入地址的设定.

SSD1306也有一些控制命令,详情请查看SSD1306的数据手册。

由于我的STM8L-DISCOVERY的芯片烧坏掉了,所以没办法再继续用STM8L来写程序了。去淘宝买了块STM8S103F3的最小系统板,使用STM8L-DISCOVERY上的SWIM进行仿真调试。


第一次遇到,超过2000字不能发表的情况,大概是程序太长了。我把程序上传到GitHub了,刚刚摸索着使用这个国外的网站进行代码托管,由于是全英文的网站,还不是很会用。

  1. /*硬件连接*/
  2. // PB4--SCL   PB5--SDA
  3. /****************************************************************************************
  4. *开发环境:IAR for stm8 v6.5.3
  5. *硬件平台:STM8S103F3
  6. *功能说明:通过硬件I2C等待的方法,
  7. *作    者:茗风
  8. ****************************************************************************************/
  9. #include"iostm8s103f3.h"
  10. #include"stdbool.h"
  11. #include"stdint.h"

  12. /******************************************************************************************************
  13. * 名 称: uint8_t I2C_ReadOneByteDataFromSlave(uint8_t address)
  14. * 功 能:从I2C从设备中读取一字节的数据
  15. * 入口参数:address:读取数据的寄存器地址
  16. * 出口参数:返回一个从I2C从设备指定地址读到的数据
  17. * 说 明:
  18. * 范 例:无
  19. ******************************************************************************************************/
  20. uint8_t I2C_ReadOneByteDataFromSlave(uint8_t slave_address,uint8_t address)
  21. {
  22.   volatile uint8_t t;
  23.   //----------I2C起始信号--------------
  24.   I2C_CR2_START=1;//产生一个起始条件
  25.   while(!(I2C_SR1_SB==1));//读SR1寄存器,清除SB标志位
  26. //  _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
  27.   
  28.   //-------发送写I2C从器件地址---------
  29.   I2C_DR=slave_address;//发送从设备地址
  30.   while(!(I2C_SR1_ADDR==1));//读SR1寄存器,清除ADDR标志位
  31. // _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
  32.   if(I2C_SR3_TRA==0)return 1;//读SR3寄存器,清除ADDR标志位
  33.   //  0: Data bytes received
  34.   //  1: Data bytes transmitted
  35.   
  36.   //-----写I2C从器件寄存器地址--------
  37.   I2C_DR=address;
  38.   while(!(I2C_SR1_BTF==1));//等待地址发送完成
  39. //  _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
  40.   
  41.   //--------I2C重复起始信号-----------
  42.   I2C_CR2_START=1;//重复产生一个起始条件
  43.   while(!(I2C_SR1_SB==1));//读SR1寄存器,清除SB标志位
  44. //  _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
  45.   
  46.   //-------发送读I2C从器件地址---------
  47.   I2C_DR=0xD1;//发送从设备地址
  48.   while(!(I2C_SR1_ADDR==1));//读SR1寄存器,清除ADDR标志位
  49. //  _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
  50.   if(I2C_SR3_TRA==1)return 1;//读SR3寄存器,清除ADDR标志位
  51.   
  52.   //-------------停止信号-------------
  53.   I2C_CR2_ACK=0;//ACK位控制着ACK信号,此位为0可以产生一个NOACK信号
  54.   I2C_CR2_STOP=1;
  55.   
  56.   //-------------等待接收到数据-------------
  57.   while(!(I2C_SR1_RXNE==1));//等待地址发送完成
  58.   
  59.   //-------------读取数据-------------
  60.   t=I2C_DR;
  61.   
  62.   return t;
  63. }
  64. /******************************************************************************************************
  65. * 名 称:void I2C_WriteOneByteDataToSlave(uint8_t address,uint8_t dat)
  66. * 功 能:写入一字节的数据到I2C设备中
  67. * 入口参数:address:写入的数据存储地址    dat:待写入的数据
  68. * 出口参数:无
  69. * 说 明: 通过MSTM8L硬件写入I2C设备一个字节的数据
  70. * 范 例:无
  71. ******************************************************************************************************/
  72. uint8_t I2C_WriteOneByteDataToSlave(uint8_t slave_address,uint8_t address,uint8_t dat)
  73. {
  74.   volatile uint8_t t;
  75.   I2C_CR2_ACK=1;
  76.   //----------I2C起始信号--------------
  77.   I2C_CR2_START=1;//产生一个起始条件
  78.   while(!(I2C_SR1_SB==1));
  79. // _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
  80.   I2C_DR=slave_address;
  81.   
  82.   //--------写I2C从器件地址-----------
  83.   while(!(I2C_SR1_ADDR==1));
  84. //  _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
  85.   if(I2C_SR3_TRA==0)return 1;//读SR3寄存器,清除ADDR标志位
  86.   
  87.   //-----写I2C从器件寄存器地址--------
  88.   while(!(I2C_SR1_TXE==1));
  89.   I2C_DR=address;
  90.   
  91.   //-------写I2C数据到寄存器中--------
  92.   while(!(I2C_SR1_TXE==1));
  93.   I2C_DR=dat;
  94.   while(!(I2C_SR1_TXE==1));
  95.   while(!(I2C_SR1_BTF==1));
  96. // _5NOPS;//根据数据手册,检测到标志位后,需插入5个NOP进行延时
  97.   
  98.   //-------------停止信号-------------
  99.   I2C_CR2_STOP=1;
  100.   return 0;
  101. }
  102. /******************************************************************************************************
  103. * 功    能:从I2C从设备读取多个字节数据
  104. * 入口函数:
  105. * 出口函数:
  106. * 说    明:
  107. * 范    例:
  108. * 日    期:
  109. ******************************************************************************************************/
  110. uint8_t I2C_ReadMultiBytesFromSlave(uint8_t slave_address,uint8_t address,uint8_t *rxbuf,uint8_t len)
  111. {
  112.   volatile uint8_t i=0;
  113.   
  114.   if(len==0)return 1;//如果写入字节长度为0退出
  115.   
  116.   I2C_CR2_ACK=1;
  117.   //----------I2C起始信号--------------
  118.   I2C_CR2_START=1;//产生一个起始条件
  119.   while(!(I2C_SR1_SB==1));//读SR1寄存器,清除SB标志位
  120.   
  121.   //-------发送写I2C从器件地址---------
  122.   I2C_DR=slave_address;//发送从设备地址
  123.   while(!(I2C_SR1_ADDR==1));//读SR1寄存器,清除ADDR标志位
  124.   if(I2C_SR3_TRA==0)return 1;//读SR3寄存器,清除ADDR标志位
  125.   //  0: Data bytes received
  126.   //  1: Data bytes transmitted
  127.   
  128.   //-----写I2C从器件寄存器地址--------
  129.   I2C_DR=address;
  130.   while(!(I2C_SR1_BTF==1));//等待地址发送完成
  131.   
  132.   //--------I2C重复起始信号-----------
  133.   I2C_CR2_START=1;//重复产生一个起始条件
  134.   while(!(I2C_SR1_SB==1));//读SR1寄存器,清除SB标志位
  135.   
  136.   //-------发送读I2C从器件地址---------
  137.   I2C_DR=0xD1;//发送从设备地址
  138.   while(!(I2C_SR1_ADDR==1));//读SR1寄存器,清除ADDR标志位
  139.   if(I2C_SR3_TRA==1)return 1;//读SR3寄存器,清除ADDR标志位
  140.   //-------------读取数据-------------
  141.   if(len>1)
  142.   {
  143.       for( i=len;i>1;i-- )
  144.       {
  145.         while(!(I2C_SR1_RXNE==1));//等待I2C_DR接收到数
  146.         *rxbuf++ = I2C_DR;  
  147.       }
  148.   }

  149.   //-------------停止信号-------------
  150.   I2C_CR2_ACK=0;//ACK位控制着ACK信号,此位为0可以产生一个NOACK信号
  151.   I2C_CR2_STOP=1;
  152.   
  153.   while(!(I2C_SR1_RXNE==1));//等待I2C_DR接收到数
  154.   *rxbuf++ = I2C_DR;
  155.   
  156.   return 0;
  157. }
  158. /******************************************************************************************************
  159. * 名     称:IIC_init()
  160. * 功     能:初始化I2C,系统主频位8MHz,I2C通信速度333KHz
  161. * 入口 参数:无
  162. * 出口 参数:无
  163. * 说     明:PB4--SCL   PB5--SDA
  164. * 范     例:无
  165. ******************************************************************************************************/
  166. void I2C_Init(void)
  167. {
  168.   //----打开IIC外设时钟----
  169.   I2C_CR1_PE=0;
  170.   I2C_CR2_ACK=1;
  171.   
  172.   //----I2C输入时钟频率选择----
  173.   I2C_FREQR_FREQ=0x08;//8MHz
  174.   /*  The allowed range is between 1 MHz and 16 MHz
  175.   000000: not allowed
  176.   000001: 1 MHz
  177.   000010: 2 MHz
  178.   ...
  179.   010000: 16 MHz                                 */
  180.   
  181.   //----配置时钟控制寄存器----
  182.   I2C_CCRH=0;
  183.   I2C_CCRH_F_S=1; //Fast mode I2C
  184.   I2C_CCRH_DUTY=0;
  185. /* If DUTY = 0:
  186. Period(I2C) = 3* CCR * tMASTER
  187. thigh = CCR * tMASTER
  188. tlow = 2 * CCR * tMASTER*/
  189.   I2C_CCRL=7;    //SCL高电平时间配置
  190.   //I2C的SCK时钟设置为400KHz,则SCK周期为2.5us   2.5us/0.125/3=7   
  191.   //因为I2C_FREQR_FREQ=0x08,即I2C输入时钟频率为8M,周期为0.125us  
  192.   //CCR=7时,SCK的低电平时间为2*tlow=2*7*0.125us=1.75us,SCk高电平时间为thigh=7*0.125us=0.875us
  193.   //所以CCR=7时,SCK输出频率为380KHz
  194.   
  195.   //----配置上升时间寄存器----
  196.   I2C_TRISER_TRISE=5;//in standard mode, the maximum allowed SCL rise time is 1000 ns.
  197.   //1 us / 0.125 us = 8
  198.   //+1
  199.   I2C_CR1_PE=1;//
  200. }
  201. #define  Write_CMD_TO_OLED12864(byte)  I2C_WriteOneByteDataToSlave(0x78,0x00,byte)
  202. #define  Write_DAT_TO_OLED12864(byte)  I2C_WriteOneByteDataToSlave(0x78,0x40,byte)

  203. /************************************6*8的点阵************************************/
  204. const uint8_t ASCII_6X8[92][6] =           //水平寻址
  205. {
  206.     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // sp
  207.     { 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 },   // !
  208.     { 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 },   // "
  209.     { 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 },   // #
  210.     { 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 },   // $
  211.     { 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 },   // %
  212.     { 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 },   // &
  213.     { 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 },   // '
  214.     { 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 },   // (
  215.     { 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 },   // )
  216.     { 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 },   // *
  217.     { 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 },   // +
  218.     { 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 },   // ,
  219.     { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08 },   // -
  220.     { 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 },   // .
  221.     { 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 },   // /
  222.     { 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E },   // 0
  223.     { 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 },   // 1
  224.     { 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 },   // 2
  225.     { 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 },   // 3
  226.     { 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 },   // 4
  227.     { 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 },   // 5
  228.     { 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 },   // 6
  229.     { 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 },   // 7
  230.     { 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 },   // 8
  231.     { 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E },   // 9
  232.     { 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 },   // :
  233.     { 0x00, 0x00, 0x56, 0x36, 0x00, 0x00 },   // ;
  234.     { 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 },   // <
  235.     { 0x00, 0x14, 0x14, 0x14, 0x14, 0x14 },   // =
  236.     { 0x00, 0x00, 0x41, 0x22, 0x14, 0x08 },   // >
  237.     { 0x00, 0x02, 0x01, 0x51, 0x09, 0x06 },   // ?
  238.     { 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E },   // @
  239.     { 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C },   // A
  240.     { 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 },   // B
  241.     { 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 },   // C
  242.     { 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C },   // D
  243.     { 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 },   // E
  244.     { 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 },   // F
  245.     { 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A },   // G
  246.     { 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F },   // H
  247.     { 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 },   // I
  248.     { 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 },   // J
  249.     { 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 },   // K
  250.     { 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 },   // L
  251.     { 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F },   // M
  252.     { 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F },   // N
  253.     { 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E },   // O
  254.     { 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 },   // P
  255.     { 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E },   // Q
  256.     { 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 },   // R
  257.     { 0x00, 0x46, 0x49, 0x49, 0x49, 0x31 },   // S
  258.     { 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 },   // T
  259.     { 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F },   // U
  260.     { 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F },   // V
  261.     { 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F },   // W
  262.     { 0x00, 0x63, 0x14, 0x08, 0x14, 0x63 },   // X
  263.     { 0x00, 0x07, 0x08, 0x70, 0x08, 0x07 },   // Y
  264.     { 0x00, 0x61, 0x51, 0x49, 0x45, 0x43 },   // Z
  265.     { 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 },   // [
  266.     { 0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55 },   // 55
  267.     { 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 },   // ]
  268.     { 0x00, 0x04, 0x02, 0x01, 0x02, 0x04 },   // ^
  269.     { 0x00, 0x40, 0x40, 0x40, 0x40, 0x40 },   // _
  270.     { 0x00, 0x00, 0x01, 0x02, 0x04, 0x00 },   // '
  271.     { 0x00, 0x20, 0x54, 0x54, 0x54, 0x78 },   // a
  272.     { 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 },   // b
  273.     { 0x00, 0x38, 0x44, 0x44, 0x44, 0x20 },   // c
  274.     { 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F },   // d
  275.     { 0x00, 0x38, 0x54, 0x54, 0x54, 0x18 },   // e
  276.     { 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 },   // f
  277.     { 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C },   // g
  278.     { 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 },   // h
  279.     { 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 },   // i
  280.     { 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 },   // j
  281.     { 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 },   // k
  282.     { 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 },   // l
  283.     { 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 },   // m
  284.     { 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 },   // n
  285.     { 0x00, 0x38, 0x44, 0x44, 0x44, 0x38 },   // o
  286.     { 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 },   // p
  287.     { 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC },   // q
  288.     { 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 },   // r
  289.     { 0x00, 0x48, 0x54, 0x54, 0x54, 0x20 },   // s
  290.     { 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 },   // t
  291.     { 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C },   // u
  292.     { 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C },   // v
  293.     { 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C },   // w
  294.     { 0x00, 0x44, 0x28, 0x10, 0x28, 0x44 },   // x
  295.     { 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C },   // y
  296.     { 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 },   // z
  297.     { 0x14, 0x14, 0x14, 0x14, 0x14, 0x14 }    // horiz lines
  298. };

  299. //汉字 “楠楠,我爱你!”先扫描这串汉字的上半部分,再扫描下半部分
  300. uint8_t Hzk1[]=   //本数据由PCtoLCD取模软件产生,手动改了一下汉字下半部分数据位置
  301. {
  302.    //楠楠,我爱你!
  303.   0x84,0x64,0xFF,0x24,0xFA,0x0A,0x5A,0xEF,0x5A,0x0A,0xFA,0x00,/*"楠",0up*/
  304.   0x84,0x64,0xFF,0x24,0xFA,0x0A,0x5A,0xEF,0x5A,0x0A,0xFA,0x00,/*"楠",1up*/
  305.   0x00,0x00,0x00,0x00,0x00,0x00,/*",",2up*/
  306.   0x10,0x12,0x12,0xFF,0x91,0x10,0xFF,0x10,0x90,0x52,0x14,0x00,/*"我",3up*/
  307.   0x32,0x56,0x5A,0xD2,0x76,0x5A,0x51,0x51,0x59,0x55,0x31,0x00,/*"爱",4up*/
  308.   0x20,0x10,0xFC,0x03,0x10,0xCF,0x04,0xF4,0x04,0x54,0x8C,0x00,/*"你",5up*/
  309.   0x00,0x00,0x7C,0x00,0x00,0x00,/*"!",6up*/
  310.   0x00,0x00,0x0F,0x00,0x0F,0x01,0x01,0x07,0x01,0x09,0x0F,0x00,/*"楠",0*/
  311.   0x00,0x00,0x0F,0x00,0x0F,0x01,0x01,0x07,0x01,0x09,0x0F,0x00,/*"楠",1*/
  312.   
  313.   0x04,0x03,0x00,0x00,0x00,0x00,/*",",2*/
  314.   0x02,0x02,0x09,0x0F,0x00,0x04,0x02,0x03,0x04,0x08,0x0E,0x00,/*"我",3*/
  315.   0x08,0x04,0x0A,0x09,0x0B,0x05,0x05,0x05,0x0B,0x08,0x08,0x00,/*"爱",4*/
  316.   0x00,0x00,0x0F,0x00,0x02,0x01,0x08,0x0F,0x00,0x00,0x03,0x00,/*"你",5*/
  317.   0x00,0x00,0x02,0x00,0x00,0x00/*"!",6*/
  318. };



  319. /******************************************************************************************************
  320. * 功    能:清屏
  321. * 入口函数:
  322. * 出口函数:
  323. * 说    明:
  324. * 范    例:
  325. * 日    期:2016年11月1日
  326. ******************************************************************************************************/
  327. void OLED12864_Clear(void)
  328. {
  329.   uint8_t x,y;
  330.   for(y=0;y<8;y++)
  331.   {
  332.     //设置地址
  333.     Write_CMD_TO_OLED12864(0xB0+y);
  334.     Write_CMD_TO_OLED12864(0x00);
  335.     Write_CMD_TO_OLED12864(0x10);
  336.     for(x=0;x<128;x++)
  337.     {
  338.       Write_DAT_TO_OLED12864(0x00);         
  339.     }
  340.   }
  341. }
  342. /******************************************************************************************************
  343. * 功    能:OLED12864初始化配置
  344. * 入口函数:
  345. * 出口函数:
  346. * 说   明:设置显示坐标
  347. * 作   者:茗风
  348. * 日   期:2016年11月1日
  349. ******************************************************************************************************/
  350. void OLED_Set_Pos(uint8_t x, uint8_t y)
  351. {
  352.   if(y>7)return 1;//y轴
  353.         Write_CMD_TO_OLED12864(0xB0+y);//y轴坐标,0xB0为y轴起始地址
  354.   Write_CMD_TO_OLED12864((x&0x0F)+0x00);//x轴坐标低位
  355.         Write_CMD_TO_OLED12864(((x&0xF0)>>4)+0x10);//x轴坐标高位
  356. }
  357. ///******************************************************************************************************
  358. //* 功    能        :向OLED12864写一串字符函数
  359. //* 入口参数        :x  x轴坐标,取值范围(0~127)
  360. //*             y  y轴坐标,取值范围(0~7)
  361. //*             *s 一串字符
  362. //* 出口参数        :无
  363. //* 说    明        :显示6*8一组标准ASCII字符串,显示的坐标(x,y),y为页范围0~7
  364. //* 编写日期  :2016年11月1日
  365. //* 作    者  :茗风
  366. //******************************************************************************************************/
  367. uint8_t OLED12864_Display_Char(uint8_t _char)
  368. {
  369.   uint8_t  i=0;
  370.    
  371.   _char -= 32;//计算ASCII字符在F6x8[][]数组中的位置
  372.      
  373.   for(i=0; i<6; i++)
  374.   {
  375.     Write_DAT_TO_OLED12864(ASCII_6X8[_char][i]);  
  376.   }   
  377.   return 0;
  378. }

  379. ///******************************************************************************************************
  380. //* 功    能        :向OLED12864写一串字符函数
  381. //* 入口参数        :x  x轴坐标,取值范围(0~127)
  382. //*             y  y轴坐标,取值范围(0~7),一共两行
  383. //*             *s 一串字符
  384. //* 出口参数        :无
  385. //* 说    明        :显示6*8一组标准ASCII字符串,显示的坐标(x,y),y为页范围0~7
  386. //* 编写日期  :2016年11月1日
  387. //* 作    者  :茗风
  388. //******************************************************************************************************/
  389. uint8_t OLED12864_Display_String(uint8_t x,uint8_t y,uint8_t *s)
  390. {
  391. //  uint8_t c=0, i=0;
  392.   OLED_Set_Pos(x,y);   
  393.   while (*s != '\0')
  394.   {   
  395. //    c = *s-32;//计算ASCII字符在F6x8[][]数组中的位置
  396. //    if(x>126) {x=0; y++;}   
  397.     OLED12864_Display_Char(*s++);  
  398. //    x += 6;
  399. //    s++;//指向字符串的指针自增,指向下一个字符
  400.   }  
  401.   return 0;
  402. }
  403. ///******************************************************************************************************
  404. //* 功    能        :OLED12864显示一个uint16_t类型的数据
  405. //* 入口参数        :x  x轴坐标,取值范围(0~127)
  406. //*             y  y轴坐标,取值范围(0~7),一共两行
  407. //*             number 写入的字符
  408. //* 出口参数        :无
  409. //* 说    明        :
  410. //* 编写日期  :2016年10月22日
  411. //* 作    者  :茗风
  412. //******************************************************************************************************/
  413. void LCD1602_Display_Number(uint8_t x,uint8_t y,uint32_t _number)
  414. {
  415. //  uint8_t tmp=0;
  416.   OLED_Set_Pos(x,y);  
  417.   
  418.   if(_number<10)  //9
  419.   {
  420.      OLED12864_Display_Char(_number%10+48);
  421.   }
  422.   else if(_number<100) //98
  423.   {
  424.      OLED12864_Display_Char(_number/10+48);
  425.      OLED12864_Display_Char(_number%10+48);
  426.   }
  427.   else if(_number<1000) //988
  428.   {
  429.      OLED12864_Display_Char(_number/100+48);
  430.      OLED12864_Display_Char(_number%100/10+48);
  431.      OLED12864_Display_Char(_number%10+48);
  432.   }
  433.   else if(_number<10000) //9999
  434.   {
  435.      OLED12864_Display_Char(_number/1000+48);
  436.      OLED12864_Display_Char(_number%1000/100+48);
  437.      OLED12864_Display_Char(_number%100/10+48);
  438.      OLED12864_Display_Char(_number%10+48);
  439.   }
  440.   else if(_number<100000) //99999
  441.   {
  442.      OLED12864_Display_Char(_number/10000+48);
  443.      OLED12864_Display_Char(_number%10000/1000+48);
  444.      OLED12864_Display_Char(_number%1000/100+48);
  445.      OLED12864_Display_Char(_number%100/10+48);
  446.      OLED12864_Display_Char(_number%10+48);
  447.   }
  448.   else if(_number<1000000) //999999
  449.   {
  450.      OLED12864_Display_Char(_number/100000+48);
  451.      OLED12864_Display_Char(_number%100000/10000+48);
  452.      OLED12864_Display_Char(_number%10000/1000+48);
  453.      OLED12864_Display_Char(_number%1000/100+48);
  454.      OLED12864_Display_Char(_number%100/10+48);
  455.      OLED12864_Display_Char(_number%10+48);
  456.   }
  457.   else if(_number<10000000) //999999
  458.   {
  459.      OLED12864_Display_Char(_number/1000000+48);
  460.      OLED12864_Display_Char(_number%1000000/100000+48);
  461.      OLED12864_Display_Char(_number%100000/10000+48);
  462.      OLED12864_Display_Char(_number%10000/1000+48);
  463.      OLED12864_Display_Char(_number%1000/100+48);
  464.      OLED12864_Display_Char(_number%100/10+48);
  465.      OLED12864_Display_Char(_number%10+48);
  466.   }
  467. }
  468. ///******************************************************************************************************
  469. //*  功  能   :显示一行汉字,汉字大小为12*12,先写上半部分8个像素,再写下半部分4个像素
  470. //*  入口参数 :x,y:汉字写入的地址坐标   s:写的汉字数组  len:汉字数组中的数据个数
  471. //*  出口参数 : 0:写字串成功     1:坐标越界      2:字符越界
  472. //*  说  明   :注意,本函数暂时只能一次写小于一行的汉字,多行需要分开写
  473. //*  范  例   :无
  474. //* 日     期:2016年10月31日
  475. //******************************************************************************************************/
  476. uint8_t OLED12864_Display_SimplifiedChinese(uint8_t x,uint8_t y,uint8_t *s,uint16_t len)
  477. {
  478.     static uint8_t i=0;
  479.   
  480.     len=len/2;//分上半部分和下半部分写入
  481.     //先写上半部分8个像素
  482.     OLED_Set_Pos(x,y);
  483.     for(i=0;i<len;i++)
  484.     {      
  485.       Write_DAT_TO_OLED12864(*s++);
  486.     }
  487.     //再写下半部分4个像素
  488.     OLED_Set_Pos(x,y+1);
  489.     for(i=0;i<len;i++)
  490.     {
  491.       Write_DAT_TO_OLED12864(*s++);
  492.     }
  493.     return 0;
  494. }
  495. /******************************************************************************************************
  496. * 功    能:draw one picture
  497. * 入口函数:
  498. * 出口函数:
  499. * 说    明:
  500. * 范    例:
  501. * 日    期:2016年10月31日
  502. ******************************************************************************************************/
  503. //void OLED12864_Draw_One_Picture(void)
  504. //{
  505. //  uint8_t x,y;
  506. //  uint16_t i=0;
  507. //  for(y=0;y<8;y++)
  508. //  {
  509. //    Write_CMD_TO_OLED12864(0xb0+y);
  510. //    Write_CMD_TO_OLED12864(0x00);
  511. //    Write_CMD_TO_OLED12864(0x10);
  512. //    for(x=0;x<128;x++)
  513. //    {
  514. //      Write_DAT_TO_OLED12864(0x00);         
  515. //    }
  516. //  }
  517. //  for(y=0;y<8;y++)
  518. //  {
  519. //    Write_CMD_TO_OLED12864(0xb0+y);
  520. //    Write_CMD_TO_OLED12864(0x00);
  521. //    Write_CMD_TO_OLED12864(0x10);
  522. //    for(x=0;x<128;x++)
  523. //    {
  524. //      Write_DAT_TO_OLED12864(show1[i++]);
  525. //      delay_100us(1000);         
  526. //    }
  527. //  }
  528. //}
  529. /******************************************************************************************************
  530. *  名    称:void delay_100us(uint8_t x_us)
  531. *  功    能:延时100us
  532. *  入口参数:无
  533. *  出口参数:无
  534. *  说    明:
  535. *  范    例:无
  536. ******************************************************************************************************/
  537. void delay_100us(uint16_t x_us)
  538. {
  539.   uint8_t j;
  540.   while(x_us--)
  541.   {
  542.     for(j=0;j<33;j++);//2*40个指令周期
  543.   }
  544.   //delay_10ms共消耗 x_ms*2*255+2*x_ms个指令周期  
  545.   //*2*40+2*x_ms=80us+
  546.   //16M/8/2=1M 一个指令周期为1us
  547. }
  548. /******************************************************************************************************
  549. * 功    能:OLED12864初始化配置
  550. * 入口函数:
  551. * 出口函数:
  552. * 说    明:
  553. * 范    例:
  554. * 日    期:2016年10月31日
  555. ******************************************************************************************************/
  556. void OLED12864_Init(void)
  557. {
  558.   delay_100us(100);
  559.         Write_CMD_TO_OLED12864(0xAE); //display off
  560.         Write_CMD_TO_OLED12864(0x20);        //Set Memory Addressing Mode       
  561.         Write_CMD_TO_OLED12864(0x10);        //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
  562.         Write_CMD_TO_OLED12864(0xB0);        //Set Page Start Address for Page Addressing Mode,0-7
  563.         Write_CMD_TO_OLED12864(0xC8);        //Set COM Output Scan Direction
  564.         Write_CMD_TO_OLED12864(0x00);//---set low column address
  565.         Write_CMD_TO_OLED12864(0x10);//---set high column address
  566.         Write_CMD_TO_OLED12864(0x40);//--set start line address
  567.         Write_CMD_TO_OLED12864(0x81);//--set contrast control register
  568.         Write_CMD_TO_OLED12864(0x7F);
  569.         Write_CMD_TO_OLED12864(0xA1);//--set segment re-map 0 to 127
  570.         Write_CMD_TO_OLED12864(0xA6);//--set normal display
  571.         Write_CMD_TO_OLED12864(0xA8);//--set multiplex ratio(1 to 64)
  572.         Write_CMD_TO_OLED12864(0x3F);//
  573.         Write_CMD_TO_OLED12864(0xA4);//0xa4,Output follows RAM content;0xa5,Output ignores RAM content
  574.         Write_CMD_TO_OLED12864(0xD3);//-set display offset
  575.         Write_CMD_TO_OLED12864(0x00);//-not offset
  576.         Write_CMD_TO_OLED12864(0xD5);//--set display clock divide ratio/oscillator frequency
  577.         Write_CMD_TO_OLED12864(0xF0);//--set divide ratio
  578.         Write_CMD_TO_OLED12864(0xD9);//--set pre-charge period
  579.         Write_CMD_TO_OLED12864(0x22); //
  580.         Write_CMD_TO_OLED12864(0xDA);//--set com pins hardware configuration
  581.         Write_CMD_TO_OLED12864(0x12);
  582.         Write_CMD_TO_OLED12864(0xDB);//--set vcomh
  583.         Write_CMD_TO_OLED12864(0x20);//0x20,0.77xVcc
  584.         Write_CMD_TO_OLED12864(0x8D);//--set DC-DC enable
  585.         Write_CMD_TO_OLED12864(0x14);//
  586.         Write_CMD_TO_OLED12864(0xAF);//--turn on oled panel
  587.   OLED12864_Clear();//清屏操作
  588.   OLED12864_Display_String(0,3,"nan nan 5201314!");
  589.   OLED12864_Display_SimplifiedChinese(30,0,Hzk1,sizeof(Hzk1));//楠楠,我爱你!
  590. //  LCD1602_Display_Number(30,5,5201314);
  591. }
  592. void main(void)
  593. {
  594.   CLK_CKDIVR =0x01;  //16M/2^1=8M
  595.   I2C_Init();
  596.   OLED12864_Init();
  597.   while(1)
  598.   {
  599.     //asm("wfi");
  600.   }
  601. }
复制代码




评分

参与人数 1黑币 +10 收起 理由
YJGG + 10 谢谢分享

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏6 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:90140 发表于 2016-11-15 08:33 | 只看该作者
很详细,谢谢楼主分享!
回复

使用道具 举报

板凳
ID:206664 发表于 2017-6-1 21:54 来自手机 | 只看该作者
为什么我刷屏的时候,屏会闪?
回复

使用道具 举报

地板
ID:257024 发表于 2017-12-17 02:12 | 只看该作者
不知道刷屏速度是否够快。有空弄一个来玩玩。
回复

使用道具 举报

5#
ID:257024 发表于 2017-12-19 13:19 | 只看该作者
刚好在某宝上买了一个4针IIC的0.96双色OLED屏。看上去和楼主的一样。
用IAR编译楼主的代码时,报了一个错误:a void function may not return a value
把360行的语句:if (y>7) return 1; //y轴
改写成:if (y>7) return; //y轴
就编译成功了。
感谢楼主的分享。
回复

使用道具 举报

6#
ID:186159 发表于 2018-6-20 15:06 | 只看该作者
回复

使用道具 举报

7#
ID:186159 发表于 2018-6-20 15:13 | 只看该作者
GitHub位置链接  :
https://github.com/tugaozi/STM8_I2C_OLED
回复

使用道具 举报

8#
ID:377647 发表于 2018-7-23 01:08 | 只看该作者
有原理图吗
回复

使用道具 举报

9#
ID:402865 发表于 2018-9-27 22:47 | 只看该作者
楼主能提供完整工程和总体原理图吗
回复

使用道具 举报

10#
ID:123924 发表于 2020-6-22 23:50 | 只看该作者
正好在做移植,很详细。多谢分享
回复

使用道具 举报

11#
ID:754694 发表于 2020-8-26 02:22 来自手机 | 只看该作者
学习了,注释很好理解~
回复

使用道具 举报

12#
ID:951974 发表于 2021-7-21 12:41 | 只看该作者
ganbc 发表于 2017-12-19 13:19
刚好在某宝上买了一个4针IIC的0.96双色OLED屏。看上去和楼主的一样。
用IAR编译楼主的代码时,报了一个错 ...

我也是,不改的话报错,但是改了后编译是成功了,但是刷进去无显示。。。
回复

使用道具 举报

13#
ID:412650 发表于 2021-7-23 00:12 | 只看该作者
感谢楼主,在楼主代码的帮助下,终于点亮了OLED
不过小弟刚开始接触C及单片机,有个地方想请教一下
下面代码的“_char”是什么意思,是怎么实现的计算ASCII字符在数组中的位置呢?
感谢!!

u8 OLED12864_Display_Char(u8 _char)
{
  u8 i=0;
   
  _char -= 32;//计算ASCII字符在F6x8[][]数组中的位置
     
  for(i=0; i<8; i++)
  {
    Write_DAT_TO_OLED12864(ASCII_6X8[_char][i]);  
  }   
  return 0;
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表