[活动专区] 【AT-START-F425测评】使用面向对象实现模拟IIC驱动OLED

[复制链接]
1381|0
 楼主| zhouminjie 发表于 2022-6-1 01:02 | 显示全部楼层 |阅读模式
#申请原创#
一、简介
使用面向的编程思想封装I2C驱动,将I2C属性、操作封装成库,在需要创建一个I2C设备时只需要实例化一个I2C对象,本文基于AT32F425和标准库做进一步封装。完成I2C驱动的封装后,依据继承特性实现OLED液晶屏的驱动开发及封装。
二、I2C驱动面向对象封装
hal_i2c.h头文件类定义如下:
  1. #ifndef __HAL_I2C_H__
  2. #define __HAL_I2C_H__

  3. #include "at32f425.h"

  4. #define HAL_ERROR 0
  5. #define HAL_OK 1

  6. //定义I2C类
  7. typedef struct I2C_Type
  8. {
  9.     //属性
  10.     gpio_type *GPIOx_SCL; //SCL所属gpio组,如:GPIOA
  11.     gpio_type *GPIOx_SDA; //SDA所属gpio组,如:GPIOA
  12.     unsigned int GPIO_SCL; //SCL引脚,如:GPIO_PINS_2
  13.     unsigned int GPIO_SDA; //SDA引脚,如:GPIO_PINS_2
  14.     //操作
  15.     void (*I2C_Init)(const struct I2C_Type*);
  16.     void (*I2C_Start)(const struct I2C_Type*);
  17.     void (*I2C_Stop)(const struct I2C_Type*);
  18.     unsigned char (*I2C_Wait_Ack)(const struct I2C_Type*);
  19.     void (*I2C_Ack)(const struct I2C_Type*);
  20.     void (*I2C_NAck)(const struct I2C_Type*);
  21.     void (*I2C_Send_Byte)(const struct I2C_Type*, unsigned char);
  22.     unsigned char (*I2C_Read_Byte)(const struct I2C_Type*, unsigned char);
  23.     void (*delay_us)(unsigned int);

  24. } I2C_TypeDef;

  25. extern I2C_TypeDef I2C_t;

  26. #endif
hal_i2c.c文件具体操作函数如下:
  1. #include "hal_i2c.h"
  2. #include "delay.h"

  3. //设置SDA输入模式
  4. static void SDA_IN(const struct I2C_Type* I2C_Type_t)
  5. {
  6.     gpio_init_type gpio_init_struct;

  7.     //GPIO_SDA初始化设置
  8.     gpio_init_struct.gpio_pins = I2C_Type_t->GPIO_SDA;
  9.     gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  10.     gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
  11.     gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  12.     gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  13.     gpio_init(I2C_Type_t->GPIOx_SDA, &gpio_init_struct);
  14. }

  15. //设置SDA为输出模式
  16. static void SDA_OUT(const struct I2C_Type* I2C_Type_t)
  17. {
  18.     gpio_init_type gpio_init_struct;

  19.     //GPIO_SDA初始化设置
  20.     gpio_init_struct.gpio_pins = I2C_Type_t->GPIO_SDA;
  21.     gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  22.     gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
  23.     gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  24.     gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  25.     gpio_init(I2C_Type_t->GPIOx_SDA, &gpio_init_struct);
  26. }

  27. //设置SCL电平
  28. static void I2C_SCL(const struct I2C_Type* I2C_Type_t, int n)
  29. {
  30.     if(n == 1)
  31.     {
  32.         gpio_bits_write(I2C_Type_t->GPIOx_SCL, I2C_Type_t->GPIO_SCL, TRUE); //设置SCL为高电平
  33.     }
  34.     else
  35.     {
  36.         gpio_bits_write(I2C_Type_t->GPIOx_SCL, I2C_Type_t->GPIO_SCL, FALSE); //设置SCL为低电平
  37.     }
  38. }

  39. //设置SDA电平
  40. static void I2C_SDA(const struct I2C_Type* I2C_Type_t, int n)
  41. {
  42.     if(n == 1)
  43.     {
  44.         gpio_bits_write(I2C_Type_t->GPIOx_SDA, I2C_Type_t->GPIO_SDA, TRUE); //设置SDA为高电平
  45.     }
  46.     else
  47.     {
  48.         gpio_bits_write(I2C_Type_t->GPIOx_SDA, I2C_Type_t->GPIO_SDA, FALSE); //设置SDA为低电平
  49.     }
  50. }

  51. //读取SDA电平
  52. static unsigned char READ_SDA(const struct I2C_Type* I2C_Type_t)
  53. {
  54.     return gpio_input_data_bit_read(I2C_Type_t->GPIOx_SDA, I2C_Type_t->GPIO_SDA); //读取SDA电平
  55. }

  56. //I2C初始化
  57. static void I2C_Init_t(const struct I2C_Type* I2C_Type_t)
  58. {
  59.     gpio_init_type gpio_init_struct;

  60.     //根据GPIO组初始化GPIO时钟
  61.     if(I2C_Type_t->GPIOx_SCL == GPIOA || I2C_Type_t->GPIOx_SDA == GPIOA)
  62.     {
  63.         crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE); //使能GPIOA时钟
  64.     }

  65.     if(I2C_Type_t->GPIOx_SCL == GPIOB || I2C_Type_t->GPIOx_SDA == GPIOB)
  66.     {
  67.         crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE); //使能GPIOB时钟
  68.     }

  69.     if(I2C_Type_t->GPIOx_SCL == GPIOC || I2C_Type_t->GPIOx_SDA == GPIOC)
  70.     {
  71.         crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE); //使能GPIOC时钟
  72.     }

  73.     if(I2C_Type_t->GPIOx_SCL == GPIOD || I2C_Type_t->GPIOx_SDA == GPIOD)
  74.     {
  75.         crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE); //使能GPIOD时钟
  76.     }

  77.     if(I2C_Type_t->GPIOx_SCL == GPIOF || I2C_Type_t->GPIOx_SDA == GPIOF)
  78.     {
  79.         crm_periph_clock_enable(CRM_GPIOF_PERIPH_CLOCK, TRUE); //使能GPIOF时钟
  80.     }

  81.     //GPIO_SCL初始化设置
  82.     gpio_init_struct.gpio_pins = I2C_Type_t->GPIO_SCL;
  83.     gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT; //gpio output mode
  84.     gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN; //output open-drain
  85.     gpio_init_struct.gpio_pull = GPIO_PULL_UP; //pull-up
  86.     gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; //stronger sourcing/sinking strength
  87.     gpio_init(I2C_Type_t->GPIOx_SCL, &gpio_init_struct);
  88.     //GPIO_SDA初始化设置
  89.     gpio_init_struct.gpio_pins = I2C_Type_t->GPIO_SDA;
  90.     gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  91.     gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN; //output open-drain
  92.     gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  93.     gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  94.     gpio_init(I2C_Type_t->GPIOx_SDA, &gpio_init_struct);
  95.     //SCL、SDA的初始化均为高电平
  96.     I2C_SCL(I2C_Type_t, 1);
  97.     I2C_SDA(I2C_Type_t, 1);
  98. }

  99. //I2C Start
  100. static void I2C_Start_t(const struct I2C_Type* I2C_Type_t)
  101. {
  102.     SDA_OUT(I2C_Type_t);
  103.     I2C_SDA(I2C_Type_t, 1);
  104.     I2C_SCL(I2C_Type_t, 1);
  105.     I2C_Type_t->delay_us(4);
  106.     I2C_SDA(I2C_Type_t, 0); //START:when CLK is high,DATA change form high to low
  107.     I2C_Type_t->delay_us(4);
  108.     I2C_SCL(I2C_Type_t, 0); //钳住I2C总线,准备发送或接收数据
  109. }

  110. //I2C Stop
  111. static void I2C_Stop_t(const struct I2C_Type* I2C_Type_t)
  112. {
  113.     SDA_OUT(I2C_Type_t);
  114.     I2C_SCL(I2C_Type_t, 0);
  115.     I2C_SDA(I2C_Type_t, 0); //STOP:when CLK is high DATA change form low to high
  116.     I2C_Type_t->delay_us(4);
  117.     I2C_SCL(I2C_Type_t, 1);
  118.     I2C_SDA(I2C_Type_t, 1); //发送I2C总线结束信号
  119.     I2C_Type_t->delay_us(4);
  120. }

  121. //I2C_Wait_ack 返回HAL_OK表示wait成功,返回HAL_ERROR表示wait失败
  122. static unsigned char I2C_Wait_Ack_t(const struct I2C_Type* I2C_Type_t) //IIC_Wait_ack,返回wait失败或是成功
  123. {
  124.     unsigned char ucErrTime = 0;

  125.     SDA_IN(I2C_Type_t);
  126.     I2C_SDA(I2C_Type_t, 1);
  127.     I2C_Type_t->delay_us(1);
  128.     I2C_SCL(I2C_Type_t, 1);
  129.     I2C_Type_t->delay_us(1);

  130.     while(READ_SDA(I2C_Type_t))
  131.     {
  132.         ucErrTime++;

  133.         if(ucErrTime > 250)
  134.         {
  135.             I2C_Type_t->I2C_Stop(I2C_Type_t);
  136.             return HAL_ERROR;
  137.         }
  138.     }

  139.     I2C_SCL(I2C_Type_t, 0);
  140.     return HAL_OK;
  141. }

  142. //产生ACK应答
  143. static void I2C_Ack_t(const struct I2C_Type* I2C_Type_t)
  144. {
  145.     I2C_SCL(I2C_Type_t, 0);
  146.     SDA_OUT(I2C_Type_t);
  147.     I2C_SDA(I2C_Type_t, 0);
  148.     I2C_Type_t->delay_us(2);
  149.     I2C_SCL(I2C_Type_t, 1);
  150.     I2C_Type_t->delay_us(2);
  151.     I2C_SCL(I2C_Type_t, 0);
  152. }

  153. //产生NACK应答
  154. static void I2C_NAck_t(const struct I2C_Type* I2C_Type_t)
  155. {
  156.     I2C_SCL(I2C_Type_t, 0);
  157.     SDA_OUT(I2C_Type_t);
  158.     I2C_SDA(I2C_Type_t, 1);
  159.     I2C_Type_t->delay_us(2);
  160.     I2C_SCL(I2C_Type_t, 1);
  161.     I2C_Type_t->delay_us(2);
  162.     I2C_SCL(I2C_Type_t, 0);
  163. }

  164. //I2C_Send_Byte,入口参数为要发送的字节
  165. static void I2C_Send_Byte_t(const struct I2C_Type* I2C_Type_t, unsigned char txd)
  166. {
  167.     unsigned char cnt = 0;

  168.     SDA_OUT(I2C_Type_t);
  169.     I2C_SCL(I2C_Type_t, 0);

  170.     for(cnt = 0; cnt < 8; cnt++)
  171.     {
  172.         I2C_SDA(I2C_Type_t, (txd & 0x80) >> 7);
  173.         txd <<= 1;
  174.         //I2C_Type_t->delay_us(2); //OLED显示刷新慢,取消延时
  175.         I2C_SCL(I2C_Type_t, 1);
  176.         //I2C_Type_t->delay_us(2);
  177.         I2C_SCL(I2C_Type_t, 0);
  178.         //I2C_Type_t->delay_us(2);
  179.     }
  180. }

  181. //I2C_Read_Byte,入口参数为是否要发送ACK信号
  182. static unsigned char I2C_Read_Byte_t(const struct I2C_Type* I2C_Type_t, unsigned char ack)
  183. {
  184.     unsigned char cnt, rec = 0;

  185.     SDA_IN(I2C_Type_t);

  186.     for(cnt = 0; cnt < 8; cnt++)
  187.     {
  188.         I2C_SCL(I2C_Type_t, 0);
  189.         //I2C_Type_t->delay_us(2);
  190.         I2C_SCL(I2C_Type_t, 1);
  191.         rec <<= 1;

  192.         if(READ_SDA(I2C_Type_t))
  193.         {
  194.             rec++;
  195.         }

  196.         //I2C_Type_t->delay_us(1);
  197.     }

  198.     if(!ack)
  199.     {
  200.         I2C_Type_t->I2C_NAck(I2C_Type_t);
  201.     }
  202.     else
  203.     {
  204.         I2C_Type_t->I2C_Ack(I2C_Type_t);
  205.     }

  206.     return rec;
  207. }

  208. //实例化一个I2C外设,相当于一个结构体变量,可以直接在其他文件中使用
  209. I2C_TypeDef I2C_t =
  210. {
  211.     .GPIOx_SCL = GPIOF, //GPIO组为GPIOF
  212.     .GPIOx_SDA = GPIOF, //GPIO组为GPIOF
  213.     .GPIO_SCL = GPIO_PINS_5, //GPIO为PIN5
  214.     .GPIO_SDA = GPIO_PINS_4, //GPIO为PIN4
  215.     .I2C_Init = I2C_Init_t,
  216.     .I2C_Start = I2C_Start_t,
  217.     .I2C_Stop = I2C_Stop_t,
  218.     .I2C_Wait_Ack = I2C_Wait_Ack_t,
  219.     .I2C_Ack = I2C_Ack_t,
  220.     .I2C_NAck = I2C_NAck_t,
  221.     .I2C_Send_Byte = I2C_Send_Byte_t,
  222.     .I2C_Read_Byte = I2C_Read_Byte_t,
  223.     .delay_us = Delay_Us, //需自己外部实现delay_us函数
  224. };
三、0.96OLED驱动封装
hal_0.96oled.h头文件类定义如下:
  1. #ifndef __HAL_096OLED_H__
  2. #define __HAL_096OLED_H__

  3. #include "hal_i2c.h"

  4. //定义0.96OLED类
  5. typedef struct OLED_Type
  6. {
  7.     //属性
  8.     //操作
  9.     I2C_TypeDef *I2C; //
  10.     void (*OLED_Write_CMD)(const struct OLED_Type*, unsigned char); //向设备写命令
  11.     void (*OLED_Write_Date)(const struct OLED_Type*, unsigned char); //向设备写数据
  12.     void (*OLED_Set_Pos)(const struct OLED_Type*, unsigned char, unsigned char); //坐标设置
  13.     void (*OLED_Display_On)(const struct OLED_Type*); //开启OLED显示
  14.     void (*OLED_Display_Off)(const struct OLED_Type*); //关闭OLED显示
  15.     void (*OLED_Clear)(const struct OLED_Type*); //OLED清屏
  16.     void (*OLED_Clear_Row)(const struct OLED_Type*, unsigned char); //OLED清行
  17.     void (*OLED_Fill)(const struct OLED_Type*); //OLED填满屏幕
  18.     void (*OLED_ShowChar)(const struct OLED_Type*, unsigned char, unsigned char, unsigned char, unsigned char); //指定位置显示一个字符
  19.     void (*OLED_ShowNum)(const struct OLED_Type*, unsigned char, unsigned char, unsigned int, unsigned char, unsigned char); //指定位置显示数字
  20.     void (*OLED_ShowString)(const struct OLED_Type*, unsigned char, unsigned char, unsigned char*, unsigned char); //指定位置显示字符串
  21.     void (*OLED_ShowCHinese)(const struct OLED_Type*, unsigned char, unsigned char, unsigned char); //显示汉字
  22.     void (*OLED_DrawBMP)(const struct OLED_Type* OLED_Type_t, unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char BMP[]); //显示图片
  23.     void (*OLED_DrawGIF)(const struct OLED_Type* OLED_Type_t, unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char k, int m, const unsigned char GIF[][m]); //显示动画
  24.     void (*OLED_Init)(const struct OLED_Type*); //初始化OLED

  25. } OLED_TypeDef;

  26. extern OLED_TypeDef _0_96OLED;

  27. #endif
hal_0.96oled.c文件具体操作函数如下:
  1. #include "hal_0.96oled.h"
  2. #include "oledfont.h"
  3. #include "delay.h"

  4. //向设备写控制命令
  5. static void OLED_Write_CMD_t(const struct OLED_Type* OLED_Type_t, unsigned char cmd)
  6. {
  7.     OLED_Type_t->I2C->I2C_Start(OLED_Type_t->I2C);
  8.     OLED_Type_t->I2C->I2C_Send_Byte(OLED_Type_t->I2C, 0x78);
  9.     OLED_Type_t->I2C->I2C_Wait_Ack(OLED_Type_t->I2C);
  10.     OLED_Type_t->I2C->I2C_Send_Byte(OLED_Type_t->I2C, 0x00);
  11.     OLED_Type_t->I2C->I2C_Wait_Ack(OLED_Type_t->I2C);
  12.     OLED_Type_t->I2C->I2C_Send_Byte(OLED_Type_t->I2C, cmd);
  13.     OLED_Type_t->I2C->I2C_Wait_Ack(OLED_Type_t->I2C);
  14.     OLED_Type_t->I2C->I2C_Stop(OLED_Type_t->I2C);
  15. }

  16. //向设备写数据
  17. static void OLED_Write_Date_t(const struct OLED_Type* OLED_Type_t, unsigned char date)
  18. {
  19.     OLED_Type_t->I2C->I2C_Start(OLED_Type_t->I2C);
  20.     OLED_Type_t->I2C->I2C_Send_Byte(OLED_Type_t->I2C, 0x78);
  21.     OLED_Type_t->I2C->I2C_Wait_Ack(OLED_Type_t->I2C);
  22.     OLED_Type_t->I2C->I2C_Send_Byte(OLED_Type_t->I2C, 0x40);
  23.     OLED_Type_t->I2C->I2C_Wait_Ack(OLED_Type_t->I2C);
  24.     OLED_Type_t->I2C->I2C_Send_Byte(OLED_Type_t->I2C, date);
  25.     OLED_Type_t->I2C->I2C_Wait_Ack(OLED_Type_t->I2C);
  26.     OLED_Type_t->I2C->I2C_Stop(OLED_Type_t->I2C);
  27. }

  28. //坐标设置
  29. static void OLED_Set_Pos_t(const struct OLED_Type* OLED_Type_t, unsigned char x, unsigned char y)
  30. {
  31.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xB0 + y);
  32.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, ((x & 0xF0) >> 4) | 0x10);
  33.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, x & 0x0F);
  34. }

  35. //开启OLED显示
  36. static void OLED_Display_On_t(const struct OLED_Type* OLED_Type_t)
  37. {
  38.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x8D); //SET DCDC命令
  39.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x14); //DCDC ON
  40.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xAF); //DISPLAY ON
  41. }

  42. //关闭OLED显示
  43. static void OLED_Display_Off_t(const struct OLED_Type* OLED_Type_t)
  44. {
  45.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x8D); //SET DCDC命令
  46.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x10); //DCDC OFF
  47.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xAE); //DISPLAY OFF
  48. }

  49. //OLED清屏
  50. static void OLED_Clear_t(const struct OLED_Type* OLED_Type_t)
  51. {
  52.     unsigned char cnt, count;

  53.     for(cnt = 0; cnt < 8; cnt++)
  54.     {
  55.         OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xB0 + cnt);
  56.         OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x00);
  57.         OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x10);

  58.         for(count = 0; count < 128; count++)
  59.         {
  60.             OLED_Type_t->OLED_Write_Date(OLED_Type_t, 0x00);
  61.         }
  62.     }
  63. }

  64. //OLED清行
  65. static void OLED_Clear_Row_t(const struct OLED_Type* OLED_Type_t, unsigned char n)
  66. {
  67.     unsigned char count;

  68.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xB0 + n);
  69.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x00);
  70.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x10);

  71.     for(count = 0; count < 128; count++)
  72.     {
  73.         OLED_Type_t->OLED_Write_Date(OLED_Type_t, 0x00);
  74.     }
  75. }

  76. //OLED填满屏幕
  77. static void OLED_Fill_t(const struct OLED_Type* OLED_Type_t)
  78. {
  79.     unsigned char cnt, count;

  80.     for(cnt = 0; cnt < 8; cnt++)
  81.     {
  82.         OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xB0 + cnt); //设置页地址(0~7)
  83.         OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x00); //设置显示位置—列低地址
  84.         OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x10); //设置显示位置—列高地址

  85.         for(count = 0; count < 128; count++)
  86.         {
  87.             OLED_Type_t->OLED_Write_Date(OLED_Type_t, 0x01);
  88.         }
  89.     }
  90. }

  91. //指定位置显示一个字符
  92. //x:0~127
  93. //y:0~63
  94. //chr:字符
  95. //mode:0,反白显示;1,正常显示
  96. //size:选择字体 16/12
  97. static void OLED_ShowChar_t(const struct OLED_Type* OLED_Type_t, unsigned char x, unsigned char y, unsigned char chr, unsigned char size)
  98. {
  99.     unsigned char offset = 0, cnt = 0;

  100.     offset = chr - ' '; //计算偏移量

  101.     if(x > 128 - 1)
  102.     {
  103.         x = 0;
  104.         y = y + 2;
  105.     }

  106.     if(size == 16)
  107.     {
  108.         OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x, y);

  109.         for(cnt = 0; cnt < 8; cnt++)
  110.         {
  111.             OLED_Type_t->OLED_Write_Date(OLED_Type_t, F8x16[offset * 16 + cnt]);
  112.         }

  113.         OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x, y + 1);

  114.         for(cnt = 0; cnt < 8; cnt++)
  115.         {
  116.             OLED_Type_t->OLED_Write_Date(OLED_Type_t, F8x16[offset * 16 + cnt + 8]);
  117.         }
  118.     }
  119.     else
  120.     {
  121.         OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x, y);

  122.         for(cnt = 0; cnt < 6; cnt++)
  123.         {
  124.             OLED_Type_t->OLED_Write_Date(OLED_Type_t, F6x8[offset][cnt]);
  125.         }
  126.     }
  127. }

  128. unsigned int oled_pow(unsigned char m, unsigned char n)
  129. {
  130.     unsigned int result = 1;

  131.     while(n--)
  132.     {
  133.         result *= m;
  134.     }

  135.     return result;
  136. }

  137. //指定位置显示一个数字
  138. //x,y:起点坐标
  139. //num:数值(0~4294967295)
  140. //len:数字的位数
  141. //size:字体大小
  142. //mode:模式        0,填充模式;1,叠加模式
  143. static void OLED_ShowNum_t(const struct OLED_Type* OLED_Type_t, unsigned char x, unsigned char y, unsigned int num, unsigned char len, unsigned char size)
  144. {
  145.     unsigned char cnt, temp;
  146.     unsigned char show = 0;

  147.     for(cnt = 0; cnt < len; cnt++)
  148.     {
  149.         temp = (num / oled_pow(10, len - cnt - 1)) % 10;

  150.         if(show == 0 && cnt < (len - 1))
  151.         {
  152.             if(temp == 0)
  153.             {
  154.                 OLED_Type_t->OLED_ShowChar(OLED_Type_t, x + (size / 2) * cnt, y, ' ', size);
  155.                 continue;
  156.             }
  157.             else
  158.             {
  159.                 show = 1;
  160.             }
  161.         }

  162.         OLED_Type_t->OLED_ShowChar(OLED_Type_t, x + (size / 2) * cnt, y, temp + '0', size);
  163.     }
  164. }

  165. //指定位置显示字符串
  166. static void OLED_ShowString_t(const struct OLED_Type* OLED_Type_t, unsigned char x, unsigned char y, unsigned char *chr, unsigned char size)
  167. {
  168.     unsigned char cnt = 0;

  169.     while(chr[cnt] != '\0')
  170.     {
  171.         OLED_Type_t->OLED_ShowChar(OLED_Type_t, x, y, chr[cnt], size);
  172.         x += 8;

  173.         if(x > 120)
  174.         {
  175.             x = 0;
  176.             y += 2;
  177.         }

  178.         cnt++;
  179.     }
  180. }

  181. //显示汉字
  182. static void OLED_ShowCHinese_t(const struct OLED_Type* OLED_Type_t, unsigned char x, unsigned char y, unsigned char no)
  183. {
  184.     unsigned char cnt, addr = 0;

  185.     OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x, y);

  186.     for(cnt = 0; cnt < 16; cnt++)
  187.     {
  188.         OLED_Type_t->OLED_Write_Date(OLED_Type_t, Hzk[2 * no][cnt]);
  189.         addr++;
  190.     }

  191.     OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x, y + 1);

  192.     for(cnt = 0; cnt < 16; cnt++)
  193.     {
  194.         OLED_Type_t->OLED_Write_Date(OLED_Type_t, Hzk[2 * no + 1][cnt]);
  195.         addr++;
  196.     }
  197. }

  198. //显示图片
  199. /*
  200.         @brief                        显示图片
  201.         @param                        x0:起始列地址
  202.                                         y0:起始页地址
  203.                                         x1:终止列地址
  204.                                         y1:终止页地址
  205.                                         BMP[]:存放图片代码的数组
  206.         @retval                        无
  207. */
  208. static void OLED_DrawBMP_t(const struct OLED_Type* OLED_Type_t, unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char BMP[])
  209. {
  210.     unsigned int j = 0; //定义变量
  211.     unsigned char x, y; //定义变量

  212.     if(y1 % 8 == 0)
  213.     {
  214.         y = y1 / 8; //判断终止页是否为8的整数倍
  215.     }
  216.     else
  217.     {
  218.         y = y1 / 8 + 1;
  219.     }

  220.     for(y = y0; y < y1; y++) //从起始页开始,画到终止页
  221.     {
  222.         OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x0, y); //在页的起始列开始画

  223.         for(x = x0; x < x1; x++) //画x1 - x0 列
  224.         {
  225.             OLED_Type_t->OLED_Write_Date(OLED_Type_t, BMP[j++]); //画图片的点
  226.         }
  227.     }
  228. }

  229. //显示动图
  230. /*
  231.         @brief                        显示动图
  232.         @param                        x0:起始列地址
  233.                                 y0:起始页地址
  234.                                 x1:终止列地址
  235.                                 y1:终止页地址
  236.                                 k: 帧个数
  237.                                 m: 单帧数组大小
  238.                                 BMP[][m]:存放动图代码的数组
  239.         @retval                        无
  240. */
  241. static void OLED_DrawGIF_t(const struct OLED_Type* OLED_Type_t, unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char k, int m, const unsigned char GIF[][m])
  242. {
  243.     unsigned int j = 0; //定义变量
  244.     unsigned char x, y, i; //定义变量

  245.     if(y1 % 8 == 0)
  246.     {
  247.         y = y1 / 8; //判断终止页是否为8的整数倍
  248.     }
  249.     else
  250.     {
  251.         y = y1 / 8 + 1;
  252.     }

  253.     for (i = 0; i < k; i++) //从第一帧开始画
  254.     {
  255.         j = 0;

  256.         for(y = y0; y < y1; y++) //从起始页开始,画到终止页
  257.         {
  258.             OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x0, y); //在页的起始列开始画

  259.             for(x = x0; x < x1; x++) //画x1 - x0 列
  260.             {
  261.                 OLED_Type_t->OLED_Write_Date(OLED_Type_t, GIF[i][j++]); //画图片的点
  262.             }
  263.         }

  264.         //delay_ms(80);
  265.     }
  266. }

  267. //OLED初始化
  268. static void OLED_Init_t(const struct OLED_Type* OLED_Type_t)
  269. {
  270.     OLED_Type_t->I2C->I2C_Init(OLED_Type_t->I2C);
  271.     Delay_Ms(200);
  272.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xAE); //display off
  273.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x00); //set low column address
  274.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x10); //set high column address
  275.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x40); //set start line address
  276.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xB0); //set page address
  277.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x81); //contract control
  278.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xFF); //128
  279.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xA1); //set segment remap
  280.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xA6); //normal / reverse
  281.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xA8); //set multiplex ratio(1 to 64)
  282.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x3F); //1/32 duty
  283.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xC8); //Com scan direction
  284.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xD3); //set display offset
  285.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x00); //
  286.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xD5); //set osc division
  287.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x80); //
  288.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xD8); //set area color mode off
  289.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x05); //
  290.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xD9); //Set Pre-Charge Period
  291.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xF1); //
  292.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xDA); //set com pin configuartion
  293.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x12); //
  294.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xDB); //set Vcomh
  295.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x30); //
  296.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x8D); //set charge pump enable
  297.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x14); //
  298.     OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xAF); //turn on oled panel
  299. }

  300. //实例化
  301. OLED_TypeDef _0_96OLED =
  302. {
  303.     .I2C = &I2C_t,
  304.     .OLED_Write_CMD = OLED_Write_CMD_t,
  305.     .OLED_Write_Date = OLED_Write_Date_t,
  306.     .OLED_Set_Pos = OLED_Set_Pos_t,
  307.     .OLED_Display_On = OLED_Display_On_t,
  308.     .OLED_Display_Off = OLED_Display_Off_t,
  309.     .OLED_Clear = OLED_Clear_t,
  310.     .OLED_Clear_Row = OLED_Clear_Row_t,
  311.     .OLED_Fill = OLED_Fill_t,
  312.     .OLED_ShowChar = OLED_ShowChar_t,
  313.     .OLED_ShowNum = OLED_ShowNum_t,
  314.     .OLED_ShowString = OLED_ShowString_t,
  315.     .OLED_ShowCHinese = OLED_ShowCHinese_t,
  316.     .OLED_DrawBMP = OLED_DrawBMP_t,
  317.     .OLED_DrawGIF = OLED_DrawGIF_t,
  318.     .OLED_Init = OLED_Init_t,

  319. };
以上可看出OLED类中包含I2C类的成员对象,由于OLED的实现需要调用I2C的成员方法,I2C相当于OLED的下一层的驱动,因此将I2C类对象作为OLED类的成员;我们在使用OLED的时候需要实例化OLED类对象,由于I2C和OLED是分别在不同的.c文件中,在实例化OLED外设时,结构体中包含的是I2C设备的指针,而不是实体,同时在I2C.c文件中应完成实例化一个I2C对象;从而对外提供了OLED的封装接口。
四、main调用
在main中直接使用_0_96OLED来实现所有操作,如下:
  1. int main(void)
  2. {
  3.     /* initial system clock */
  4.     system_clock_config();

  5.     /* config nvic priority group */
  6.     nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);

  7.     Delay_Init();
  8.     hal_ledInit();
  9.     hal_timerInit();

  10.     //I2C_t.I2C_Init(&I2C_t);
  11.     _0_96OLED.OLED_Init(&_0_96OLED);
  12.     _0_96OLED.OLED_Clear(&_0_96OLED);

  13.     _0_96OLED.OLED_ShowString(&_0_96OLED, 16, 0, "www.21ic.com", 16);
  14.     _0_96OLED.OLED_ShowString(&_0_96OLED, 14, 2, "AT32F425 TEST", 16);
  15.     _0_96OLED.OLED_ShowString(&_0_96OLED, 28, 4, "2022/5/31", 16);
  16.     _0_96OLED.OLED_ShowString(&_0_96OLED, 14, 6, "ID:zhouminjie", 16);

  17.     Delay_Ms(1000);

  18.     while(1)
  19.     {
  20.         _0_96OLED.OLED_DrawGIF(&_0_96OLED, 0, 0, 128, 8, 29, 1024, GIF);
  21.     }
  22. }
五、总结
面向对象方法实现I2C驱动封装及OLED驱动封装,对外仅提供一个OLED操作对象接口,提高了代码的复用性及封装性,方便了代码后期的维护修改。
参考:https://blog.csdn.net/weixin_42700740/article/details/113624909
六、效果及测试代码
056af8253c3e38c5e4efcf483c3777c8_ (1).gif

AT32F425_SW_I2C_0.96OLED_oo.zip (382.25 KB, 下载次数: 23)


您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

140

帖子

3

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