12下一页
返回列表 发新帖我要提问本帖赏金: 30.00元(功能说明)

[单片机芯片] 移植1.3寸I2C的OLED屏STM32驱动到CH32V203

[复制链接]
4208|23
 楼主| lilijin1995 发表于 2023-1-5 11:21 | 显示全部楼层 |阅读模式
本帖最后由 lilijin1995 于 2023-1-5 14:22 编辑

今天给大家分享的是移植1.3寸I2C的OLED屏STM32驱动到CH32V203的过程。
一、硬件资料:
    1.  1.3寸OLED屏
       这里我们用的是中景园1.3寸OLED屏,原理图如下图,其中I2C地址是0x78,因为是默认DC接GND,R11是焊接的,另外我们可以看到这款屏幕用的是SSH1106驱动的,原理图可以打开附件。
4019763b6452c557a8.png
    2.  SH1106
       SH1106是一款单片CMOS OLED/PLED驱动器,带控制器,用于有机/聚合物发光二极管点阵图形显示系统。SH1106由132个分段、64个共用点组成,可支持132 x 64的最大显示分辨率。它是专为共阴极型OLED面板而设计的。SH1106内置对比度控制、显示RAM振荡器和高效Dc-Dc转换器,减少外部组件数量和功耗。SH1106适用于各种紧凑便携的应用,如手机的子显示器、计算器、MP3播放器等。规格书可以在附件中找到。   
      3. CH32V203评估板
       评估板是我们自己设计的,主要用于项目前期的评估测试,如下图:
9080663b65a6e40766.png
二、软件移植
官方提供的例程是有基于STM32、STM8和51的,我们选择STM32F103C8T6的,如附件OLED.zip
    1.首先是OLED_Init,代码如下:
  1. void OLED_Init(void) {

  2.     GPIO_InitTypeDef GPIO_InitStructure;

  3.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);         //使能A端口时钟
  4.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
  5.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出
  6.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                  //速度50MHz
  7.     GPIO_Init(GPIOA, &GPIO_InitStructure);          //初始化GPIOD3,6
  8.     GPIO_SetBits(GPIOA, GPIO_Pin_5 | GPIO_Pin_7);

  9.     Delay_Ms(800);
  10.     OLED_WR_Byte(0xAE, OLED_CMD);          //--display off
  11.     OLED_WR_Byte(0x02, OLED_CMD);          //---set low column address
  12.     OLED_WR_Byte(0x10, OLED_CMD);          //---set high column address
  13.     OLED_WR_Byte(0x40, OLED_CMD);          //--set start line address
  14.     OLED_WR_Byte(0xB0, OLED_CMD);          //--set page address
  15.     OLED_WR_Byte(0x81, OLED_CMD); // contract control
  16.     OLED_WR_Byte(0xFF, OLED_CMD); //--128
  17.     OLED_WR_Byte(0xA1, OLED_CMD); //set segment remap
  18.     OLED_WR_Byte(0xA6, OLED_CMD); //--normal / reverse
  19.     OLED_WR_Byte(0xA8, OLED_CMD); //--set multiplex ratio(1 to 64)
  20.     OLED_WR_Byte(0x3F, OLED_CMD); //--1/32 duty
  21.     OLED_WR_Byte(0xC8, OLED_CMD); //Com scan direction
  22.     OLED_WR_Byte(0xD3, OLED_CMD); //-set display offset
  23.     OLED_WR_Byte(0x00, OLED_CMD); //

  24.     OLED_WR_Byte(0xD5, OLED_CMD); //set osc division
  25.     OLED_WR_Byte(0x80, OLED_CMD); //

  26.     OLED_WR_Byte(0xD8, OLED_CMD); //set area color mode off
  27.     OLED_WR_Byte(0x05, OLED_CMD); //

  28.     OLED_WR_Byte(0xD9, OLED_CMD); //Set Pre-Charge Period
  29.     OLED_WR_Byte(0xF1, OLED_CMD); //

  30.     OLED_WR_Byte(0xDA, OLED_CMD); //set com pin configuartion
  31.     OLED_WR_Byte(0x12, OLED_CMD); //

  32.     OLED_WR_Byte(0xDB, OLED_CMD); //set Vcomh
  33.     OLED_WR_Byte(0x30, OLED_CMD); //

  34.     OLED_WR_Byte(0x8D, OLED_CMD); //set charge pump enable
  35.     OLED_WR_Byte(0x14, OLED_CMD); //

  36.     OLED_WR_Byte(0xAF, OLED_CMD); //--turn on oled panel
  37. }
可以发现,这是通过IO口模拟的方式去实现的I2C,如果是一般情况IO口模拟的话,基本配置为开漏输出模式,但由于这里是驱动OLED,只需要写,不需要读取,所以这里配置推挽输出。命令注释已经很详细了,如果需要学习的话,直接看附件的      SH1106的规格书。      
          2.清屏
  1. //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!         
  2. void OLED_Clear(void) {
  3.     u8 i, n;
  4.     for (i = 0; i < 8; i++) {
  5.         OLED_WR_Byte(0xb0 + i, OLED_CMD);    //设置页地址(0~7)
  6.         OLED_WR_Byte(0x02, OLED_CMD);      //设置显示位置—列低地址
  7.         OLED_WR_Byte(0x10, OLED_CMD);      //设置显示位置—列高地址
  8.         for (n = 0; n < 128; n++)
  9.             OLED_WR_Byte(0, OLED_DATA);
  10.     } //更新显示
  11. }
清屏就是往芯片里面写0。

          3.OLED_WR_Byte的实现
  1. /**********************************************
  2. // IIC Write Command
  3. **********************************************/
  4. void Write_IIC_Command(unsigned char IIC_Command) {
  5.     IIC_Start();
  6.     Write_IIC_Byte(0x78);            //Slave address,SA0=0
  7.     IIC_Wait_Ack();
  8.     Write_IIC_Byte(0x00);                        //write command
  9.     IIC_Wait_Ack();
  10.     Write_IIC_Byte(IIC_Command);
  11.     IIC_Wait_Ack();
  12.     IIC_Stop();
  13. }
  14. /**********************************************
  15. // IIC Write Data
  16. **********************************************/
  17. void Write_IIC_Data(unsigned char IIC_Data) {
  18.     IIC_Start();
  19.     Write_IIC_Byte(0x78);                        //D/C#=0; R/W#=0
  20.     IIC_Wait_Ack();
  21.     Write_IIC_Byte(0x40);                        //write data
  22.     IIC_Wait_Ack();
  23.     Write_IIC_Byte(IIC_Data);
  24.     IIC_Wait_Ack();
  25.     IIC_Stop();
  26. }
  27. void OLED_WR_Byte(unsigned dat, unsigned cmd) {
  28.     if (cmd) {

  29.         Write_IIC_Data(dat);

  30.     } else {
  31.         Write_IIC_Command(dat);

  32.     }

  33. }
上面是基本的写命令和数据的操作,是I2C的时序,I2C的时序图如下,
6446563b666d4e6941.png
时序的要求也如下:
722063b66700e41eb.png

由于STM32和CH32的库函数名字基本一样的,所以我们基本不用修改太多。

         4.OLED_ShowCHinese显示中文函数的实现
  1. void OLED_ShowCHinese(u8 x, u8 y, u8 no) {
  2.     u8 t, adder = 0;
  3.     OLED_Set_Pos(x, y);
  4.     for (t = 0; t < 16; t++) {
  5.         OLED_WR_Byte(Hzk[2 * no][t], OLED_DATA);
  6.         adder += 1;
  7.     }
  8.     OLED_Set_Pos(x, y + 1);
  9.     for (t = 0; t < 16; t++) {
  10.         OLED_WR_Byte(Hzk[2 * no + 1][t], OLED_DATA);
  11.         adder += 1;
  12.     }
  13. }
其中,x和y是屏幕的坐标,而no应该是中文字的索引,
Hzk是中文字库,char Hzk[][32]例程没有加const,我们自己减少,因为家里const就是占用Flash空间,否则是SRAM空间。这个字库是通过取模软件生产的。
取模软件可以用PCtoLCD2002,它可以生成图片和中文字库。如果有条件的话,现在市面上也有自带中文库的OLED屏,或者可以自己加字库芯片。               
        5.OLED_ShowString显示字符串函数的实现
  1. //显示一个字符号串
  2. void OLED_ShowString(u8 x, u8 y, u8 *chr, u8 Char_Size) {
  3.     unsigned char j = 0;
  4.     while (chr[j]!='\0')
  5.     {   OLED_ShowChar(x,y,chr[j],Char_Size);
  6.         x+=8;
  7.         if(x>120) {x=0;y+=2;}
  8.         j++;
  9.     }
  10. }
  11. //在指定位置显示一个字符,包括部分字符
  12. //x:0~127
  13. //y:0~63
  14. //mode:0,反白显示;1,正常显示                                 
  15. //size:选择字体 16/12
  16. void OLED_ShowChar(u8 x, u8 y, u8 chr, u8 Char_Size) {
  17.     unsigned char c = 0, i = 0;
  18.     c = chr - ' '; //得到偏移后的值
  19.     if (x > Max_Column - 1) {
  20.         x = 0;
  21.         y = y + 2;
  22.     }
  23.     if (Char_Size == 16) {
  24.         OLED_Set_Pos(x, y);
  25.         for (i = 0; i < 8; i++)
  26.             OLED_WR_Byte(F8X16[c * 16 + i], OLED_DATA);
  27.         OLED_Set_Pos(x, y + 1);
  28.         for (i = 0; i < 8; i++)
  29.             OLED_WR_Byte(F8X16[c * 16 + i + 8], OLED_DATA);
  30.     } else {
  31.         OLED_Set_Pos(x, y);
  32.         for (i = 0; i < 6; i++)
  33.             OLED_WR_Byte(F6x8[c][i], OLED_DATA);

  34.     }
  35. }
可以看到,这个函数提供了F8X16和F6x8两个不同点阵的ASCII码表,F6x8是6*8点阵的,F8X16是8*16点阵的,乘积越大,字符串字体越大。
        6.OLED_DrawBMP显示图片函数的实现
  1. void OLED_DrawBMP(unsigned char x0, unsigned char y0, unsigned char x1,
  2.         unsigned char y1, unsigned char BMP[]) {
  3.     unsigned int j = 0;
  4.     unsigned char x, y;

  5.     if (y1 % 8 == 0)
  6.         y = y1 / 8;
  7.     else
  8.         y = y1 / 8 + 1;
  9.     for (y = y0; y < y1; y++) {
  10.         OLED_Set_Pos(x0, y);
  11.         for (x = x0; x < x1; x++) {
  12.             OLED_WR_Byte(BMP[j++], OLED_DATA);
  13.         }
  14.     }
  15. }
图片我们的显示关键不是这个函数的实现,关键在于取模,图片库也是取模软件取的,例程是这样调用图片库显示的
OLED_DrawBMP(0,0,128,8,BMP1);其中unsigned char BMP1[] ,BMP1是普通变量,这将会占用非常多的SRAM,SRAM非常小,所以不建议这样,我们可以改一下,将其定义为只读的,const unsigned char BMP1[],调用时候强制转换一下:OLED_DrawBMP(0,0,128,8,(unsigned char *)BMP1);

最后在main函数中实现的中文、字符串、图片显示如下:
  1. int main(void) {
  2.     u8 t;
  3.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  4.     Delay_Init();
  5.     USART_Printf_Init(115200);
  6.     printf("SystemClk:%d\r\n", SystemCoreClock);
  7.     printf("This is printf example\r\n");

  8.     OLED_Init();            //初始化OLED
  9.     OLED_Clear();
  10.     t=' ';
  11.     OLED_ShowCHinese(0, 0, 0);             //中
  12.     OLED_ShowCHinese(18, 0, 1);            //景
  13.     OLED_ShowCHinese(36, 0, 2);            //园
  14.     OLED_ShowCHinese(54, 0, 3);            //电
  15.     OLED_ShowCHinese(72, 0, 4);            //子
  16.     OLED_ShowCHinese(90, 0, 5);            //科
  17.     OLED_ShowCHinese(108, 0, 6);            //技
  18.     while(1)
  19.     {
  20.         OLED_Clear();
  21.         OLED_ShowCHinese(0,0,0);            //中
  22.         OLED_ShowCHinese(18,0,1);           //景
  23.         OLED_ShowCHinese(36,0,2);           //园
  24.         OLED_ShowCHinese(54,0,3);           //电
  25.         OLED_ShowCHinese(72,0,4);           //子
  26.         OLED_ShowCHinese(90,0,5);           //科
  27.         OLED_ShowCHinese(108,0,6);          //技
  28.         OLED_ShowString(6,3,"1.30' OLED TEST",16);
  29.         //OLED_ShowString(8,2,"ZHONGJINGYUAN");
  30.         // OLED_ShowString(20,4,"2014/05/01");
  31.         OLED_ShowString(0,6,"ASCII:",16);
  32.         OLED_ShowString(63,6,"CODE:",16);
  33.         OLED_ShowChar(48,6,t,16);//显示ASCII字符
  34.         t++;
  35.         if(t>'~')t=' ';
  36.         OLED_ShowNum(103,6,t,3,16);//显示ASCII字符的码值
  37.         Delay_Ms(1000);
  38.         OLED_DrawBMP(0,0,128,8,(unsigned char *)BMP1);//图片显示(图片显示慎用,生成的字表较大,会占用较多空间,FLASH空间8K以下慎用)
  39.         Delay_Ms(1000);
  40.     }
  41. }
Delay_Ms是CH32中实现的,所以需要修改一下。


最终实现的效果图如下:
3127263b66c8d1826e.png
615963b66c9da55d5.png



中景园电子1.3OLED-4PIN显示屏IIC接口原理图.pdf

62.42 KB, 下载次数: 16

1.3寸竖屏横屏-控制芯片SH1106手册.pdf

1.47 MB, 下载次数: 14

OLED.zip

1.83 MB, 下载次数: 32

打赏榜单

21ic小管家 打赏了 30.00 元 2023-02-08
理由:签约作者奖励

geraldbetty 发表于 2023-1-9 11:22 | 显示全部楼层
这个使用宏定义很简单。              
biechedan 发表于 2023-1-9 11:30 | 显示全部楼层
这个彩色oled不好用的吗?              
jackcat 发表于 2023-1-9 12:00 | 显示全部楼层
CH32V203和stm32很兼容的。
qiufengsd 发表于 2023-1-9 13:30 | 显示全部楼层
可以使用硬件spi接口吗?              
mickit 发表于 2023-1-9 15:29 | 显示全部楼层
怎么实现汉字和英文 的混合显示?
gygp 发表于 2023-1-9 16:47 | 显示全部楼层
这个的驱动芯片是哪个?              
chenjun89 发表于 2023-1-9 19:14 来自手机 | 显示全部楼层
哈哈,中景元的OLED屏,我手上很多个。
pmp 发表于 2023-1-10 19:29 | 显示全部楼层
能不能把arduin的库移植过来。
macpherson 发表于 2023-2-4 12:25 | 显示全部楼层
oled的刷屏速度是多少?              
zerorobert 发表于 2023-2-4 15:11 | 显示全部楼层
ips屏幕的显示效果也非常不错的。
ulystronglll 发表于 2023-2-4 16:21 | 显示全部楼层
使用的硬件的iic吗?              
qiufengsd 发表于 2023-2-4 19:44 | 显示全部楼层
oled的iic的驱动速度是多少?
bestwell 发表于 2023-2-4 20:43 | 显示全部楼层
可以移植gui过来的吗?              
yeates333 发表于 2023-2-4 21:23 | 显示全部楼层
这个屏幕驱动还是比较简单的。              
wilhelmina2 发表于 2023-2-4 22:53 | 显示全部楼层
这个代码基本上就是兼容的。              
tpgf 发表于 2023-2-6 11:17 | 显示全部楼层
在时序上需要进行细微的调节吗
 楼主| lilijin1995 发表于 2023-2-6 11:40 | 显示全部楼层
tpgf 发表于 2023-2-6 11:17
在时序上需要进行细微的调节吗

在要求的范围内,我直接144主频上跑,没调
木木guainv 发表于 2023-2-6 11:58 | 显示全部楼层
请问控制这个屏幕使用的是at指令吗
磨砂 发表于 2023-2-6 12:06 | 显示全部楼层
感觉主要的部分都不需要改动 稍微变动一下配置就行了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

56

主题

165

帖子

8

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