• HAL库与cubemx系列教程|采用面向对象的方法写一个OLED驱动


    上一章节主要介绍了什么怎么样实现C语言面向对象编程,本章节来实战看看如何运用在嵌入式开发中

    面向对象

    ...有对象的面向她,没对象的,面向我,开课了...,说起面向对象编程,不得不说说面向过程编程

    C语言中一般使用面向过程编程,就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步调用,在函数中对数据结构进行处理(执行算法),也就是说数据结构和算法是分开的。

    C++语言把数据和算法封装在一起,形成一个整体,无论是对它的属性进行操作、还是对它的行为进行调用,都是通过一个对象来执行,这就是面向对象编程思想(摘自道哥:IOT物联网小镇)。

    既然本次要实现面向对象编写OLED驱动,那就要具备上面所说的面向对象的特性,代码较多,大家可以在**文末评论区找到源码链接,直接阅读源码**...

    IIC底层驱动封装

    • 测试平台:STM32G030C8T6

    • OLED:096寸OLED(IIC接口)

    此部分参考:https://blog.csdn.net/weixin_42700740/article/details/113624909

    IIC的协议就不多说了,网络上有很多讲的很形象的例子,接下来主要看代码实现就可以了

    先定义一个IIC的“类”,主要包含用到的IO,IIC底层驱动函数等

    1. //定义IIC类
    2. typedef struct IIC_Type
    3. {
    4.    //属性
    5.    GPIO_TypeDef  *GPIOx_SCL;  //GPIO_SCL所属的GPIO组(如:GPIOA)
    6.    GPIO_TypeDef  *GPIOx_SDA;  //GPIO_SDA所属的GPIO组(如:GPIOA)
    7.    uint32_t GPIO_SCL;     //GPIO_SCL的IO引脚(如:GPIO_PIN_0)
    8.    uint32_t GPIO_SDA;     //GPIO_SDA的IO引脚(如:GPIO_PIN_0)
    9.    //操作
    10.    void (*IIC_Init)(const struct IIC_Type*);        //IIC_Init
    11.    void (*IIC_Start)(const struct IIC_Type*);       //IIC_Start
    12.    void (*IIC_Stop)(const struct IIC_Type*);        //IIC_Stop
    13.    uint8_t (*IIC_Wait_Ack)(const struct IIC_Type*);    //IIC_Wait_ack,返回wait失败或是成功
    14.    void (*IIC_Ack)(const struct IIC_Type*);       //IIC_Ack,IIC发送ACK信号
    15.    void (*IIC_NAck)(const struct IIC_Type*);       //IIC_NAck,IIC发送NACK信号
    16.    void (*IIC_Send_Byte)(const struct IIC_Type*,uint8_t);       //IIC_Send_Byte,入口参数为要发送的字节
    17.    uint8_t (*IIC_Read_Byte)(const struct IIC_Type*,uint8_t);     //IIC_Send_Byte,入口参数为是否要发送ACK信号
    18.    void (*delay_us)(uint32_t);              //us延时
    19. }IIC_TypeDef;

    接下来封装

    IO时钟、PIN脚:

    1. //设置SDA为输入模式
    2. static void SDA_IN(const struct IIC_Type *IIC_Type_t)
    3. {
    4.  uint8_t io_num = 0//定义io Num号
    5.  switch (IIC_Type_t->GPIO_SDA)
    6.  {
    7.  case GPIO_PIN_0:
    8.   io_num = 0;
    9.   break;
    10.  case GPIO_PIN_1:
    11.   io_num = 1;
    12.   break;
    13.  case GPIO_PIN_2:
    14.   io_num = 2;
    15.   break;
    16.  case GPIO_PIN_3:
    17.   io_num = 3;
    18.   break;
    19.  case GPIO_PIN_4:
    20.   io_num = 4;
    21.   break;
    22.  case GPIO_PIN_5:
    23.   io_num = 5;
    24.   break;
    25.  case GPIO_PIN_6:
    26.   io_num = 6;
    27.   break;
    28.  case GPIO_PIN_7:
    29.   io_num = 7;
    30.   break;
    31.  case GPIO_PIN_8:
    32.   io_num = 8;
    33.   break;
    34.  case GPIO_PIN_9:
    35.   io_num = 9;
    36.   break;
    37.  case GPIO_PIN_10:
    38.   io_num = 10;
    39.   break;
    40.  case GPIO_PIN_11:
    41.   io_num = 11;
    42.   break;
    43.  case GPIO_PIN_12:
    44.   io_num = 12;
    45.   break;
    46.  case GPIO_PIN_13:
    47.   io_num = 13;
    48.   break;
    49.  case GPIO_PIN_14:
    50.   io_num = 14;
    51.   break;
    52.  case GPIO_PIN_15:
    53.   io_num = 15;
    54.   break;
    55.  }
    56.  IIC_Type_t->GPIOx_SDA->MODER &= ~(3 << (io_num * 2)); //将GPIOx_SDA->GPIO_SDA清零
    57.  IIC_Type_t->GPIOx_SDA->MODER |= 0 << (io_num * 2);   //将GPIOx_SDA->GPIO_SDA设置为输入模式
    58. }
    59. //设置SDA为输出模式
    60. static void SDA_OUT(const struct IIC_Type *IIC_Type_t)
    61. {
    62.  uint8_t io_num = 0//定义io Num号
    63.  switch (IIC_Type_t->GPIO_SDA)
    64.  {
    65.  case GPIO_PIN_0:
    66.   io_num = 0;
    67.   break;
    68.  case GPIO_PIN_1:
    69.   io_num = 1;
    70.   break;
    71.  case GPIO_PIN_2:
    72.   io_num = 2;
    73.   break;
    74.  case GPIO_PIN_3:
    75.   io_num = 3;
    76.   break;
    77.  case GPIO_PIN_4:
    78.   io_num = 4;
    79.   break;
    80.  case GPIO_PIN_5:
    81.   io_num = 5;
    82.   break;
    83.  case GPIO_PIN_6:
    84.   io_num = 6;
    85.   break;
    86.  case GPIO_PIN_7:
    87.   io_num = 7;
    88.   break;
    89.  case GPIO_PIN_8:
    90.   io_num = 8;
    91.   break;
    92.  case GPIO_PIN_9:
    93.   io_num = 9;
    94.   break;
    95.  case GPIO_PIN_10:
    96.   io_num = 10;
    97.   break;
    98.  case GPIO_PIN_11:
    99.   io_num = 11;
    100.   break;
    101.  case GPIO_PIN_12:
    102.   io_num = 12;
    103.   break;
    104.  case GPIO_PIN_13:
    105.   io_num = 13;
    106.   break;
    107.  case GPIO_PIN_14:
    108.   io_num = 14;
    109.   break;
    110.  case GPIO_PIN_15:
    111.   io_num = 15;
    112.   break;
    113.  }
    114.  IIC_Type_t->GPIOx_SDA->MODER &= ~(3 << (io_num * 2)); //将GPIOx_SDA->GPIO_SDA清零
    115.  IIC_Type_t->GPIOx_SDA->MODER |= 1 << (io_num * 2);   //将GPIOx_SDA->GPIO_SDA设置为输出模式
    116. }
    117. //设置SCL电平
    118. static void IIC_SCL(const struct IIC_Type *IIC_Type_t, int n)
    119. {
    120.  if (n == 1)
    121.  {
    122.   HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL, IIC_Type_t->GPIO_SCL, GPIO_PIN_SET); //设置SCL为高电平
    123.  }
    124.  else
    125.  {
    126.   HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL, IIC_Type_t->GPIO_SCL, GPIO_PIN_RESET); //设置SCL为低电平
    127.  }
    128. }
    129. //设置SDA电平
    130. static void IIC_SDA(const struct IIC_Type *IIC_Type_t, int n)
    131. {
    132.  if (n == 1)
    133.  {
    134.   HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA, IIC_Type_t->GPIO_SDA, GPIO_PIN_SET); //设置SDA为高电平
    135.  }
    136.  else
    137.  {
    138.   HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA, IIC_Type_t->GPIO_SDA, GPIO_PIN_RESET); //设置SDA为低电平
    139.  }
    140. }
    141. //读取SDA电平
    142. static uint8_t READ_SDA(const struct IIC_Type *IIC_Type_t)
    143. {
    144.  return HAL_GPIO_ReadPin(IIC_Type_t->GPIOx_SDA, IIC_Type_t->GPIO_SDA); //读取SDA电平
    145. }
    146. // IIC初始化
    147. void IIC_Init_t(const struct IIC_Type *IIC_Type_t)
    148. {
    149.  GPIO_InitTypeDef GPIO_Initure;
    150.  //根据GPIO组初始化GPIO时钟
    151.  if (IIC_Type_t->GPIOx_SCL == GPIOA || IIC_Type_t->GPIOx_SDA == GPIOA)
    152.  {
    153.   __HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟
    154.  }
    155.  if (IIC_Type_t->GPIOx_SCL == GPIOB || IIC_Type_t->GPIOx_SDA == GPIOB)
    156.  {
    157.   __HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB时钟
    158.  }
    159.  if (IIC_Type_t->GPIOx_SCL == GPIOC || IIC_Type_t->GPIOx_SDA == GPIOC)
    160.  {
    161.   __HAL_RCC_GPIOC_CLK_ENABLE(); //使能GPIOC时钟
    162.  }
    163.  if (IIC_Type_t->GPIOx_SCL == GPIOD || IIC_Type_t->GPIOx_SDA == GPIOD)
    164.  {
    165.   __HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD时钟
    166.  }
    167.  // GPIO_SCL初始化设置
    168.  GPIO_Initure.Pin = IIC_Type_t->GPIO_SCL;
    169.  GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;  //推挽输出
    170.  GPIO_Initure.Pull = GPIO_PULLUP;    //上拉
    171.  GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; //快速
    172.  HAL_GPIO_Init(IIC_Type_t->GPIOx_SCL, &GPIO_Initure);
    173.  // GPIO_SDA初始化设置
    174.  GPIO_Initure.Pin = IIC_Type_t->GPIO_SDA;
    175.  GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;  //推挽输出
    176.  GPIO_Initure.Pull = GPIO_PULLUP;    //上拉
    177.  GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; //快速
    178.  HAL_GPIO_Init(IIC_Type_t->GPIOx_SDA, &GPIO_Initure);
    179.  // SCL与SDA的初始化均为高电平
    180.  IIC_SCL(IIC_Type_t, 1);
    181.  IIC_SDA(IIC_Type_t, 1);
    182. }

    起始信号:

    1. // IIC Start
    2. void IIC_Start_t(const struct IIC_Type *IIC_Type_t)
    3. {
    4.  SDA_OUT(IIC_Type_t); // sda线输出
    5.  IIC_SDA(IIC_Type_t, 1);
    6.  IIC_SCL(IIC_Type_t, 1);
    7.  IIC_Type_t->delay_us(4);
    8.  IIC_SDA(IIC_Type_t, 0); // START:when CLK is high,DATA change form high to low
    9.  IIC_Type_t->delay_us(4);
    10.  IIC_SCL(IIC_Type_t, 0); //钳住I2C总线,准备发送或接收数据
    11. }

    停止信号:

    1. // IIC Stop
    2. void IIC_Stop_t(const struct IIC_Type *IIC_Type_t)
    3. {
    4.  SDA_OUT(IIC_Type_t); // sda线输出
    5.  IIC_SCL(IIC_Type_t, 0);
    6.  IIC_SDA(IIC_Type_t, 0); // STOP:when CLK is high DATA change form low to high
    7.  IIC_Type_t->delay_us(4);
    8.  IIC_SCL(IIC_Type_t, 1);
    9.  IIC_SDA(IIC_Type_t, 1); //发送I2C总线结束信号
    10.  IIC_Type_t->delay_us(4);
    11. }

    等待应答信号:

    1. // IIC_Wait_ack 返回HAL_OK表示wait成功,返回HAL_ERROR表示wait失败
    2. uint8_t IIC_Wait_Ack_t(const struct IIC_Type *IIC_Type_t) // IIC_Wait_ack,返回wait失败或是成功
    3. {
    4.  uint8_t ucErrTime = 0;
    5.  SDA_IN(IIC_Type_t); // SDA设置为输入
    6.  IIC_SDA(IIC_Type_t, 1);
    7.  IIC_Type_t->delay_us(1);
    8.  IIC_SCL(IIC_Type_t, 1);
    9.  IIC_Type_t->delay_us(1);
    10.  while (READ_SDA(IIC_Type_t))
    11.  {
    12.   ucErrTime++;
    13.   if (ucErrTime > 250)
    14.   {
    15.    IIC_Type_t->IIC_Stop(IIC_Type_t);
    16.    return HAL_ERROR;
    17.   }
    18.  }
    19.  IIC_SCL(IIC_Type_t, 0); //时钟输出0
    20.  return HAL_OK;
    21. }

    产生ACK信号:

    1. //产生ACK应答
    2. void IIC_Ack_t(const struct IIC_Type *IIC_Type_t)
    3. {
    4.  IIC_SCL(IIC_Type_t, 0);
    5.  SDA_OUT(IIC_Type_t);
    6.  IIC_SDA(IIC_Type_t, 0);
    7.  IIC_Type_t->delay_us(2);
    8.  IIC_SCL(IIC_Type_t, 1);
    9.  IIC_Type_t->delay_us(2);
    10.  IIC_SCL(IIC_Type_t, 0);
    11. }

    产生NACK信号:

    1. //产生NACK应答
    2. void IIC_NAck_t(const struct IIC_Type *IIC_Type_t)
    3. {
    4.  IIC_SCL(IIC_Type_t, 0);
    5.  SDA_OUT(IIC_Type_t);
    6.  IIC_SDA(IIC_Type_t, 1);
    7.  IIC_Type_t->delay_us(2);
    8.  IIC_SCL(IIC_Type_t, 1);
    9.  IIC_Type_t->delay_us(2);
    10.  IIC_SCL(IIC_Type_t, 0);
    11. }

    发送一字节:

    1. // IIC_Send_Byte,入口参数为要发送的字节
    2. void IIC_Send_Byte_t(const struct IIC_Type *IIC_Type_t, uint8_t txd)
    3. {
    4.  uint8_t t = 0;
    5.  SDA_OUT(IIC_Type_t);
    6.  IIC_SCL(IIC_Type_t, 0); //拉低时钟开始数据传输
    7.  for (t = 0; t < 8; t++)
    8.  {
    9.   IIC_SDA(IIC_Type_t, (txd & 0x80) >> 7);
    10.   txd <<= 1;
    11.   IIC_Type_t->delay_us(2); //对TEA5767这三个延时都是必须的
    12.   IIC_SCL(IIC_Type_t, 1);
    13.   IIC_Type_t->delay_us(2);
    14.   IIC_SCL(IIC_Type_t, 0);
    15.   IIC_Type_t->delay_us(2);
    16.  }
    17. }

    读取一字节:

    1. uint8_t IIC_Read_Byte_t(const struct IIC_Type *IIC_Type_t, uint8_t ack)
    2. {
    3.  uint8_t i, receive = 0;
    4.  SDA_IN(IIC_Type_t); // SDA设置为输入
    5.  for (i = 0; i < 8; i++)
    6.  {
    7.   IIC_SCL(IIC_Type_t, 0);
    8.   IIC_Type_t->delay_us(2);
    9.   IIC_SCL(IIC_Type_t, 1);
    10.   receive <<= 1;
    11.   if (READ_SDA(IIC_Type_t))
    12.    receive++;
    13.   IIC_Type_t->delay_us(1);
    14.  }
    15.  if (!ack)
    16.   IIC_Type_t->IIC_NAck(IIC_Type_t); //发送nACK
    17.  else
    18.   IIC_Type_t->IIC_Ack(IIC_Type_t); //发送ACK
    19.  return receive;
    20. }

    最后,来实例化一个“对象”,主要包含了供外部调用的一些成员,对于外部用户来说,他只需要关注这个结构体里面的成员,而不需要去关注内部如何实现的

    1. //实例化一个IIC1外设,相当于一个结构体变量,可以直接在其他文件中使用
    2. IIC_TypeDef IIC1 = {
    3.  .GPIOx_SCL = GPIOB,  // GPIO组为GPIOB
    4.  .GPIOx_SDA = GPIOB,  // GPIO组为GPIOB
    5.  .GPIO_SCL = GPIO_PIN_9, // GPIO为PIN9
    6.  .GPIO_SDA = GPIO_PIN_8, // GPIO为PIN8
    7.  .IIC_Init = IIC_Init_t,
    8.  .IIC_Start = IIC_Start_t,
    9.  .IIC_Stop = IIC_Stop_t,
    10.  .IIC_Wait_Ack = IIC_Wait_Ack_t,
    11.  .IIC_Ack = IIC_Ack_t,
    12.  .IIC_NAck = IIC_NAck_t,
    13.  .IIC_Send_Byte = IIC_Send_Byte_t,
    14.  .IIC_Read_Byte = IIC_Read_Byte_t,
    15.  .delay_us = delay_us //需自己外部实现delay_us函数
    16. };

    OLED封装

    依然是先封装一个“OLED类”

    1. //定义RT_OLED类
    2. typedef struct RT_OLED_TYPE
    3. {
    4.  //操作
    5.  IIC_TypeDef IIC;       //IIC驱动
    6.  void (*rt_oled_write_byte)(const struct RT_OLED_TYPE*,uint8_t,uint8_t,uint8_t);
    7.  void (*rt_oled_init)(const struct RT_OLED_TYPE*);
    8.  void (*rt_oled_display_on)(const struct RT_OLED_TYPE*,uint8_t);
    9.  void (*rt_oled_clear)(const struct RT_OLED_TYPE*);
    10.  void (*rt_oled_displayall)(const struct RT_OLED_TYPE*);
    11.  void (*rt_oled_showchar)(const struct RT_OLED_TYPE*,uint8_t,uint8_t,uint8_t,uint8_t);
    12.  void (*rt_oled_shownum)(const struct RT_OLED_TYPE*,uint8_t,uint8_t,uint32_t,uint8_t,uint8_t);
    13.  void (*rt_oled_showstring)(const struct RT_OLED_TYPE*,uint8_t,uint8_t,uint8_t *,uint8_t);
    14.  void (*rt_oled_showchinese)(const struct RT_OLED_TYPE*,uint8_t,uint8_t,uint8_t);
    15.  void (*rt_oled_showbmp)(const struct RT_OLED_TYPE*,uint8_t,uint8_t,uint8_t,uint8_t,unsigned char *);
    16.  void (*rt_oled_fillpicture)(const struct RT_OLED_TYPE*,unsigned char);
    17. }RT_OLED_TypeDef;
    18. extern RT_OLED_TypeDef rt_oled;              //外部声明实例化RT_OLED对象

    写数据、命令封装:

    1. /**
    2.  * @author:小飞哥玩嵌入式-小飞哥
    3.  * @TODO: oled写数据
    4.  * @param
    5.  * @return NULL
    6.  */
    7. static void rt_oled_write_data_t(const struct RT_OLED_TYPE *rt_oled_type_tuint8_t chipid, uint8_t dat)
    8. {
    9.  rt_oled_type_t->IIC.IIC_Start(&rt_oled_type_t->IIC);
    10.  rt_oled_type_t->IIC.IIC_Send_Byte(&rt_oled_type_t->IIC, chipid); // D/C#=0; R/W#=0
    11.  rt_oled_type_t->IIC.IIC_Ack(&rt_oled_type_t->IIC);
    12.  rt_oled_type_t->IIC.IIC_Send_Byte(&rt_oled_type_t->IIC, 0x40);
    13.  rt_oled_type_t->IIC.IIC_Ack(&rt_oled_type_t->IIC);
    14.  rt_oled_type_t->IIC.IIC_Send_Byte(&rt_oled_type_t->IIC, dat);
    15.  rt_oled_type_t->IIC.IIC_Ack(&rt_oled_type_t->IIC);
    16.  rt_oled_type_t->IIC.IIC_Stop(&rt_oled_type_t->IIC);
    17. }
    18. /**
    19.  * @author:小飞哥玩嵌入式-小飞哥
    20.  * @TODO: oled写命令
    21.  * @param
    22.  * @return NULL
    23.  */
    24. static void rt_oled_write_cmd_t(const struct RT_OLED_TYPE *rt_oled_type_tuint8_t chipid, uint8_t cmd)
    25. {
    26.  rt_oled_type_t->IIC.IIC_Start(&rt_oled_type_t->IIC);
    27.  rt_oled_type_t->IIC.IIC_Send_Byte(&rt_oled_type_t->IIC, chipid); // D/C#=0; R/W#=0
    28.  rt_oled_type_t->IIC.IIC_Ack(&rt_oled_type_t->IIC);
    29.  rt_oled_type_t->IIC.IIC_Send_Byte(&rt_oled_type_t->IIC, 0x00);
    30.  rt_oled_type_t->IIC.IIC_Ack(&rt_oled_type_t->IIC);
    31.  rt_oled_type_t->IIC.IIC_Send_Byte(&rt_oled_type_t->IIC, cmd);
    32.  rt_oled_type_t->IIC.IIC_Ack(&rt_oled_type_t->IIC);
    33.  rt_oled_type_t->IIC.IIC_Stop(&rt_oled_type_t->IIC);
    34. }
    35. /**
    36.  * @author:小飞哥玩嵌入式-小飞哥
    37.  * @TODO: oled写数据或者写命令
    38.  * @param
    39.  * @return NULL
    40.  */
    41. static void rt_oled_write_byte_t(const struct RT_OLED_TYPE *rt_oled_type_tuint8_t chipid, uint8_t dat, uint8_t cmd)
    42. {
    43.  if (cmd) //写数据
    44.  {
    45.   rt_oled_write_data_t(rt_oled_type_t, chipid, dat);
    46.  }
    47.  else //写命令
    48.  {
    49.   rt_oled_write_cmd_t(rt_oled_type_t, chipid, dat);
    50.  }
    51. }

    接下来是一些对OLED的显示操作,就不一一介绍了:

    1. /**
    2.  * @author:小飞哥玩嵌入式-小飞哥
    3.  * @TODO: oled坐标设置
    4.  * @param
    5.  * @return NULL
    6.  */
    7. static void rt_oled_setpos_t(const struct RT_OLED_TYPE *rt_oled_type_tuint8_t x, uint8_t y)
    8. {
    9.  rt_oled_write_byte_t(rt_oled_type_t0x780xb0 + y, OLED_CMD);
    10.  rt_oled_write_byte_t(rt_oled_type_t0x78, ((x & 0xf0) >> 4) | 0x10, OLED_CMD);
    11.  rt_oled_write_byte_t(rt_oled_type_t0x78, (x & 0x0f), OLED_CMD);
    12. }
    13. /**
    14.  * @author:小飞哥玩嵌入式-小飞哥
    15.  * @TODO: oled显示开关
    16.  * @param
    17.  * @return NULL
    18.  */
    19. static void rt_oled_display_on_t(const struct RT_OLED_TYPE *rt_oled_type_tuint8_t ON)
    20. {
    21.  if (ON)
    22.  {
    23.   rt_oled_write_byte_t(rt_oled_type_t0x780X8D, OLED_CMD);
    24.   rt_oled_write_byte_t(rt_oled_type_t0x780X14, OLED_CMD);
    25.   rt_oled_write_byte_t(rt_oled_type_t0x780XAF, OLED_CMD);
    26.  }
    27.  else
    28.  {
    29.   rt_oled_write_byte_t(rt_oled_type_t0x780X8D, OLED_CMD);
    30.   rt_oled_write_byte_t(rt_oled_type_t0x780X14, OLED_CMD);
    31.   rt_oled_write_byte_t(rt_oled_type_t0x780XAE, OLED_CMD);
    32.  }
    33. }
    34. /**
    35.  * @author:小飞哥玩嵌入式-小飞哥
    36.  * @TODO: oled清屏
    37.  * @param
    38.  * @return NULL
    39.  */
    40. static void rt_oled_clear_t(const struct RT_OLED_TYPE *rt_oled_type_t)
    41. {
    42.  uint8_t i, n;
    43.  for (i = 0; i < 8; i++)
    44.  {
    45.   rt_oled_write_byte_t(rt_oled_type_t0x780xb0 + i, OLED_CMD);
    46.   rt_oled_write_byte_t(rt_oled_type_t0x780x00, OLED_CMD);
    47.   rt_oled_write_byte_t(rt_oled_type_t0x780x10, OLED_CMD);
    48.   for (n = 0; n < 128; n++)
    49.    rt_oled_write_byte_t(rt_oled_type_t0x780, OLED_DATA);
    50.  } //更新显示
    51. }
    52. /**
    53.  * @author:小飞哥玩嵌入式-小飞哥
    54.  * @TODO: oled全显示
    55.  * @param
    56.  * @return NULL
    57.  */
    58. static void rt_oled_displayall_t(const struct RT_OLED_TYPE *rt_oled_type_t)
    59. {
    60.  uint8_t i, n;
    61.  for (i = 0; i < 8; i++)
    62.  {
    63.   rt_oled_write_byte_t(rt_oled_type_t0x780xb0 + i, OLED_CMD);
    64.   rt_oled_write_byte_t(rt_oled_type_t0x780x00, OLED_CMD);
    65.   rt_oled_write_byte_t(rt_oled_type_t0x780x10, OLED_CMD);
    66.   for (n = 0; n < 128; n++)
    67.    rt_oled_write_byte_t(rt_oled_type_t0x781, OLED_DATA);
    68.  } //更新显示
    69. }
    70. /**
    71.  * @author:小飞哥玩嵌入式-小飞哥
    72.  * @TODO: oled显示一个字符
    73.  * @param
    74.  * @return NULL
    75.  */
    76. static void rt_oled_showchar_t(const struct RT_OLED_TYPE *rt_oled_type_tuint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size)
    77. {
    78.  unsigned char c = 0, i = 0;
    79.  c = chr - ' '//得到偏移后的值
    80.  if (x > Max_Column - 1)
    81.  {
    82.   x = 0;
    83.   y = y + 2;
    84.  }
    85.  if (Char_Size == 16)
    86.  {
    87.   rt_oled_setpos_t(rt_oled_type_t, x, y);
    88.   for (i = 0; i < 8; i++)
    89.   {
    90.    rt_oled_write_byte_t(rt_oled_type_t0x78, F8X16[c * 16 + i], OLED_DATA);
    91.   }
    92.   rt_oled_setpos_t(rt_oled_type_t, x, y + 1);
    93.   for (i = 0; i < 8; i++)
    94.   {
    95.    rt_oled_write_byte_t(rt_oled_type_t0x78, F8X16[c * 16 + i + 8], OLED_DATA);
    96.   }
    97.  }
    98.  else
    99.  {
    100.   rt_oled_setpos_t(rt_oled_type_t, x, y);
    101.   for (i = 0; i < 6; i++)
    102.   {
    103.    rt_oled_write_byte_t(rt_oled_type_t0x78, F6x8[c][i], OLED_DATA);
    104.   }
    105.  }
    106. }
    107. /**
    108.  * @author:小飞哥玩嵌入式-小飞哥
    109.  * @TODO: oled m^n
    110.  * @param
    111.  * @return NULL
    112.  */
    113. static uint32_t rt_oled_pow_t(uint8_t m, uint8_t n)
    114. {
    115.  uint32_t result = 1;
    116.  while (n--)
    117.   result *= m;
    118.  return result;
    119. }
    120. /**
    121.  * @author:小飞哥玩嵌入式-小飞哥
    122.  * @TODO: oled显示一个字符
    123.  * @param
    124.  * @return NULL
    125. //显示2个数字
    126. //x,y :起点坐标
    127. //len :数字的位数
    128. //size:字体大小
    129. //mode:模式 0,填充模式;1,叠加模式
    130. //num:数值(0~4294967295);
    131. */
    132. static void rt_oled_shownum_t(const struct RT_OLED_TYPE *rt_oled_type_tuint8_t x, uint8_t y, uint32_t num, uint8_t size2, uint8_t len)
    133. {
    134.  uint8_t t, temp;
    135.  uint8_t enshow = 0;
    136.  for (t = 0; t < len; t++)
    137.  {
    138.   temp = (num / rt_oled_pow_t(10, len - t - 1)) % 10;
    139.   if (enshow == 0 && t < (len - 1))
    140.   {
    141.    if (temp == 0)
    142.    {
    143.     rt_oled_showchar_t(rt_oled_type_t, x + (size2 / 2) * t, y, ' ', size2);
    144.     continue;
    145.    }
    146.    else
    147.     enshow = 1;
    148.   }
    149.   rt_oled_showchar_t(rt_oled_type_t, x + (size2 / 2) * t, y, temp + '0', size2);
    150.  }
    151. }
    152. /**
    153.  * @author:小飞哥玩嵌入式-小飞哥
    154.  * @TODO: oled显示一个字符号串
    155.  * @param
    156.  * @return NULL
    157.  */
    158. static void rt_oled_showstring_t(const struct RT_OLED_TYPE *rt_oled_type_tuint8_t x, uint8_t y, uint8_t *chr, uint8_t charsize)
    159. {
    160.  unsigned char j = 0;
    161.  while (chr[j] != '\0')
    162.  {
    163.   rt_oled_showchar_t(rt_oled_type_t, x, y, chr[j], charsize);
    164.   x += 8;
    165.   if (x > 120)
    166.   {
    167.    x = 0;
    168.    y += 2;
    169.   }
    170.   j++;
    171.  }
    172. }
    173. /**
    174.  * @author:小飞哥玩嵌入式-小飞哥
    175.  * @TODO: oled显示汉字
    176.  * @param
    177.  * @return NULL
    178.  */
    179. static void rt_oled_showchinese_t(const struct RT_OLED_TYPE *rt_oled_type_tuint8_t x, uint8_t y, uint8_t no)
    180. {
    181.  uint8_t t, adder = 0;
    182.  rt_oled_setpos_t(rt_oled_type_t, x, y);
    183.  for (t = 0; t < 16; t++)
    184.  {
    185.   rt_oled_write_byte_t(rt_oled_type_t0x78, Hzk[2 * no][t], OLED_DATA);
    186.   adder += 1;
    187.  }
    188.  rt_oled_setpos_t(rt_oled_type_t, x, y + 1);
    189.  for (t = 0; t < 16; t++)
    190.  {
    191.   rt_oled_write_byte_t(rt_oled_type_t0x78, Hzk[2 * no + 1][t], OLED_DATA);
    192.   adder += 1;
    193.  }
    194. }
    195. /**
    196.  * @author:小飞哥玩嵌入式-小飞哥
    197.  * @TODO: 显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7
    198.  * @param
    199.  * @return NULL
    200.  */
    201. static void rt_oled_showbmp_t(const struct RT_OLED_TYPE *rt_oled_type_tuint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, unsigned char BMP[])
    202. {
    203.  unsigned int j = 0;
    204.  unsigned char x, y;
    205.  if (y1 % 8 == 0)
    206.   y = y1 / 8;
    207.  else
    208.   y = y1 / 8 + 1;
    209.  for (y = y0; y < y1; y++)
    210.  {
    211.   rt_oled_setpos_t(rt_oled_type_t, x0, y);
    212.   for (x = x0; x < x1; x++)
    213.   {
    214.    rt_oled_write_byte_t(rt_oled_type_t0x78, BMP[j++], OLED_DATA);
    215.   }
    216.  }
    217. }
    218. /**
    219.  * @author:小飞哥玩嵌入式-小飞哥
    220.  * @TODO: oled写数据或者写命令
    221.  * @param
    222.  * @return NULL
    223.  */
    224. static void rt_oled_fillpicture_t(const struct RT_OLED_TYPE *rt_oled_type_tunsigned char fill_Data)
    225. {
    226.  unsigned char m, n;
    227.  for (m = 0; m < 8; m++)
    228.  {
    229.   rt_oled_write_byte_t(rt_oled_type_t0x780xb0 + m, OLED_CMD);
    230.   rt_oled_write_byte_t(rt_oled_type_t0x780x00, OLED_CMD);
    231.   rt_oled_write_byte_t(rt_oled_type_t0x780x10, OLED_CMD);
    232.   for (n = 0; n < 128; n++)
    233.   {
    234.    rt_oled_write_byte_t(rt_oled_type_t0x78, fill_Data, OLED_DATA);
    235.   }
    236.  }
    237. }
    238. //初始化SSD1306
    239. void rt_oled_init_t(const struct RT_OLED_TYPE *rt_oled_type_t)
    240. {
    241.  rt_oled_type_t->IIC.IIC_Init(&rt_oled_type_t->IIC); // IIC初始化
    242.  HAL_Delay(800);
    243.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xAE, OLED_CMD); //--display off
    244.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x00, OLED_CMD); //---set low column address
    245.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x10, OLED_CMD); //---set high column address
    246.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x40, OLED_CMD); //--set start line address
    247.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xB0, OLED_CMD); //--set page address
    248.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x81, OLED_CMD); // contract control
    249.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xFF, OLED_CMD); //--128
    250.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xA1, OLED_CMD); // set segment remap
    251.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xA6, OLED_CMD); //--normal / reverse
    252.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xA8, OLED_CMD); //--set multiplex ratio(1 to 64)
    253.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x3F, OLED_CMD); //--1/32 duty
    254.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xC8, OLED_CMD); // Com scan direction
    255.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xD3, OLED_CMD); //-set display offset
    256.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x00, OLED_CMD); //
    257.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xD5, OLED_CMD); // set osc division
    258.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x80, OLED_CMD); //
    259.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xD8, OLED_CMD); // set area color mode off
    260.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x05, OLED_CMD); //
    261.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xD9, OLED_CMD); // Set Pre-Charge Period
    262.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xF1, OLED_CMD); //
    263.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xDA, OLED_CMD); // set com pin configuartion
    264.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x12, OLED_CMD); //
    265.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xDB, OLED_CMD); // set Vcomh
    266.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x30, OLED_CMD); //
    267.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x8D, OLED_CMD); // set charge pump enable
    268.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x14, OLED_CMD); //
    269.  rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xAF, OLED_CMD); //--turn on oled panel
    270. }

    实例化OLED对象:

    1. //实例化RT_OLED对象
    2. RT_OLED_TypeDef rt_oled = {
    3.  //操作
    4.  .IIC = {
    5.   .GPIOx_SCL = GPIOB,
    6.   .GPIOx_SDA = GPIOB,
    7.   .GPIO_SCL = OLED_SCL_Pin,
    8.   .GPIO_SDA = OLED_SDA_Pin,
    9.   .IIC_Init = IIC_Init_t,
    10.   .IIC_Start = IIC_Start_t,
    11.   .IIC_Stop = IIC_Stop_t,
    12.   .IIC_Wait_Ack = IIC_Wait_Ack_t,
    13.   .IIC_Ack = IIC_Ack_t,
    14.   .IIC_NAck = IIC_NAck_t,
    15.   .IIC_Send_Byte = IIC_Send_Byte_t,
    16.   .IIC_Read_Byte = IIC_Read_Byte_t,
    17.   .delay_us = delay_us}, // IIC驱动
    18.  .rt_oled_write_byte = rt_oled_write_byte_t,
    19.  .rt_oled_init = rt_oled_init_t,
    20.  .rt_oled_display_on = rt_oled_display_on_t,
    21.  .rt_oled_displayall = rt_oled_displayall_t,
    22.  .rt_oled_showchar = rt_oled_showchar_t,
    23.  .rt_oled_shownum = rt_oled_shownum_t,
    24.  .rt_oled_showstring = rt_oled_showstring_t,
    25.  .rt_oled_showchinese = rt_oled_showchinese_t,
    26.  .rt_oled_showbmp = rt_oled_showbmp_t,
    27.  .rt_oled_fillpicture = rt_oled_fillpicture_t,
    28.  .rt_oled_clear = rt_oled_clear_t
    29.  };

    如何调用?

    对于使用者来讲,面向对象最终要实现的效果是他不需要关注底层驱动,只需要应用层即可,直接调用“类”中的“方法”即可,非常简单

    看看实现效果:

     

    经验交流

    欢迎关注关注小飞哥玩嵌入式!

  • 相关阅读:
    【算法与数据结构】--目录
    java-net-php-python-jsp学生创新项目系统计算机毕业设计程序
    C语言程序设计算法题 -- lab07(1027 - 1030)
    Autovue springboot集成
    AIR32F103(四) 27倍频216MHz,CoreMark跑分测试
    WordPress 安装教程
    传入标签 sql按标签筛选数据 数据必须符合标签
    javaScript:拖拽效果
    MyBatis初级
    野火FPGA入门(4):时序逻辑电路
  • 原文地址:https://blog.csdn.net/qq_16519885/article/details/126311798