社区导航

 

搜索
查看: 234|回复: 0

[经验分享] 【GD32E231 DIY大赛】4,模拟IIC操作OLED

[复制链接]

40

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2019-5-19 00:11 | 显示全部楼层 |阅读模式
模拟IIC相对而言是一种很简单的曹锁IIC的方式,编程简单,而且易于修改操作。所以对于IIC的操作我一般是选用模拟IIC来做的。
OLED的程序是参考的正点原子的OLED显示代码修改了部分的。
支持OLED的字符,文字和图形的显示。
IIC连线:SCL -- PB10
              SDA -- PB11

IIC驱动程序:
myiic.c
  1. #include "myiic.h"
  2. #include "systick.h"

  3. /*init IIC*/
  4. void IIC_Init(void)
  5. {                                                    
  6.         rcu_periph_clock_enable(RCU_GPIOB);   
  7.         gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_10|GPIO_PIN_11);
  8.         gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10|GPIO_PIN_11);        
  9. }
  10. /*IIC start signal*/
  11. void IIC_Start(void)
  12. {
  13.         SET_IIC_SDA();                    
  14.         SET_IIC_SCL();
  15.         CLR_IIC_SDA();//START:when CLK is high,DATA change form high to low
  16.         CLR_IIC_SCL();//钳住I2C总线,准备发送或接收数据
  17. }          
  18. /*IIC stop signal*/
  19. void IIC_Stop(void)
  20. {
  21.         SET_IIC_SCL();
  22.         CLR_IIC_SDA();//STOP:when CLK is high DATA change form low to high
  23.         SET_IIC_SDA();//发送I2C总线结束信号                                                          
  24. }
  25. /*wait for reponse signal*/
  26. //return :1,failure
  27. //         0,sucessful
  28. u8 IIC_Wait_Ack(void)
  29. {
  30. //        u8 ucErrTime=0;
  31. //        SDA_IN();      //Set the SDA as input
  32. //        SET_IIC_SDA();          
  33.         SET_IIC_SCL();
  34. //        while(READ_SDA)
  35. //        {
  36. //                ucErrTime++;
  37. //                if(ucErrTime>250)
  38. //                {
  39. //                        IIC_Stop();
  40. //                        return 1;
  41. //                }
  42. //        }
  43.         CLR_IIC_SCL();                                  
  44.         return 0;  
  45. }
  46. /*ack signal*/
  47. void IIC_Ack(void)
  48. {
  49.         CLR_IIC_SCL();
  50.         SDA_OUT();
  51.         CLR_IIC_SDA();
  52.         SET_IIC_SCL();
  53.         CLR_IIC_SCL();
  54. }
  55. //不产生ACK应答                    
  56. void IIC_NAck(void)
  57. {
  58.         CLR_IIC_SCL();
  59.         SDA_OUT();
  60.         SET_IIC_SDA();
  61.         SET_IIC_SCL();
  62.         CLR_IIC_SCL();
  63. }                                                                              
  64. //IIC发送一个字节
  65. //返回从机有无应答
  66. //1,有应答
  67. //0,无应答                          
  68. void IIC_Send_Byte(u8 txd)
  69. {                        
  70.     u8 t;      
  71.     CLR_IIC_SCL();//拉低时钟开始数据传输
  72.     for(t=0;t<8;t++)
  73.     {              
  74.                 if((txd&0x80)>>7)
  75.                         SET_IIC_SDA();
  76.                 else
  77.                         CLR_IIC_SDA();
  78.         txd<<=1;           
  79.                 SET_IIC_SCL();
  80.                 CLR_IIC_SCL();       
  81.     }         
  82. }             
  83. //读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
  84. u8 IIC_Read_Byte(unsigned char ack)
  85. {
  86.         unsigned char i,receive=0;
  87.         SDA_IN();//SDA设置为输入
  88.     for(i=0;i<8;i++ )
  89.         {
  90.         CLR_IIC_SCL();
  91.                 SET_IIC_SCL();
  92.         receive<<=1;
  93.         if(READ_SDA)
  94.                         receive++;   
  95.     }                                         
  96.     if (!ack)
  97.         IIC_NAck();//发送nACK
  98.     else
  99.         IIC_Ack(); //发送ACK   
  100.     return receive;
  101. }




复制代码




myiic.h
  1. #ifndef __MYIIC_H
  2. #define __MYIIC_H

  3. #include "gd32e23x.h"

  4. typedef uint8_t u8;
  5. typedef uint16_t u16;
  6. typedef uint32_t u32;

  7. //IO操作函数         
  8. #define SET_IIC_SCL() gpio_bit_set(GPIOB, GPIO_PIN_10)//输出1
  9. #define CLR_IIC_SCL() gpio_bit_reset(GPIOB, GPIO_PIN_10)//输出0

  10. #define SET_IIC_SDA() gpio_bit_set(GPIOB, GPIO_PIN_11)//输出1
  11. #define CLR_IIC_SDA() gpio_bit_reset(GPIOB, GPIO_PIN_11)//输出0

  12. #define READ_SDA   gpio_input_bit_get(GPIOB, GPIO_PIN_11)  //输入SDA

  13. //IO方向设置
  14. #define SDA_IN()      gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_11)//配置为输入
  15. #define SDA_OUT()     { gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_11);\
  16.                                                 gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11);} //配置为输出
  17.    
  18. //IIC所有操作函数
  19. void IIC_Init(void);                //初始化IIC的IO口                                 
  20. void IIC_Start(void);                                //发送IIC开始信号
  21. void IIC_Stop(void);                                  //发送IIC停止信号
  22. void IIC_Send_Byte(unsigned char txd);                        //IIC发送一个字节
  23. unsigned char IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
  24. unsigned char IIC_Wait_Ack(void);                                 //IIC等待ACK信号
  25. void IIC_Ack(void);                                        //IIC发送ACK信号
  26. void IIC_NAck(void);                                //IIC不发送ACK信号

  27. void IIC_Write_One_Byte(unsigned char daddr,unsigned char addr,unsigned char data);
  28. unsigned char IIC_Read_One_Byte(unsigned char daddr,unsigned char addr);          

  29. #endif


复制代码




OLED驱动程序:
oled.c
  1. //OLED
  2. #include "codetab.h"
  3. #include "app_oled.h"
  4. #include "myiic.h"
  5. #include "systick.h"

  6. /*******************************************************************************
  7. * Definitions
  8. ******************************************************************************/


  9. /*******************************************************************************
  10. * Prototypes
  11. ******************************************************************************/


  12. /*******************************************************************************
  13. * Code
  14. ******************************************************************************/

  15. //OLED的显存
  16. //存放格式如下.
  17. //[0]0 1 2 3 ... 127       
  18. //[1]0 1 2 3 ... 127       
  19. //[2]0 1 2 3 ... 127       
  20. //[3]0 1 2 3 ... 127       
  21. //[4]0 1 2 3 ... 127       
  22. //[5]0 1 2 3 ... 127       
  23. //[6]0 1 2 3 ... 127       
  24. //[7]0 1 2 3 ... 127                   
  25. u8 OLED_GRAM[128][8];       

  26. /*********************OLED写数据函数************************************/
  27. void OLED_WrDat(unsigned char IIC_Data)
  28. {
  29.         IIC_Start();
  30.         IIC_Send_Byte(0x78);
  31.         IIC_Wait_Ack();
  32.         IIC_Send_Byte(0x40);                        //write data
  33.         IIC_Wait_Ack();
  34.         IIC_Send_Byte(IIC_Data);
  35.         IIC_Wait_Ack();
  36.         IIC_Stop();
  37. }
  38. /*********************OLED写命令函数************************************/
  39. void OLED_WrCmd(unsigned char IIC_Command)
  40. {
  41.         IIC_Start();
  42.         IIC_Send_Byte(0x78);            //Slave address,SA0=0
  43.         IIC_Wait_Ack();
  44.         IIC_Send_Byte(0x00);                        //write command
  45.         IIC_Wait_Ack();
  46.         IIC_Send_Byte(IIC_Command);
  47.         IIC_Wait_Ack();
  48.         IIC_Stop();
  49. }

  50. //--------------------------------------------------------------
  51. // Prototype      : void OLED_OFF(void)
  52. // Calls          :
  53. // Parameters     : none
  54. // Description    : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
  55. //--------------------------------------------------------------
  56. void OLED_OFF(void)
  57. {
  58.         OLED_WrCmd(0X8D);  
  59.         OLED_WrCmd(0X10);  
  60.         OLED_WrCmd(0XAE);  
  61. }


  62. //--------------------------------------------------------------
  63. // Prototype      : void OLED_ON(void)
  64. // Calls          :
  65. // Parameters     : none
  66. // Description    : 将OLED从休眠中唤醒
  67. //--------------------------------------------------------------
  68. void OLED_ON(void)
  69. {
  70.         OLED_WrCmd(0X8D);
  71.         OLED_WrCmd(0X14);  
  72.         OLED_WrCmd(0XAF);  
  73. }

  74. //x1,y1,x2,y2 填充区域的对角坐标
  75. //确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63                  
  76. //dot:0,清空;1,填充          
  77. void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot)  
  78. {  
  79.         u8 x,y;  
  80.         for(x=x1;x<=x2;x++)
  81.                 for(y=y1;y<=y2;y++)
  82.                         OLED_DrawPoint(x,y,dot);                                                                                            
  83.         OLED_Refresh_Gram();//更新显示
  84. }

  85. //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!          
  86. void OLED_Clear(void)  
  87. {  
  88.         u8 i,n;  
  89.         for(i=0;i<8;i++)
  90.                 for(n=0;n<128;n++)
  91.                         OLED_GRAM[n][i]=0X00;  
  92.         OLED_Refresh_Gram();//更新显示
  93. }

  94. /*********************OLED初始化************************************/
  95. void OLED_Init(void)
  96. {
  97.         IIC_Init();
  98. //        delay_1ms(100);

  99.         OLED_WrCmd(0xAE); //关闭显示
  100.         OLED_WrCmd(0xD5); //设置时钟分频因子,震荡频率
  101.         OLED_WrCmd(80);   //[3:0],分频因子;[7:4],震荡频率
  102.         OLED_WrCmd(0xA8); //设置驱动路数
  103.         OLED_WrCmd(0X3F); //默认0X3F(1/64)
  104.         OLED_WrCmd(0xD3); //设置显示偏移
  105.         OLED_WrCmd(0X00); //默认为0

  106.         OLED_WrCmd(0x40); //设置显示开始行 [5:0],行数.
  107.                                                                                                             
  108.         OLED_WrCmd(0x8D); //电荷泵设置
  109.         OLED_WrCmd(0x14); //bit2,开启/关闭
  110.         OLED_WrCmd(0x20); //设置内存地址模式
  111.         OLED_WrCmd(0x02); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
  112.         OLED_WrCmd(0xA1); //段重定义设置,bit0:0,0->0;1,0->127;
  113.         OLED_WrCmd(0xC0); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
  114.         OLED_WrCmd(0xDA); //设置COM硬件引脚配置
  115.         OLED_WrCmd(0x12); //[5:4]配置
  116.                  
  117.         OLED_WrCmd(0x81); //对比度设置
  118.         OLED_WrCmd(0xEF); //1~255;默认0X7F (亮度设置,越大越亮)
  119.         OLED_WrCmd(0xD9); //设置预充电周期
  120.         OLED_WrCmd(0xf1); //[3:0],PHASE 1;[7:4],PHASE 2;
  121.         OLED_WrCmd(0xDB); //设置VCOMH 电压倍率
  122.         OLED_WrCmd(0x30); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

  123.         OLED_WrCmd(0xA4); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
  124.         OLED_WrCmd(0xA6); //设置显示方式;bit0:1,反相显示;0,正常显示                                                              
  125.         OLED_WrCmd(0xAF); //开启显示
  126.        
  127.         OLED_Clear();
  128. }

  129. u8 OLED_GRAM[128][8];         

  130. //更新显存到LCD                 
  131. void OLED_Refresh_Gram(void)
  132. {
  133.         u8 i,n;                    
  134.         for(i=0;i<8;i++)  
  135.         {  
  136.                 OLED_WrCmd (0xb0+i);    //设置页地址(0~7)
  137.                 OLED_WrCmd (0x00);      //设置显示位置—列低地址
  138.                 OLED_WrCmd (0x10);      //设置显示位置—列高地址   
  139.                 for(n=0;n<128;n++)
  140.                         OLED_WrDat(OLED_GRAM[n][i]);
  141.         }   
  142. }

  143. //画点
  144. //x:0~127
  145. //y:0~63
  146. //t:1 填充 0,清空                                  
  147. void OLED_DrawPoint(u8 x,u8 y,u8 t)
  148. {
  149.         u8 pos,bx,temp=0;
  150.         if(x>127||y>63)return;//超出范围了.
  151.         pos=7-y/8;
  152.         bx=y%8;
  153.         temp=1<<(7-bx);
  154.         if(t)
  155.                 OLED_GRAM[x][pos]|=temp;
  156.         else
  157.                 OLED_GRAM[x][pos]&=~temp;            
  158. }

  159. //在指定位置显示一个字符,包括部分字符
  160. //x:0~127
  161. //y:0~63
  162. //mode:0,反白显示;1,正常显示                                 
  163. //size:选择字体 16/12
  164. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode)
  165. {                                  
  166.         u8 temp,t,t1;
  167.         u8 y0=y;
  168.         u8 csize=(size/8+((size%8)?1:0))*(size/2);                //得到字体一个字符对应点阵集所占的字节数
  169.         chr=chr-' ';//得到偏移后的值                 
  170.     for(t=0;t<csize;t++)
  171.     {   
  172.                 if(size==12)temp=asc2_1206[chr][t];                  //调用1206字体
  173.                 else if(size==16)temp=asc2_1608[chr][t];        //调用1608字体
  174.                 else if(size==24)temp=asc2_2412[chr][t];        //调用2412字体
  175.                 else return;                                                                //没有的字库
  176.         for(t1=0;t1<8;t1++)
  177.                 {
  178.                         if(temp&0x80)
  179.                                 OLED_DrawPoint(x,y,mode);
  180.                         else OLED_DrawPoint(x,y,!mode);
  181.                         temp<<=1;
  182.                         y++;
  183.                         if((y-y0)==size)
  184.                         {
  185.                                 y=y0;
  186.                                 x++;
  187.                                 break;
  188.                         }
  189.                 }           
  190.     }         
  191. }

  192. //在指定位置显示一个汉字
  193. //x:0~127
  194. //y:0~63                         
  195. //chr:汉字的索引
  196. //mode:0,反白显示;1,正常显示       
  197. void OLED_ShowHz(u8 x,u8 y,u8 chr,u8 mode)
  198. {
  199.         u8 temp,t,t1;
  200.         u8 y0=y;
  201.         u8 csize=32;                //得到字体一个字符对应点阵集所占的字节数
  202.         chr=chr*2;//得到偏移后的值                 
  203.     for(t=0;t<csize;t++)
  204.     {   
  205.                 temp=Hz[chr][t];       
  206.         for(t1=0;t1<8;t1++)
  207.                 {
  208.                         if(temp&0x80)
  209.                                 OLED_DrawPoint(x,y,mode);
  210.                         else OLED_DrawPoint(x,y,!mode);
  211.                         temp<<=1;
  212.                         y++;
  213.                         if((y-y0)==16)
  214.                         {
  215.                                 y=y0;
  216.                                 x++;
  217.                                 break;
  218.                         }
  219.                 }           
  220.     }                  
  221. }

  222. //OLED字符串连续显示函数
  223. void OLED_Hz_String(u8 x,u8 y,u8 chr_S,u8 chr_E)
  224. {
  225.         unsigned char i;
  226.         for(i=chr_S;i<=chr_E;i++)
  227.         {
  228.                 OLED_ShowHz(x+16*(i-chr_S),y,i,1);        
  229.         }
  230. }

  231. //m^n函数
  232. u32 mypow(u8 m,u8 n)
  233. {
  234.         u32 result=1;         
  235.         while(n--)result*=m;   
  236.         return result;
  237. }                                  
  238. //显示2个数字
  239. //x,y :起点坐标         
  240. //len :数字的位数
  241. //size:字体大小
  242. //mode:模式        0,填充模式;1,叠加模式
  243. //num:数值(0~4294967295);                           
  244. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size)
  245. {                
  246.         u8 t,temp;
  247.         u8 enshow=0;                                                  
  248.         for(t=0;t<len;t++)
  249.         {
  250.                 temp=(num/mypow(10,len-t-1))%10;
  251.                 if(enshow==0&&t<(len-1))
  252.                 {
  253.                         if(temp==0)
  254.                         {
  255.                                 OLED_ShowChar(x+(size/2)*t,y,'0',size,1);
  256.                                 continue;
  257.                         }else enshow=1;
  258.                           
  259.                 }
  260.                  OLED_ShowChar(x+(size/2)*t,y,temp+'0',size,1);
  261.         }
  262. }
  263. //显示字符串
  264. //x,y:起点坐标  
  265. //size:字体大小
  266. //*p:字符串起始地址
  267. void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size,uint8_t mode)
  268. {       
  269.     while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
  270.     {      
  271.         if(x>(128-(size/2))){x=0;y+=size;}
  272.         if(y>(64-size)){y=x=0;OLED_Clear();}
  273.         OLED_ShowChar(x,y,*p,size,mode);         
  274.         x+=size/2;
  275.         p++;
  276.     }  
  277.        
  278. }


  279. //显示图形
  280. //得到字体一个字符对应点阵集所占的字节数
  281. //len--传入的数据的总长度
  282. void OLED_ShowBMP(u8 x,u8 y,u8 mode,u8 bmp[][16],u32 len)
  283. {
  284.         u16 t,t1;
  285.         u8 y0=y;
  286.         u8 temp;
  287.         u16 len2=len/16;                //数组的列数
  288.        
  289.         for(t=0;t<len;t++)
  290.         {   
  291.                 temp=bmp[0][t];       
  292.                 for(t1=0;t1<8;t1++)
  293.                 {
  294.                         if(temp&0x80)
  295.                                 OLED_DrawPoint(x,y,mode);
  296.                         else OLED_DrawPoint(x,y,!mode);
  297.                         temp<<=1;
  298.                         y++;
  299.                         if((y-y0) == len2)
  300.                         {
  301.                                 y = y0;
  302.                                 x ++;
  303.                                 break;
  304.                         }
  305.                 }           
  306.         }
  307. }

  308. //显示蛇的函数
  309. void OLED_Snake_Head_Dis(u8 x,u8 y,u8 mode)
  310. {
  311.         u8 i,j;
  312.         u8 x_draw,y_draw;
  313.         x_draw = ((x-1)*4)%128;                //限制长度
  314.         y_draw = ((y-1)*4)%64;                //限制宽度
  315.         for(i=0;i<4;i++)
  316.         {
  317.                 for(j=0;j<4;j++)
  318.                 {
  319.                         OLED_DrawPoint(x_draw+i,y_draw+j,mode);
  320.                 }
  321.         }
  322. }


复制代码



图形和文字生成的工具是:
PCtoLCD2002(OLED取字工具)
可以自行百度,很好找的

这里需要强调一下端口的配置,速度一定要配置成50MHz的,最开始配置成2MHz发现怎么都驱动不了
,如下图所示:
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10|GPIO_PIN_11);        



此帖出自GD32 MCU论坛


回复

使用道具 举报

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

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2019-6-26 22:56 , Processed in 0.076695 second(s), 15 queries , Gzip On, MemCache On.

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