[MM32软件] 【MM32 eMiniBoard测评报告】续调OLED驱动

[复制链接]
 楼主| yinwuqing110 发表于 2020-5-5 15:04 | 显示全部楼层 |阅读模式
本帖最后由 yinwuqing110 于 2020-5-5 15:10 编辑

    今天是五一假的最后一天了,明天又开始准备忙碌的工作了。今天来分享一下使用GPIO来模拟IIC通讯,尝试驱动一块0.96吋oled模块。想必大伙对这种oled屏都比较熟悉,这类屏成本低,有黑白与彩色版,有IIC接口与SPI接口版,我选择的是彩色IIC接口版,不知道是模拟的时序有问题,还是GPIO口存在复用功能的原因,移植好的驱动程序驱动不了该模块,确认该屏硬件没问题。
    OLED显示屏的正面与背面如下图所示:
oled正面.jpg
oled背面.jpg
     部分代码如下:
  1. /*
  2.      延时1us
  3. */
  4. void delay(unsigned char num)
  5. {
  6.      uint8_t i = 10;
  7.      while (num--)
  8.      {
  9.          while (i--);
  10.       }
  11. }

  12. /*
  13.      延时1ms
  14. */
  15. void delay_ms(unsigned int ms)
  16. {
  17.       unsigned int x, y;
  18.       for (x = ms; x > 0; x--)
  19.       {
  20.         for (y = 12000; y > 0; y--);
  21.        }
  22. }
  23. /**********************************************
  24. //IIC Start
  25. **********************************************/
  26. void IIC_Start()
  27. {
  28.     OLED_SCLK_Set();   
  29.     OLED_SDIN_Set();   
  30.     delay(1);   
  31.     OLED_SDIN_Clr();   
  32.     delay(1);   
  33.     OLED_SCLK_Clr();   
  34.     delay(1);   
  35. }

  36. /**********************************************
  37. //IIC Stop
  38. **********************************************/
  39. void IIC_Stop()
  40. {
  41.     OLED_SCLK_Set();
  42.     OLED_SDIN_Clr();
  43.     OLED_SDIN_Set();
  44. }
  45. /**********************************************
  46. //IIC Ack
  47. **********************************************/
  48. void IIC_Wait_Ack()
  49. {
  50.     OLED_SCLK_Set();
  51.     OLED_SCLK_Clr();
  52. }
  53. /**********************************************
  54. // IIC Write byte
  55. **********************************************/
  56. void Write_IIC_Byte(unsigned char IIC_Byte)
  57. {
  58.     unsigned char i;
  59.     unsigned char m,da;
  60.                
  61.     da=IIC_Byte;
  62.     OLED_SCLK_Clr();
  63.    for(i=0;i<8;i++)               
  64.    {
  65.       m=da;
  66.       m=m&0x80;
  67.       if(m==0x80)
  68.       {
  69.          OLED_SDIN_Set();
  70.        }
  71.      else
  72.        {
  73.          OLED_SDIN_Clr();
  74.         }
  75.          da=da<<1;
  76.          OLED_SCLK_Set();
  77.          OLED_SCLK_Clr();
  78.       }
  79. }
  80. /**********************************************
  81. IIC Write Command
  82. **********************************************/
  83. void Write_IIC_Command(unsigned char IIC_Command)
  84. {
  85.      IIC_Start();
  86.      Write_IIC_Byte(IIC_Address);      //Slave address,SA0=0
  87.      IIC_Wait_Ack();        
  88.      Write_IIC_Byte(0x00);                                                        //write command
  89.      IIC_Wait_Ack();        
  90.      Write_IIC_Byte(IIC_Command);
  91.      IIC_Wait_Ack();        
  92.      IIC_Stop();
  93. }
  94. void OLED_WR_Byte(unsigned dat,unsigned cmd)
  95. {
  96.      if(cmd)
  97.      {
  98.        Write_IIC_Data(dat);
  99.      }
  100.     else
  101.      {
  102.        Write_IIC_Command(dat);
  103.       }
  104.   }
  105. /********************************************
  106. //开启OLED显示
  107. ********************************************/
  108. void OLED_Display_On(void)
  109. {
  110.      OLED_WR_Byte(0X8D,OLED_CMD);                                          //SET DCDC命令
  111.      OLED_WR_Byte(0X14,OLED_CMD);                                          //DCDC ON
  112.      OLED_WR_Byte(0XAF,OLED_CMD);                                          //DISPLAY ON
  113. }
  114. /********************************************
  115. //关闭OLED显示     
  116. ********************************************/
  117. void OLED_Display_Off(void)
  118. {
  119.     OLED_WR_Byte(0X8D,OLED_CMD);                                  //SET DCDC命令
  120.     OLED_WR_Byte(0X10,OLED_CMD);                                  //DCDC OFF
  121.     OLED_WR_Byte(0XAE,OLED_CMD);                                  //DISPLAY OFF
  122. }        
  1. void OLED_On(void)  
  2. {  
  3.      uint8_t i,n;        
  4.      for(i=0;i<8;i++)  
  5.      {  
  6.         OLED_WR_Byte(0xb0+i,OLED_CMD);            //设置页地址(0~7)
  7.         OLED_WR_Byte(0x00,OLED_CMD);              //设置显示位置—列低地址
  8.         OLED_WR_Byte(0x10,OLED_CMD);              //设置显示位置—列高地址   
  9.         for(n=0;n<128;n++)
  10.         {
  11.           OLED_WR_Byte(1,OLED_DATA);                         //更新显示
  12.         }
  13.       }               
  14. }
  15. void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size2)
  16. {                 
  17.     uint8_t t,temp;
  18.     uint8_t enshow=0;                                                   
  19.     for(t=0;t<len;t++)
  20.     {
  21.       temp=(num/oled_pow(10,len-t-1))%10;
  22.       if(enshow==0&&t<(len-1))
  23.       {
  24.         if(temp==0)
  25.         {
  26.          OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
  27.          continue;
  28.          }
  29.         else
  30.         {
  31.           enshow=1;
  32.          }
  33.        }
  34.      OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
  35.     }
  36.   }
  37. //显示一个字符号串
  38. void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t Char_Size)
  39. {
  40.     unsigned char j=0;
  41.     while (chr[j]!='\0')
  42.     {               
  43.        OLED_ShowChar(x,y,chr[j],Char_Size);
  44.        x+=8;
  45.       if(x>120)
  46.       {
  47.         x=0;
  48.         y+=2;
  49.        }
  50.        j++;
  51.      }
  52.    }
  53. void OLED_DrawBattery(char level)
  54. {
  55.       switch(level)
  56.       {
  57.         case 0:
  58.         OLED_DrawBMP(104,0,128,1,Battery_0);
  59.         break;
  60.         case 1:
  61.         OLED_DrawBMP(104,0,128,1,Battery_25);
  62.         break;
  63.         case 2:
  64.         OLED_DrawBMP(104,0,128,1,Battery_50);
  65.         break;
  66.         case 3:
  67.         OLED_DrawBMP(104,0,128,1,Battery_75);
  68.         break;
  69.         case 4:
  70.         OLED_DrawBMP(104,0,128,1,Battery_100);
  71.         break;
  72.         }
  73.      }
  74. /*
  75.     [url=home.php?mod=space&uid=247401]@brief[/url]          初始化OLED与单片机的IO接口
  76. */
  77. static void OLED_GPIO_Init(void)
  78. {
  79.         GPIO_InitTypeDef  GPIO_InitStructure;
  80.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC,ENABLE);

  81.         GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_15|GPIO_Pin_14;
  82.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  83.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  84.         GPIO_Init(GPIOC, &GPIO_InitStructure);
  85.         OLED_SCLK_Set();    //设置PC14(SCL)为高电平
  86.         OLED_SDIN_Set();    //设置PC15(SDA)为高电平
  87. }

  88. //初始化SSD1306                                            
  89. void OLED_Init(void)
  90. {
  91.        OLED_GPIO_Init();   //GPIO口初始化
  92.        delay_ms(200);  //延时,由于单片机上电初始化比OLED模块快,所以必须加上延迟,等待OLED上电复位完成
  93.        OLED_WR_Byte(0xAE, OLED_CMD);   //关闭显示
  94.        OLED_WR_Byte(0x00, OLED_CMD);   //设置地列地址
  95.        OLED_WR_Byte(0x10, OLED_CMD);   //设置高列地址
  96.        OLED_WR_Byte(0x40, OLED_CMD);   //设置起始行地址
  97.        OLED_WR_Byte(0xB0, OLED_CMD);   //设置页地址
  98.        OLED_WR_Byte(0x81, OLED_CMD);   // 对比度设置,可设置亮度
  99.        OLED_WR_Byte(0xFF, OLED_CMD);   //  265
  100.        OLED_WR_Byte(0xA1, OLED_CMD);   //设置段(SEG)的起始映射地址;column的127地址是SEG0的地址
  101.        OLED_WR_Byte(0xA6, OLED_CMD);   //正常显示;0xa7逆显示
  102.        OLED_WR_Byte(0xA8, OLED_CMD);   //设置驱动路数(16~64)
  103.        OLED_WR_Byte(0x3F, OLED_CMD);   //64duty
  104.        OLED_WR_Byte(0xC8, OLED_CMD);   //重映射模式,COM[N-1]~COM0扫描
  105.        OLED_WR_Byte(0xD3, OLED_CMD);   //设置显示偏移
  106.        OLED_WR_Byte(0x00, OLED_CMD);   //无偏移
  107.        OLED_WR_Byte(0xD5, OLED_CMD);   //设置震荡器分频
  108.        OLED_WR_Byte(0x80, OLED_CMD);   //使用默认值
  109.        OLED_WR_Byte(0xD9, OLED_CMD);   //设置Pre-Charge Period
  110.        OLED_WR_Byte(0xF1, OLED_CMD);   //使用官方推荐值
  111.        OLED_WR_Byte(0xDA, OLED_CMD);   //设置com pin configuartion
  112.        OLED_WR_Byte(0x12, OLED_CMD);   //使用默认值
  113.        OLED_WR_Byte(0xDB, OLED_CMD);   //设置Vcomh,可调节亮度(默认)
  114.        OLED_WR_Byte(0x40, OLED_CMD);   //使用官方推荐值
  115.        OLED_WR_Byte(0x8D, OLED_CMD);   //设置OLED电荷泵
  116.        OLED_WR_Byte(0x14, OLED_CMD);   //开启显示
  117.        OLED_WR_Byte(0xAF, OLED_CMD);   //开启OLED面板显示
  118.        OLED_Clear(CLEAR_ALL);        //清屏
  119.        OLED_Set_Pos(0, 0);  //设置数据写入的起始行、列
  120. }  
  121. void TEST_OLED(void)
  122. {               
  123.       OLED_ShowString(16, 2, (unsigned char *)"HELLO EEWORLD",NUM_SIZE);
  124.       OLED_DrawBattery(BATTERY_LEVEL_0);
  125.       delay_ms(300);                                       
  126.       OLED_DrawBattery(BATTERY_LEVEL_25);
  127.       delay_ms(300);                                       
  128.       OLED_DrawBattery(BATTERY_LEVEL_50);
  129.       delay_ms(300);                                       
  130.       OLED_DrawBattery(BATTERY_LEVEL_75);
  131.       delay_ms(300);
  132.       OLED_DrawBattery(BATTERY_LEVEL_100);
  133.       delay_ms(500);
  134. }
       此次工程包含流水灯与串口打印功能的实现,因此全编译的时候会报空间不足的错误,如果将调用OLED驱动程序部分注释掉,程序可以编译通过,后面在Keil中将IRAM1的Size由原来的0x2000改为0x4000,编译通过了还是未能驱动OLED屏。
空间不够.png
增大空间.png
       接线参考的电路原理图如下:
MM32 eMiniBoard MB-023原理图.png
       串口1是通过USB线直接转换出的,因此只需在Keil的软件中设置烧录后自动重启,打开串口工具就能正常打印了。
设置烧录后自动重启.png
串口打印.png
    工程对应的实物连线与LED灯的状态如下:
流水灯.gif
     部分代码附上:
  1. /********************************************************************************************************
  2. **函数信息 :UartInit_Loop(void)                     
  3. **功能描述 :初始化串口
  4. **输入参数 :无
  5. **输出参数 :无
  6. ********************************************************************************************************/
  7. void UartInit_Loop(void)
  8. {
  9.     //GPIO端口设置
  10.     GPIO_InitTypeDef GPIO_InitStructure;
  11.     UART_InitTypeDef UART_InitStructure;
  12.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);        //使能UART1
  13.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);  //开启GPIOA时钟

  14.     //UART 初始化设置
  15.     GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);
  16.     GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1);

  17.     UART_InitStructure.UART_BaudRate = 115200;//串口波特率
  18.     UART_InitStructure.UART_WordLength = UART_WordLength_8b;//字长为8位数据格式
  19.     UART_InitStructure.UART_StopBits = UART_StopBits_1;//一个停止位
  20.     UART_InitStructure.UART_Parity = UART_Parity_No;//无奇偶校验位
  21.     UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;//无硬件数据流控制
  22.     UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;        //收发模式
  23.    
  24.     UART_Init(UART1, &UART_InitStructure); //初始化串口1
  25.     UART_Cmd(UART1, ENABLE);                    //使能串口1
  26.    
  27.     //UART1_TX   GPIOA.9
  28.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  29.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  30.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
  31.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2
  32.    
  33.     //UART1_RX          GPIOA.10初始化
  34.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA3
  35.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  36.     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  
  37.    
  38.     printf("Welcome to https://www.21ic.com/\r\n");
  39. }

  40. /********************************************************************************************************
  41. **函数信息 :uart_send(UART_TypeDef* UARTx,char c)                    
  42. **功能描述 :串口发送字节
  43. **输入参数 :UART_TypeDef* UARTx ,选择UART1、UART2、UART3
  44. **输入参数 :char c ,串口发送的字节
  45. **输出参数 :无
  46. ********************************************************************************************************/
  47. void uart_send(UART_TypeDef* UARTx,char c)
  48. {
  49.    UART_SendData(UARTx,(uint16_t)c);  
  50.     while(1)
  51.     {
  52.       if(UART_GetITStatus(UARTx, UART_IT_TXIEN))
  53.       {
  54.        UART_ClearITPendingBit(UARTx, UART_IT_TXIEN);
  55.        break;
  56.       }
  57.     }
  58. }

  59. /********************************************************************************************************
  60. **函数信息 :unsigned char inbyte(UART_TypeDef* UARTx)               
  61. **功能描述 :串口接收函数
  62. **输入参数 :UART_TypeDef* UARTx ,选择UART1、UART2、UART3
  63. **输出参数 :unsigned char 串口接收返回的字节
  64. ********************************************************************************************************/
  65. unsigned char inbyte(UART_TypeDef* UARTx)
  66. {
  67.    unsigned char temp;
  68.    while(1)
  69.   {
  70.     if(UART_GetITStatus(UARTx, UART_IT_RXIEN))
  71.     {
  72.      UART_ClearITPendingBit(UARTx, UART_IT_RXIEN);  //清除接受中断位
  73.      break;
  74.     }
  75.   }
  76.     temp = (uint8_t)UART_ReceiveData(UARTx);
  77.     if(temp==0xd)//清除错误接收的数据
  78.     {
  79.        return 0;               
  80.     }
  81.     return temp;
  82. }
  83. /********************************************************************************************************
  84. **函数信息 :void Uart1RxTest(UART_TypeDef* UARTx)               
  85. **功能描述 :串口接收函数测试
  86. **输入参数 :UART_TypeDef* UARTx ,选择UART1、UART2、UART3
  87. **输出参数 :无
  88. ********************************************************************************************************/
  89. void Uart1RxTest(UART_TypeDef* UARTx)
  90. {
  91.     unsigned char temp;
  92.     temp = inbyte(UARTx);
  93.    if(temp!=0)
  94.    {
  95.      printf("您输入的数据为:%c\r\n",temp);        
  96.     }                        
  97. }
  1. #include "delay.h"
  2. #include "sys.h"
  3. #include "led.h"
  4. #include "uart_loop.h"
  5. #include "oled.h"

  6. #define TIME 280
  7. /********************************************************************************************************
  8. **函数信息 :int main (void)                          
  9. **功能描述 :开机后,ARMLED闪动
  10. **输入参数 :
  11. **输出参数 :
  12. ********************************************************************************************************/
  13. int main(void)
  14. {
  15.         //OLED_Init();
  16.     LED_Init();                                   //初始化与LED连接的硬件接口
  17.         //OLED_ShowString(0, 2, (unsigned char *)"Set Time:",NUM_SIZE);
  18.     while(1)              //无限循环
  19. {
  20.    //TEST_OLED();
  21.    UartInit_Loop();  //UART1的发送,可以通过串口软件打印:Welcome to https://www.21ic.com/
  22.    //uart_send(UART1,0x55);
  23.    //Uart1RxTest(UART1);//UART1的接收,在串口软件中输入字符,可以通过打印验证接收的数据是否正确
  24.    LED1_ON();
  25.    LED2_ON();
  26.    LED3_ON();
  27.    LED4_ON();
  28.    delay_ms(TIME);
  29.    LED1_OFF();
  30.    LED2_ON();
  31.    LED3_ON();
  32.    LED4_ON();
  33.    delay_ms(TIME);
  34.    LED1_OFF();
  35.    LED2_OFF();
  36.    LED3_ON();
  37.    LED4_ON();
  38.    delay_ms(TIME);
  39.    LED1_OFF();
  40.    LED2_OFF();
  41.    LED3_OFF();
  42.    LED4_ON();
  43.    delay_ms(TIME);
  44.    LED1_OFF();
  45.    LED2_OFF();
  46.    LED3_OFF();
  47.    LED4_OFF();
  48.    delay_ms(TIME);
  49.    LED1_OFF();
  50.    LED2_OFF();
  51.    LED3_OFF();
  52.    LED4_ON();
  53.    delay_ms(TIME);
  54.    LED1_OFF();
  55.    LED2_OFF();
  56.    LED3_ON();
  57.    LED4_ON();
  58.    delay_ms(TIME);
  59.    LED1_OFF();
  60.    LED2_ON();
  61.    LED3_ON();
  62.    LED4_ON();
  63.    delay_ms(TIME);
  64.    LED1_ON();
  65.    LED2_ON();
  66.    LED3_ON();
  67.    LED4_ON();
  68.   }
  69. }
  1. #define IIC_Address                                                0x78

  2. #define Max_Column                                                128
  3. #define Max_Row                                                     64
  4. #define        Brightness                                             0xFF

  5. /*--------------------引脚定义--------------------------*/
  6. #define         OLED_SCLK_Set()         GPIO_SetBits(GPIOC, GPIO_Pin_14)                   //PC14(SCL)输出高
  7. #define         OLED_SCLK_Clr()         GPIO_ResetBits(GPIOC,GPIO_Pin_14)                  //PC14(SCL)输出低
  8. #define         OLED_SDIN_Set()         GPIO_SetBits(GPIOC, GPIO_Pin_15)                    //PC15(SDA)输出高
  9. #define         OLED_SDIN_Clr()         GPIO_ResetBits(GPIOC, GPIO_Pin_15)                  //PC15(SDA)输出高
  10. #define         OLED_READ_SDIN()        GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_15)   //读取PC15(SDA)电平

  11. //-----------------OLED IIC端口定义----------------                                             
  12. #define OLED_SDA                                                        PC14                       //I2C数据
  13. #define OLED_SCL                                                        PC15                        //I2C时钟
  14. #define OLED_RES                                                        4                              //I2CRES
  15. #define OLED_EN                                                          5                              //I2CEN

  16. #define OLED_CMD                                                        0                              //写命令
  17. #define OLED_DATA                                                       1                              //写数据

  18. //-----------------OLED 横向位置定义----------------                                             
  19. #define LINE_HIGHT                                                       0                             //第一行
  20. #define LINE_MIDDLE                                                     3                             //第二行
  21. #define LINE_LOW                                                          6                             //第三行

  22. //-----------------OLED 电池电量定义----------------  
  23. #define BATTERY_LEVEL_0                          0                                        //空电量
  24. #define BATTERY_LEVEL_25                        1                                        //25%电量
  25. #define BATTERY_LEVEL_50                        2                                        //50%电量
  26. #define BATTERY_LEVEL_75                        3                                        //75%电量
  27. #define BATTERY_LEVEL_100                      4                                        //100%电量

  28. //-----------------OLED 字号大小定义----------------
  29. #define NUM_SIZE                                                        16  //普通数字和汉字的大小
  30. #define SET_SIZE                                                         24  //设置界面的字体大小

  31. typedef enum
  32. {
  33.     CLEAR_ALL,                                                                                                    //全部清屏
  34.     CLEAR_HIGTH,                                                                                                //清除顶部行
  35.     CLEAR_MIDDLE,                                                                                              //清除中间行
  36.     CLEAR_LOW,                                                                                                   //清除底部行
  37.     CLEAR_PASSWORD                                                                                          //清除密码行
  38. }clear_mode_t;
    有心的坛友们可以谈谈您的见解,代码中有没有不妥的地方,有的话烦请回帖指明,谢谢啦,此次分享就到这里啦,后会有期。
nawu 发表于 2020-6-1 16:37 | 显示全部楼层
非常感谢楼主分享
qcliu 发表于 2020-6-1 16:38 | 显示全部楼层
调试的时候需要注意什么呢
tfqi 发表于 2020-6-1 16:38 | 显示全部楼层
小视频很漂亮
wiba 发表于 2020-6-1 16:38 | 显示全部楼层
楼主辛苦了
zljiu 发表于 2020-6-1 16:39 | 显示全部楼层
好羡慕楼主呀
您需要登录后才可以回帖 登录 | 注册

本版积分规则

106

主题

1098

帖子

7

粉丝
快速回复 在线客服 返回列表 返回顶部

106

主题

1098

帖子

7

粉丝
快速回复 在线客服 返回列表 返回顶部