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

今天给大家分享的是移植1.3寸I2C的OLED屏STM32驱动到CH32V203的过程。
一、硬件资料:
    1.  1.3寸OLED屏
       这里我们用的是中景园1.3寸OLED屏,原理图如下图,其中I2C地址是0x78,因为是默认DC接GND,R11是焊接的,另外我们可以看到这款屏幕用的是SSH1106驱动的,原理图可以打开附件。

2.  SH1106
       SH1106是一款单片CMOS OLED/PLED驱动器,带控制器,用于有机/聚合物发光二极管点阵图形显示系统。SH1106由132个分段、64个共用点组成,可支持132 x 64的最大显示分辨率。它是专为共阴极型OLED面板而设计的。SH1106内置对比度控制、显示RAM振荡器和高效Dc-Dc转换器,减少外部组件数量和功耗。SH1106适用于各种紧凑便携的应用,如手机的子显示器、计算器、MP3播放器等。规格书可以在附件中找到。   
      3. CH32V203评估板
       评估板是我们自己设计的,主要用于项目前期的评估测试,如下图:


二、软件移植
官方提供的例程是有基于STM32、STM8和51的,我们选择STM32F103C8T6的,如附件OLED.zip
    1.首先是OLED_Init,代码如下:

void OLED_Init(void) {



    GPIO_InitTypeDef GPIO_InitStructure;



    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);         //使能A端口时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                  //速度50MHz

    GPIO_Init(GPIOA, &GPIO_InitStructure);          //初始化GPIOD3,6

    GPIO_SetBits(GPIOA, GPIO_Pin_5 | GPIO_Pin_7);



    Delay_Ms(800);

    OLED_WR_Byte(0xAE, OLED_CMD);          //--display off

    OLED_WR_Byte(0x02, OLED_CMD);          //---set low column address

    OLED_WR_Byte(0x10, OLED_CMD);          //---set high column address

    OLED_WR_Byte(0x40, OLED_CMD);          //--set start line address

    OLED_WR_Byte(0xB0, OLED_CMD);          //--set page address

    OLED_WR_Byte(0x81, OLED_CMD); // contract control

    OLED_WR_Byte(0xFF, OLED_CMD); //--128

    OLED_WR_Byte(0xA1, OLED_CMD); //set segment remap

    OLED_WR_Byte(0xA6, OLED_CMD); //--normal / reverse

    OLED_WR_Byte(0xA8, OLED_CMD); //--set multiplex ratio(1 to 64)

    OLED_WR_Byte(0x3F, OLED_CMD); //--1/32 duty

    OLED_WR_Byte(0xC8, OLED_CMD); //Com scan direction

    OLED_WR_Byte(0xD3, OLED_CMD); //-set display offset

    OLED_WR_Byte(0x00, OLED_CMD); //



    OLED_WR_Byte(0xD5, OLED_CMD); //set osc division

    OLED_WR_Byte(0x80, OLED_CMD); //



    OLED_WR_Byte(0xD8, OLED_CMD); //set area color mode off

    OLED_WR_Byte(0x05, OLED_CMD); //



    OLED_WR_Byte(0xD9, OLED_CMD); //Set Pre-Charge Period

    OLED_WR_Byte(0xF1, OLED_CMD); //



    OLED_WR_Byte(0xDA, OLED_CMD); //set com pin configuartion

    OLED_WR_Byte(0x12, OLED_CMD); //



    OLED_WR_Byte(0xDB, OLED_CMD); //set Vcomh

    OLED_WR_Byte(0x30, OLED_CMD); //



    OLED_WR_Byte(0x8D, OLED_CMD); //set charge pump enable

    OLED_WR_Byte(0x14, OLED_CMD); //



    OLED_WR_Byte(0xAF, OLED_CMD); //--turn on oled panel

}

可以发现,这是通过IO口模拟的方式去实现的I2C,如果是一般情况IO口模拟的话,基本配置为开漏输出模式,但由于这里是驱动OLED,只需要写,不需要读取,所以这里配置推挽输出。命令注释已经很详细了,如果需要学习的话,直接看附件的      SH1106的规格书。      
          2.清屏

//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!          

void OLED_Clear(void) {

    u8 i, n;

    for (i = 0; i < 8; i++) {

        OLED_WR_Byte(0xb0 + i, OLED_CMD);    //设置页地址(0~7)

        OLED_WR_Byte(0x02, OLED_CMD);      //设置显示位置—列低地址

        OLED_WR_Byte(0x10, OLED_CMD);      //设置显示位置—列高地址

        for (n = 0; n < 128; n++)

            OLED_WR_Byte(0, OLED_DATA);

    } //更新显示

}

清屏就是往芯片里面写0。

          3.OLED_WR_Byte的实现

/**********************************************

 // IIC Write Command

 **********************************************/

void Write_IIC_Command(unsigned char IIC_Command) {

    IIC_Start();

    Write_IIC_Byte(0x78);            //Slave address,SA0=0

    IIC_Wait_Ack();

    Write_IIC_Byte(0x00);                        //write command

    IIC_Wait_Ack();

    Write_IIC_Byte(IIC_Command);

    IIC_Wait_Ack();

    IIC_Stop();

}

/**********************************************

 // IIC Write Data

 **********************************************/

void Write_IIC_Data(unsigned char IIC_Data) {

    IIC_Start();

    Write_IIC_Byte(0x78);                        //D/C#=0; R/W#=0

    IIC_Wait_Ack();

    Write_IIC_Byte(0x40);                        //write data

    IIC_Wait_Ack();

    Write_IIC_Byte(IIC_Data);

    IIC_Wait_Ack();

    IIC_Stop();

}

void OLED_WR_Byte(unsigned dat, unsigned cmd) {

    if (cmd) {



        Write_IIC_Data(dat);



    } else {

        Write_IIC_Command(dat);



    }



}

上面是基本的写命令和数据的操作,是I2C的时序,I2C的时序图如下,


时序的要求也如下:


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

         4.OLED_ShowCHinese显示中文函数的实现

void OLED_ShowCHinese(u8 x, u8 y, u8 no) {

    u8 t, adder = 0;

    OLED_Set_Pos(x, y);

    for (t = 0; t < 16; t++) {

        OLED_WR_Byte(Hzk[2 * no][t], OLED_DATA);

        adder += 1;

    }

    OLED_Set_Pos(x, y + 1);

    for (t = 0; t < 16; t++) {

        OLED_WR_Byte(Hzk[2 * no + 1][t], OLED_DATA);

        adder += 1;

    }

}

其中,x和y是屏幕的坐标,而no应该是中文字的索引,Hzk是中文字库,char Hzk[][32]例程没有加const,我们自己减少,因为家里const就是占用Flash空间,否则是SRAM空间。这个字库是通过取模软件生产的。
取模软件可以用PCtoLCD2002,它可以生成图片和中文字库。如果有条件的话,现在市面上也有自带中文库的OLED屏,或者可以自己加字库芯片。               
        5.OLED_ShowString显示字符串函数的实现

//显示一个字符号串

void OLED_ShowString(u8 x, u8 y, u8 *chr, u8 Char_Size) {

    unsigned char j = 0;

    while (chr[j]!='\0')

    {   OLED_ShowChar(x,y,chr[j],Char_Size);

        x+=8;

        if(x>120) {x=0;y+=2;}

        j++;

    }

}

//在指定位置显示一个字符,包括部分字符

//x:0~127

//y:0~63

//mode:0,反白显示;1,正常显示                                 

//size:选择字体 16/12 

void OLED_ShowChar(u8 x, u8 y, u8 chr, u8 Char_Size) {

    unsigned char c = 0, i = 0;

    c = chr - ' '; //得到偏移后的值

    if (x > Max_Column - 1) {

        x = 0;

        y = y + 2;

    }

    if (Char_Size == 16) {

        OLED_Set_Pos(x, y);

        for (i = 0; i < 8; i++)

            OLED_WR_Byte(F8X16[c * 16 + i], OLED_DATA);

        OLED_Set_Pos(x, y + 1);

        for (i = 0; i < 8; i++)

            OLED_WR_Byte(F8X16[c * 16 + i + 8], OLED_DATA);

    } else {

        OLED_Set_Pos(x, y);

        for (i = 0; i < 6; i++)

            OLED_WR_Byte(F6x8[c][i], OLED_DATA);



    }

}

可以看到,这个函数提供了F8X16和F6x8两个不同点阵的ASCII码表,F6x8是6*8点阵的,F8X16是8*16点阵的,乘积越大,字符串字体越大。
        6.OLED_DrawBMP显示图片函数的实现

void OLED_DrawBMP(unsigned char x0, unsigned char y0, unsigned char x1,

        unsigned char y1, unsigned char BMP[]) {

    unsigned int j = 0;

    unsigned char x, y;



    if (y1 % 8 == 0)

        y = y1 / 8;

    else

        y = y1 / 8 + 1;

    for (y = y0; y < y1; y++) {

        OLED_Set_Pos(x0, y);

        for (x = x0; x < x1; x++) {

            OLED_WR_Byte(BMP[j++], OLED_DATA);

        }

    }

}

图片我们的显示关键不是这个函数的实现,关键在于取模,图片库也是取模软件取的,例程是这样调用图片库显示的
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函数中实现的中文、字符串、图片显示如下:

int main(void) {

    u8 t;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    Delay_Init();

    USART_Printf_Init(115200);

    printf("SystemClk:%d\r\n", SystemCoreClock);

    printf("This is printf example\r\n");



    OLED_Init();            //初始化OLED

    OLED_Clear();

    t=' ';

    OLED_ShowCHinese(0, 0, 0);             //中

    OLED_ShowCHinese(18, 0, 1);            //景

    OLED_ShowCHinese(36, 0, 2);            //园

    OLED_ShowCHinese(54, 0, 3);            //电

    OLED_ShowCHinese(72, 0, 4);            //子

    OLED_ShowCHinese(90, 0, 5);            //科

    OLED_ShowCHinese(108, 0, 6);            //技

    while(1)

    {

        OLED_Clear();

        OLED_ShowCHinese(0,0,0);            //中

        OLED_ShowCHinese(18,0,1);           //景

        OLED_ShowCHinese(36,0,2);           //园

        OLED_ShowCHinese(54,0,3);           //电

        OLED_ShowCHinese(72,0,4);           //子

        OLED_ShowCHinese(90,0,5);           //科

        OLED_ShowCHinese(108,0,6);          //技

        OLED_ShowString(6,3,"1.30' OLED TEST",16);

        //OLED_ShowString(8,2,"ZHONGJINGYUAN");

        // OLED_ShowString(20,4,"2014/05/01");

        OLED_ShowString(0,6,"ASCII:",16);

        OLED_ShowString(63,6,"CODE:",16);

        OLED_ShowChar(48,6,t,16);//显示ASCII字符

        t++;

        if(t>'~')t=' ';

        OLED_ShowNum(103,6,t,3,16);//显示ASCII字符的码值

        Delay_Ms(1000);

        OLED_DrawBMP(0,0,128,8,(unsigned char *)BMP1);//图片显示(图片显示慎用,生成的字表较大,会占用较多空间,FLASH空间8K以下慎用)

        Delay_Ms(1000);

    }

}

Delay_Ms是CH32中实现的,所以需要修改一下。


最终实现的效果图如下:


---------------------
作者:lilijin1995
链接:https://bbs.21ic.com/icview-3276574-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值