查看: 1685|回复: 0
收起左侧

第六十九章:CH32V103应用教程——IIC-硬件IIC驱动OLED

[复制链接]

  离线 

  • TA的每日心情
    慵懒
    2021-7-23 17:16
  • 签到天数: 17 天

    [LV.4]

    发表于 2021-4-30 20:44:11 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 草帽王子 于 2021-9-10 18:00 编辑

    本章教程主要在第十四章硬件IIC读写EEPROM的基础上进行改动,使用硬件IIC驱动OLED屏。


    1、IIC简介及相关函数介绍

    关于IIC,在前面第十四章以及第三十七章已进行过介绍,在此不再赘述。


    2、硬件设计

    本章教程主要使用硬件IIC驱动OLED屏,所用OLED屏为0.96寸OLED屏。程序中使用IIC1驱动OLED屏,因此配置PB7作为SDA线,PB6作为SCL线,具体连接方式如下:
    • PB7连接OLED屏的SDA引脚
    • PB6连接OLED屏的SCL引脚


    3、软件设计

    关于硬件IIC的初始化配置以及各状态的配置,在前面第十四章已经介绍,在此不再赘述。本章教程主要对OLED相关配置文件进行介绍,其与模拟IIC驱动OLED相比,程序变化不大,具体如下:
    oled.h文件
    1. #ifndef __OLED_H
    2. #define __OLED_H

    3. #include "ch32v10x.h"
    4. #include "ch32v10x_conf.h"

    5. #define OLED_CMD  0
    6. #define OLED_DATA 1

    7. void Write_IIC_Command(u8 IIC_Command);
    8. void Write_IIC_Data(u8 IIC_Data);
    9. void OLED_ClearPoint(u8 x,u8 y);
    10. void OLED_ColorTurn(u8 i);
    11. void OLED_DisplayTurn(u8 i);
    12. void OLED_WR_Byte(u8 dat,u8 mode);
    13. void OLED_DisPlay_On(void);
    14. void OLED_DisPlay_Off(void);
    15. void OLED_Refresh(void);
    16. void OLED_Clear(void);
    17. void OLED_DrawPoint(u8 x,u8 y,u8 t);
    18. void OLED_DrawLine(u8 x1,u8 y1,u8 x2,u8 y2,u8 mode);
    19. void OLED_DrawCircle(u8 x,u8 y,u8 r);
    20. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1,u8 mode);
    21. void OLED_ShowChar6x8(u8 x,u8 y,u8 chr,u8 mode);
    22. void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1,u8 mode);
    23. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1,u8 mode);
    24. void OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1,u8 mode);
    25. void OLED_ScrollDisplay(u8 num,u8 space,u8 mode);
    26. void OLED_ShowPicture(u8 x,u8 y,u8 sizex,u8 sizey,u8 BMP[],u8 mode);
    27. void OLED_Init(void);

    28. #endif
    复制代码
    oled.h文件主要进行相关定义和函数声明;
    oled.c文件
    1. #include "oled.h"
    2. #include "oledfont.h"
    3. #include "iic.h"
    4. #include "debug.h"

    5. u8 OLED_GRAM[144][8];

    6. //反显函数
    7. void OLED_ColorTurn(u8 i)
    8. {
    9.     if(i==0)
    10.         {
    11.             OLED_WR_Byte(0xA6,OLED_CMD);//正常显示
    12.         }
    13.     if(i==1)
    14.         {
    15.             OLED_WR_Byte(0xA7,OLED_CMD);//反色显示
    16.         }
    17. }

    18. //屏幕旋转180度
    19. void OLED_DisplayTurn(u8 i)
    20. {
    21.     if(i==0)
    22.         {
    23.             OLED_WR_Byte(0xC8,OLED_CMD);//正常显示
    24.             OLED_WR_Byte(0xA1,OLED_CMD);
    25.         }
    26.     if(i==1)
    27.         {
    28.             OLED_WR_Byte(0xC0,OLED_CMD);//反转显示
    29.             OLED_WR_Byte(0xA0,OLED_CMD);
    30.         }
    31. }

    32. //发送一个字节
    33. //mode:数据/命令标志  0,表示命令;1,表示数据;
    34. void OLED_WR_Byte(u8 dat,u8 mode)
    35. {
    36.     if(mode)
    37.     {
    38.         Write_IIC_Byte(0x40,dat);
    39.     }
    40.     else
    41.     {
    42.         Write_IIC_Byte(0x00,dat);
    43.     }

    44. }

    45. //开启OLED显示
    46. void OLED_DisPlay_On(void)
    47. {
    48.     OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
    49.     OLED_WR_Byte(0x14,OLED_CMD);//开启电荷泵
    50.     OLED_WR_Byte(0xAF,OLED_CMD);//点亮屏幕
    51. }

    52. //关闭OLED显示
    53. void OLED_DisPlay_Off(void)
    54. {
    55.     OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
    56.     OLED_WR_Byte(0x10,OLED_CMD);//关闭电荷泵
    57.     OLED_WR_Byte(0xAE,OLED_CMD);//关闭屏幕
    58. }

    59. //更新显存到OLED
    60. void OLED_Refresh(void)
    61. {
    62.     u8 i,n;
    63.     for(i=0;i<8;i++)
    64.     {
    65.         OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
    66.         OLED_WR_Byte(0x00,OLED_CMD);   //设置低列起始地址
    67.         OLED_WR_Byte(0x10,OLED_CMD);   //设置高列起始地址

    68.         for(n=0;n<128;n++)
    69.         {
    70.             Write_IIC_Byte(0x40,OLED_GRAM[n][i]);
    71.         }
    72.     }
    73. }

    74. //清屏函数
    75. void OLED_Clear(void)
    76. {
    77.     u8 i,n;
    78.     for(i=0;i<8;i++)
    79.     {
    80.        for(n=0;n<128;n++)
    81.             {
    82.              OLED_GRAM[n][i]=0;//清除所有数据
    83.             }
    84.     }
    85.     OLED_Refresh();            //更新显示
    86. }

    87. //画点
    88. //x:0~127
    89. //y:0~63
    90. //t:1,填充 ;0,清空
    91. void OLED_DrawPoint(u8 x,u8 y,u8 t)
    92. {
    93.     u8 i,m,n;
    94.     i=y/8;
    95.     m=y%8;
    96.     n=1<<m;
    97.     if(t){OLED_GRAM[x][i]|=n;}
    98.     else
    99.     {
    100.         OLED_GRAM[x][i]=~OLED_GRAM[x][i];
    101.         OLED_GRAM[x][i]|=n;
    102.         OLED_GRAM[x][i]=~OLED_GRAM[x][i];
    103.     }
    104. }

    105. //画线
    106. //x1,y1:起点坐标
    107. //x2,y2:结束坐标
    108. void OLED_DrawLine(u8 x1,u8 y1,u8 x2,u8 y2,u8 mode)
    109. {
    110.     u16 t;
    111.     int xerr=0,yerr=0,delta_x,delta_y,distance;
    112.     int incx,incy,uRow,uCol;
    113.     delta_x=x2-x1; //计算坐标增量
    114.     delta_y=y2-y1;
    115.     uRow=x1;       //画线起点坐标
    116.     uCol=y1;
    117.     if(delta_x>0)incx=1; //设置单步方向
    118.     else if (delta_x==0)incx=0;//垂直线
    119.     else {incx=-1;delta_x=-delta_x;}
    120.     if(delta_y>0)incy=1;
    121.     else if (delta_y==0)incy=0;//水平线
    122.     else {incy=-1;delta_y=-delta_x;}
    123.     if(delta_x>delta_y)distance=delta_x; //选择基本增量坐标轴
    124.     else distance=delta_y;
    125.     for(t=0;t<distance+1;t++)
    126.     {
    127.         OLED_DrawPoint(uRow,uCol,mode);  //画点
    128.         xerr+=delta_x;
    129.         yerr+=delta_y;
    130.         if(xerr>distance)
    131.         {
    132.             xerr-=distance;
    133.             uRow+=incx;
    134.         }
    135.         if(yerr>distance)
    136.         {
    137.             yerr-=distance;
    138.             uCol+=incy;
    139.         }
    140.     }
    141. }
    142. //x,y:圆心坐标
    143. //r:圆的半径
    144. void OLED_DrawCircle(u8 x,u8 y,u8 r)
    145. {
    146.     int a, b,num;
    147.     a = 0;
    148.     b = r;
    149.     while(2 * b * b >= r * r)
    150.     {
    151.         OLED_DrawPoint(x + a, y - b,1);
    152.         OLED_DrawPoint(x - a, y - b,1);
    153.         OLED_DrawPoint(x - a, y + b,1);
    154.         OLED_DrawPoint(x + a, y + b,1);

    155.         OLED_DrawPoint(x + b, y + a,1);
    156.         OLED_DrawPoint(x + b, y - a,1);
    157.         OLED_DrawPoint(x - b, y - a,1);
    158.         OLED_DrawPoint(x - b, y + a,1);

    159.         a++;
    160.         num = (a * a + b * b) - r*r;   //计算画的点离圆心的距离
    161.         if(num > 0)
    162.         {
    163.             b--;
    164.             a--;
    165.         }
    166.     }
    167. }

    168. //在指定位置显示一个字符,包括部分字符
    169. //x:0~127
    170. //y:0~63
    171. //size1:选择字体 6x8/6x12/8x16/12x24
    172. //mode:0,反色显示;1,正常显示
    173. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1,u8 mode)
    174. {
    175.     u8 i,m,temp,size2,chr1;
    176.     u8 x0=x,y0=y;
    177.     if(size1==8)size2=6;
    178.     else size2=(size1/8+((size1%8)?1:0))*(size1/2);  //得到字体一个字符对应点阵集所占字节数
    179.     chr1=chr-' ';  //计算偏移后的值
    180.     for(i=0;i<size2;i++)
    181.     {
    182.         if(size1==8)
    183.         {temp=asc2_0806[chr1][i];} //调用0806字体
    184.         else if(size1==12)
    185.         {temp=asc2_1206[chr1][i];} //调用1206字体
    186.         else if(size1==16)
    187.         {temp=asc2_1608[chr1][i];} //调用1608字体
    188.         else if(size1==24)
    189.         {temp=asc2_2412[chr1][i];} //调用2412字体
    190.         else return;
    191.         for(m=0;m<8;m++)
    192.         {
    193.             if(temp&0x01)OLED_DrawPoint(x,y,mode);
    194.             else OLED_DrawPoint(x,y,!mode);
    195.             temp>>=1;
    196.             y++;
    197.         }
    198.         x++;
    199.         if((size1!=8)&&((x-x0)==size1/2))
    200.         {x=x0;y0=y0+8;}
    201.         y=y0;
    202.     }
    203. }

    204. //显示字符串
    205. //x,y:起点坐标
    206. //size1:字体大小
    207. //*chr:字符串起始地址
    208. //mode:0,反色显示;1,正常显示
    209. void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1,u8 mode)
    210. {
    211.     while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符
    212.     {
    213.         OLED_ShowChar(x,y,*chr,size1,mode);
    214.         if(size1==8)x+=6;
    215.         else x+=size1/2;
    216.         chr++;
    217.   }
    218. }

    219. //m^n
    220. u32 OLED_Pow(u8 m,u8 n)
    221. {
    222.     u32 result=1;
    223.     while(n--)
    224.     {
    225.       result*=m;
    226.     }
    227.     return result;
    228. }

    229. //显示数字
    230. //x,y :起点坐标
    231. //num :要显示的数字
    232. //len :数字的位数
    233. //size:字体大小
    234. //mode:0,反色显示;1,正常显示
    235. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1,u8 mode)
    236. {
    237.     u8 t,temp,m=0;
    238.     if(size1==8)m=2;
    239.     for(t=0;t<len;t++)
    240.     {
    241.         temp=(num/OLED_Pow(10,len-t-1))%10;
    242.             if(temp==0)
    243.             {
    244.                 OLED_ShowChar(x+(size1/2+m)*t,y,'0',size1,mode);
    245.             }
    246.             else
    247.             {
    248.               OLED_ShowChar(x+(size1/2+m)*t,y,temp+'0',size1,mode);
    249.             }
    250.     }
    251. }

    252. //显示汉字
    253. //x,y:起点坐标
    254. //num:汉字对应的序号
    255. //mode:0,反色显示;1,正常显示
    256. void OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1,u8 mode)
    257. {
    258.     u8 m,temp;
    259.     u8 x0=x,y0=y;
    260.     u16 i,size3=(size1/8+((size1%8)?1:0))*size1;  //得到字体一个字符对应点阵集所占字节数
    261.     for(i=0;i<size3;i++)
    262.     {
    263.         if(size1==16)
    264.                 {temp=Hzk1[num][i];}//调用16*16字体
    265.         else if(size1==24)
    266.                 {temp=Hzk2[num][i];}//调用24*24字体
    267.         else if(size1==32)
    268.                 {temp=Hzk3[num][i];}//调用32*32字体
    269.         else if(size1==64)
    270.                 {temp=Hzk4[num][i];}//调用64*64字体
    271.         else return;
    272.         for(m=0;m<8;m++)
    273.         {
    274.             if(temp&0x01)OLED_DrawPoint(x,y,mode);
    275.             else OLED_DrawPoint(x,y,!mode);
    276.             temp>>=1;
    277.             y++;
    278.         }
    279.         x++;
    280.         if((x-x0)==size1)
    281.         {x=x0;y0=y0+8;}
    282.         y=y0;
    283.     }
    284. }

    285. //num 显示汉字的个数
    286. //space 每一遍显示的间隔
    287. //mode:0,反色显示;1,正常显示
    288. void OLED_ScrollDisplay(u8 num,u8 space,u8 mode)
    289. {
    290.     u8 i,n,t=0,m=0,r;
    291.     while(1)
    292.     {
    293.         if(m==0)
    294.         {
    295.         OLED_ShowChinese(128,24,t,16,mode); //写入一个汉字保存在OLED_GRAM[][]数组中
    296.             t++;
    297.         }
    298.         if(t==num)
    299.         {
    300.                 for(r=0;r<16*space;r++)     //显示间隔
    301.                  {
    302.                     for(i=1;i<144;i++)
    303.                         {
    304.                             for(n=0;n<8;n++)
    305.                             {
    306.                                 OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
    307.                             }
    308.                         }
    309.            OLED_Refresh();
    310.                  }
    311.         t=0;
    312.         }
    313.         m++;
    314.         if(m==16){m=0;}
    315.         for(i=1;i<144;i++)                  //实现左移
    316.         {
    317.             for(n=0;n<8;n++)
    318.             {
    319.                 OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
    320.             }
    321.         }
    322.         OLED_Refresh();
    323.     }
    324. }

    325. //x,y:起点坐标
    326. //sizex,sizey,图片长宽
    327. //BMP[]:要写入的图片数组
    328. //mode:0,反色显示;1,正常显示
    329. void OLED_ShowPicture(u8 x,u8 y,u8 sizex,u8 sizey,u8 BMP[],u8 mode)
    330. {
    331.     u16 j=0;
    332.     u8 i,n,temp,m;
    333.     u8 x0=x,y0=y;
    334.     sizey=sizey/8+((sizey%8)?1:0);
    335.     for(n=0;n<sizey;n++)
    336.     {
    337.          for(i=0;i<sizex;i++)
    338.          {
    339.                 temp=BMP[j];
    340.                 j++;
    341.                 for(m=0;m<8;m++)
    342.                 {
    343.                     if(temp&0x01)OLED_DrawPoint(x,y,mode);
    344.                     else OLED_DrawPoint(x,y,!mode);
    345.                     temp>>=1;
    346.                     y++;
    347.                 }
    348.                 x++;
    349.                 if((x-x0)==sizex)
    350.                 {
    351.                     x=x0;
    352.                     y0=y0+8;
    353.                 }
    354.                 y=y0;
    355.      }
    356.      }
    357. }

    358. //OLED的初始化
    359. void OLED_Init(void)
    360. {
    361.     IIC_Init(800000,0x78);

    362.     Delay_Ms(200);              //初始化之前的延时很重要

    363.     OLED_WR_Byte(0xAE,OLED_CMD);//---turn off oled panel
    364.     OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
    365.     OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
    366.     OLED_WR_Byte(0x40,OLED_CMD);//---set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
    367.     OLED_WR_Byte(0x81,OLED_CMD);//---set contrast control register
    368.     OLED_WR_Byte(0xCF,OLED_CMD);//---Set SEG Output Current Brightness
    369.     OLED_WR_Byte(0xA1,OLED_CMD);//---Set SEG/Column Mapping       0xa0左右反置 0xa1正常
    370.     OLED_WR_Byte(0xC8,OLED_CMD);//---Set COM/Row Scan Direction   0xc0上下反置  0xc8正常
    371.     OLED_WR_Byte(0xA6,OLED_CMD);//---set normal display
    372.     OLED_WR_Byte(0xA8,OLED_CMD);//---set multiplex ratio(1 to 64)
    373.     OLED_WR_Byte(0x3f,OLED_CMD);//---1/64 duty
    374.     OLED_WR_Byte(0xD3,OLED_CMD);//---set display offset   Shift Mapping RAM Counter (0x00~0x3F)
    375.     OLED_WR_Byte(0x00,OLED_CMD);//---not offset
    376.     OLED_WR_Byte(0xd5,OLED_CMD);//---set display clock divide ratio/oscillator frequency
    377.     OLED_WR_Byte(0x80,OLED_CMD);//---set divide ratio, Set Clock as 100 Frames/Sec
    378.     OLED_WR_Byte(0xD9,OLED_CMD);//---set pre-charge period
    379.     OLED_WR_Byte(0xF1,OLED_CMD);//---Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
    380.     OLED_WR_Byte(0xDA,OLED_CMD);//---set com pins hardware configuration
    381.     OLED_WR_Byte(0x12,OLED_CMD);
    382.     OLED_WR_Byte(0xDB,OLED_CMD);//---set vcomh
    383.     OLED_WR_Byte(0x40,OLED_CMD);//---Set VCOM Deselect Level
    384.     OLED_WR_Byte(0x20,OLED_CMD);//---Set Page Addressing Mode (0x00/0x01/0x02)
    385.     OLED_WR_Byte(0x02,OLED_CMD);//
    386.     OLED_WR_Byte(0x8D,OLED_CMD);//---set Charge Pump enable/disable
    387.     OLED_WR_Byte(0x14,OLED_CMD);//---set(0x10) disable
    388.     OLED_WR_Byte(0xA4,OLED_CMD);//---Disable Entire Display On (0xa4/0xa5)
    389.     OLED_WR_Byte(0xA6,OLED_CMD);//---Disable Inverse Display On (0xa6/a7)
    390.     OLED_Clear();
    391.     OLED_WR_Byte(0xAF,OLED_CMD);
    392. }

    复制代码
    oled.c文件主要进行OLED显示相关函数的配置。关于函数的具体功能请查看程序中函数具体注释,在此不再一一介绍。
    main.c文件
    1. /********************************** (C) COPYRIGHT *******************************
    2. * File Name          : main.c
    3. * Author             : WCH
    4. * Version            : V1.0.0
    5. * Date               : 2020/04/30
    6. * Description        : Main program body.
    7. *******************************************************************************/

    8. /*
    9. *@Note
    10. 硬件IIC驱动OLED屏:
    11. PB7连接OLED屏的SDA引脚
    12. PB6连接OLED屏的SCL引脚

    13. */

    14. #include "debug.h"
    15. #include "iic.h"
    16. #include "oled.h"
    17. #include "bmp.h"

    18. /*******************************************************************************
    19. * Function Name  : main
    20. * Description    : Main program.
    21. * Input          : None
    22. * Return         : None
    23. *******************************************************************************/
    24. int main(void)
    25. {
    26.     u8 t=' ';
    27.     Delay_Init();
    28.     OLED_Init();
    29.     OLED_ColorTurn(0);    //0正常显示,1 反色显示
    30.     OLED_DisplayTurn(0);  //0正常显示 1 屏幕翻转显示
    31.     while(1)
    32.     {
    33.         OLED_ShowPicture(0,0,128,64,BMP2,1);
    34.         OLED_Refresh();
    35.         Delay_Ms(500);
    36.         OLED_Clear();
    37.         OLED_ShowChinese(0,0,0,16,1); //沁
    38.         OLED_ShowChinese(18,0,1,16,1);//恒
    39.         OLED_ShowChinese(36,0,2,16,1);//单
    40.         OLED_ShowChinese(54,0,3,16,1);//片
    41.         OLED_ShowChinese(72,0,4,16,1);//机

    42.         OLED_ShowString(0,16,"IIC driving OLED",16,1);
    43.         OLED_ShowString(20,32,"2021/02/21",16,1);
    44.         OLED_ShowString(0,48,"ASCII:",16,1);
    45.         OLED_ShowString(63,48,"CODE:",16,1);
    46.         OLED_ShowChar(48,48,t,16,1);//显示ASCII字符
    47.         t++;
    48.         if(t>'~')t=' ';
    49.         OLED_ShowNum(103,48,t,3,16,1);
    50.         OLED_Refresh();
    51.         Delay_Ms(500);
    52.         OLED_Clear();
    53.         OLED_ShowString(0,0,"ABC",8,1);//6*8 “ABC”
    54.         OLED_ShowString(0,8,"ABC",12,1);//6*12 “ABC”
    55.         OLED_ShowString(0,20,"ABC",16,1);//8*16 “ABC”
    56.         OLED_ShowString(0,36,"ABC",24,1);//12*24 “ABC”
    57.         OLED_Refresh();
    58.         Delay_Ms(500);
    59.         OLED_ScrollDisplay(5,4,1);
    60.     }
    61. }

    复制代码
    main.c文件主要进行OLED屏显示操作,显示图片、汉字等信息。


    4、下载验证

    将编译好的程序下载到开发版并复位,OLED显示如下
    CH32V CH573单片机芯片-第六十九章:CH32V103应用教程——IIC-硬件IIC驱动OLEDrisc-v单片机中文社区(1)

    68、硬件IIC-OLED.rar
    CH32V CH573单片机芯片-第六十九章:CH32V103应用教程——IIC-硬件IIC驱动OLEDrisc-v单片机中文社区(2) 68、硬件IIC-OLED.rar (514.89 KB, 下载次数: 14)
    链接:https://pan.baidu.com/s/1PsCcpUTpGx-1o5kiSpvy1w
    提取码:tdd3
    复制这段内容后打开百度网盘手机App,操作更方便哦







    上一篇:第六十八章:CH32V103应用教程——IIC-模拟IIC驱动OLED
    下一篇:第七十章:CH32V103应用教程——DHT11的应用
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条



    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2024-11-26 09:52 , Processed in 0.284522 second(s), 48 queries .

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