【沁恒微CH32V307评估板试用体验】SSD1306之HELLOWORLD - RISC-V MCU技术社区 - 电子技术william hill官网 - 广受欢迎的专业电子william hill官网 - 威廉希尔官方网站
分享 收藏 返回

[文章]

【沁恒微CH32V307评估板试用体验】SSD1306之HELLOWORLD

【前言】SSD1306是常用的显示屏,驱动好后就可以直接用显示屏显示状态。相比串口可能更方便。下面向大家介绍如何驱动这块屏:1、IO的分配:查看例程I2C1的SCK为PB8,SDA为PB9。
2、初始化I2C1:
  1. /*********************************************************************
  2. * @fn      IIC_Init
  3. *
  4. * [url=home.php?mod=space&uid=2666770]@Brief[/url]   Initializes the IIC peripheral.
  5. *
  6. * [url=home.php?mod=space&uid=1141835]@Return[/url]  none
  7. */
  8. void IIC_Init(u32 bound, u16 address)
  9. {
  10.     GPIO_InitTypeDef GPIO_InitStructure = {0};
  11.     I2C_InitTypeDef  I2C_InitTSturcture = {0};

  12.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
  13.     GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);
  14.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

  15.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  16.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  17.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  18.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  19.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  20.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  21.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  22.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  23.     I2C_InitTSturcture.I2C_ClockSpeed = bound;
  24.     I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;
  25.     I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_16_9;
  26.     I2C_InitTSturcture.I2C_OwnAddress1 = address;
  27.     I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;
  28.     I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  29.     I2C_Init(I2C1, &I2C_InitTSturcture);

  30.     I2C_Cmd(I2C1, ENABLE);

  31. #if(I2C_MODE == HOST_MODE)
  32.     I2C_AcknowledgeConfig(I2C1, ENABLE);

  33. #endif
  34. }
(备注:CH32V307最高支持400K的频率)

3、重要的3个SSD1306的函数:
  • ssd1306写命令函数:
  1. void ssd1306_write_cmd(uint8_t data)
  2. {
  3.     while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET)
  4.             ;

  5.         I2C_GenerateSTART(I2C1, ENABLE);

  6.         while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
  7.             ;
  8.         I2C_Send7bitAddress(I2C1, SSD1306_ADDRESS, I2C_Direction_Transmitter);

  9.         while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  10.             ;
  11.         if(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) != RESET)
  12.                 {
  13.                     I2C_SendData(I2C1, 0x00);
  14.                 }
  15.         if(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) != RESET)
  16.                         {
  17.                             I2C_SendData(I2C1, data);
  18.                         }
  19.         while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  20.                 ;
  21.         I2C_GenerateSTOP(I2C1, ENABLE);
  22. }
  • SSD1306发送数据函数:其实两个函数就是发送的第个字节不同 发送命令高位为0,数据为1,初始使用的可以去看看I2C通信时序图。
  1. void ssd1306_write_date(uint8_t data)
  2. {
  3.     while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET)
  4.             ;

  5.         I2C_GenerateSTART(I2C1, ENABLE);

  6.         while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
  7.             ;
  8.         I2C_Send7bitAddress(I2C1, SSD1306_ADDRESS, I2C_Direction_Transmitter);

  9.         while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  10.             ;
  11.         if(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) != RESET)
  12.                 {
  13.                     I2C_SendData(I2C1, 0x40);
  14.                 }
  15.         if(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) != RESET)
  16.                         {
  17.                             I2C_SendData(I2C1, data);
  18.                         }
  19.         while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  20.                 ;
  21.         I2C_GenerateSTOP(I2C1, ENABLE);
  22. }
  • SSD1306初始化:
  1. //OLED初始化
  2. void oled_init(void)
  3. {
  4.   IIC_Init(400000,0x02);
  5.   Delay_Ms(600);
  6.   //ssd1306复位之后,默认是页寻址方式
  7.   ssd1306_write_cmd(0xAE);  //display off

  8.   ssd1306_write_cmd(0x00);  //set low column address
  9.   ssd1306_write_cmd(0x10);  //set high column address
  10.   ssd1306_write_cmd(0x40);  //set start line address

  11.   ssd1306_write_cmd(0xB0);  //set page address

  12.   ssd1306_write_cmd(0x81);  //contract control
  13.   ssd1306_write_cmd(0xFF);  //--128
  14.   ssd1306_write_cmd(0xA1);  // set segment re-map 0 to 127
  15.   ssd1306_write_cmd(0xA6);  //set normal display
  16.   ssd1306_write_cmd(0xA8);  //set multiplex ratio(1 to 64)
  17.   ssd1306_write_cmd(0x3F);  // 1/32 duty

  18.   ssd1306_write_cmd(0xC8);  // Com scan direction
  19.   ssd1306_write_cmd(0xD3);  //set display offset
  20.   ssd1306_write_cmd(0x00);  //no offset

  21.   ssd1306_write_cmd(0xD5);  //set display clock divide ratio/oscillator frequency
  22.   ssd1306_write_cmd(0x80);

  23.   ssd1306_write_cmd(0xD8); //set area color mode off
  24.   ssd1306_write_cmd(0x05);

  25.   ssd1306_write_cmd(0xD9);  //set pre-charge period
  26.   ssd1306_write_cmd(0xF1);

  27.   ssd1306_write_cmd(0xDA);  //set com pin hardware configuartion
  28.   ssd1306_write_cmd(0x12);

  29.   ssd1306_write_cmd(0xDB); //set Vcomh
  30.   ssd1306_write_cmd(0x30); //0x020 ,0.77xVcc

  31.   ssd1306_write_cmd(0x8D); //set charge pump enable
  32.   ssd1306_write_cmd(0x14); //

  33.   ssd1306_write_cmd(0xAF); //turn on Oled panel

  34. }
4、到这里ssd1306的初始配置就完成了,下面是设置点、打印字符等的函数:
  1. //坐标设置:也就是在哪里显示
  2. void oled_set_pos(uint8_t x, uint8_t y)
  3. {
  4.   //以下3个寄存器只在页录址的模式下有效
  5.   ssd1306_write_cmd(0xb0 + y);               //页地址设置 0xb0-0xb7
  6.   ssd1306_write_cmd(((x&0xf0)>>4)|0x10);   //列高地址设置
  7.   ssd1306_write_cmd((x&0x0f)|0x01);             //列低位地址设置
  8. }

  9. void OLED_Fill(unsigned char fill_Data)//全屏填充
  10. {
  11.     unsigned char m,n;
  12.     for(m=0;m<8;m++)
  13.     {
  14.         ssd1306_write_cmd(0xb0+m);      //page0-page1
  15.         ssd1306_write_cmd(0x00);        //low column start address 列地址的低4位
  16.         ssd1306_write_cmd(0x10);        //high column start address 列地址的高4位
  17.         for(n=0;n<128;n++)
  18.             {
  19.                 ssd1306_write_date(fill_Data);
  20.             }
  21.     }
  22. }

  23. //开启oled显示
  24. void oled_display_on(void)
  25. {
  26.   ssd1306_write_cmd(0x8D);   //SET DCDC命令
  27.   ssd1306_write_cmd(0x14);   //DCDC ON
  28.   ssd1306_write_cmd(0xAF);   // DISPLAY ON
  29. }

  30. //关闭oled显示
  31. void oled_display_off(void)
  32. {
  33.   ssd1306_write_cmd(0x8D);  //SET DCDC命令
  34.   ssd1306_write_cmd(0x10);  //DCDC OFF
  35.   ssd1306_write_cmd(0xAE);  //DISPLAY OFF
  36. }

  37. //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样
  38. void oled_clear(void)
  39. {
  40.   uint8_t i, n;
  41.   for(i=0;i<8;i++)
  42.   {
  43.     ssd1306_write_cmd(0xb0+i);   //设置页地址(0-7)
  44.     ssd1306_write_cmd(0x00);     //设置显示位置-列低地址
  45.     ssd1306_write_cmd(0x10);     //设置显示位置-列高地址
  46.     for(n=0;n<128;n++)
  47.     {
  48.       ssd1306_write_date(0);     //更新显示
  49.     }

  50.   }
  51. }

  52. //在指定位置显示一个字符,包括部分字符
  53. //x:0-127, y:0-7
  54. //Char_size:选择字体16/12
  55. void oled_show_char(uint8_t x, uint8_t y, uint8_t chr, uint16_t char_size)
  56. {
  57.   uint8_t c=0, i=0;

  58.   c = chr-32; //得到偏移后的值
  59.   if(x>MAX_COLUMN-1)
  60.   {
  61.     x=0;
  62.     y++;
  63.   }
  64.   if(char_size == 16)
  65.   {
  66.     oled_set_pos(x,y);
  67.     for(i=0;i<8;i++)
  68.     {
  69.       ssd1306_write_date(asc2_1608[c][i]);//先写上半部分
  70.     }
  71.     oled_set_pos(x,y+1);
  72.      for(i=0;i<8;i++)
  73.     {
  74.       ssd1306_write_date(asc2_1608[c][i+8]);//后写下半部分
  75.     }
  76.   }
  77. }

  78. //显示一个字符串
  79. void oled_show_string(uint8_t x, uint8_t y, char *str, uint8_t char_size)
  80. {
  81.   unsigned char j=0;
  82.   while(str[j]!='\0')
  83.   {
  84.     oled_show_char(x,y,str[j],char_size);
  85.     x+=8;
  86.     if(x>120)
  87.     {
  88.       x=0;
  89.       y+=2;
  90.     }
  91.     j++;//移动一次就是一个page,取值0-7
  92.   }
  93. }

  94. //--------------------------------------------------------------
  95. /*
  96. Prototype      : void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
  97. Calls          :
  98. Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7);
  99. ch[] -- 要显示的字符串;
  100. TextSize -- 字符大小(1:6*8 ; 2:8*16)
  101. Description    : 显示codetab.h中的ASCII字符,有6*8和8*16可选择
  102. //--------------------------------------------------------------
  103. */
  104. void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
  105. {
  106.     unsigned char c = 0,i = 0,j = 0;
  107.     switch(TextSize)
  108.     {
  109.         case 6:
  110.         {
  111.             while(ch[j] != '\0')
  112.             {
  113.                 c = ch[j] - 32;
  114.                 if(x > 126)
  115.                 {
  116.                     x = 0;
  117.                     y++;
  118.                 }
  119.                 oled_set_pos(x,y);
  120.                 for(i=0;i<6;i++)
  121.                     ssd1306_write_date(asc2_0806[c][i]);
  122.         x += 6;
  123.                 j++;
  124.             }
  125.         }break;
  126.     case 12:
  127.         {
  128.             while(ch[j] != '\0')
  129.             {
  130.                 c = ch[j] - 32;
  131.                 if(x > 126)
  132.                 {
  133.                     x = 0;
  134.                     y++;
  135.                 }
  136.                 oled_set_pos(x,y);
  137.                 for(i=0;i<6;i++)
  138.                     ssd1306_write_date(asc2_1206[c][i]);
  139.         oled_set_pos(x,y+1);
  140.                 for(i=0;i<6;i++)
  141.                     ssd1306_write_date(asc2_1206[c][i+6]);
  142.         x += 6;
  143.                 j++;

  144.             }
  145.         }break;
  146.         case 16:
  147.         {
  148.             while(ch[j] != '\0')
  149.             {
  150.                 c = ch[j] - 32;
  151.                 if(x > 120)
  152.                 {
  153.                     x = 0;
  154.                     y++;
  155.                 }
  156.                 oled_set_pos(x,y);
  157.                 for(i=0;i<8;i++)
  158.                     ssd1306_write_date(asc2_1608[c][i]);//先写上半部分
  159.                 oled_set_pos(x,y+1);
  160.                 for(i=0;i<8;i++)
  161.                     ssd1306_write_date(asc2_1608[c][i+8]);//后写下半部分
  162.                 x += 8;
  163.                 j++;
  164.             }
  165.         }break;
  166.     case 24:
  167.         {
  168.             while(ch[j] != '\0')
  169.             {
  170.                 c = ch[j] - 32;
  171.                 if(x > 120)
  172.                 {
  173.                     x = 0;
  174.                     y++;
  175.                 }
  176.                 oled_set_pos(x,y);
  177.                 for(i=0;i<12;i++)
  178.                     ssd1306_write_date(asc2_2412[c][i]);//先写上半部分
  179.                 oled_set_pos(x,y+1);
  180.                 for(i=0;i<12;i++)
  181.                     ssd1306_write_date(asc2_2412[c][i+12]);//后写下半部分
  182.         oled_set_pos(x,y+2);
  183.                 for(i=0;i<12;i++)
  184.                     ssd1306_write_date(asc2_2412[c][i+24]);//后写下半部分
  185.                 x += 12;
  186.                 j++;
  187.             }
  188.         }break;
  189.     }
  190. }
6、来个测试界面的函数:
  1. //显示测试
  2. void oled_display_test(void)
  3. {
  4.   oled_init();
  5.   oled_clear();
  6.   OLED_ShowStr(2,0,"CH32V307!",24);
  7.   OLED_ShowStr(28,3,"ELECFANS",16);
  8.   OLED_ShowStr(28,5,"HELLO WORLD!",12);
  9.   OLED_ShowStr(28,7,"TEST BY LUGL!",6);

  10. }
大功告成,总的来讲CH32V307的i2c驱动按照例程非常方便。下面是效果图:
ssd1306.jpg

更多回帖

×
发帖