上一章节主要介绍了什么怎么样实现C语言面向对象编程,本章节来实战看看如何运用在嵌入式开发中
...有对象的面向她,没对象的,面向我,开课了...,说起面向对象编程,不得不说说面向过程编程
C语言中一般使用面向过程编程,就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步调用,在函数中对数据结构进行处理(执行算法),也就是说数据结构和算法是分开的。
C++语言把数据和算法封装在一起,形成一个整体,无论是对它的属性进行操作、还是对它的行为进行调用,都是通过一个对象来执行,这就是面向对象编程思想(摘自道哥:IOT物联网小镇)。
既然本次要实现面向对象编写OLED驱动,那就要具备上面所说的面向对象的特性,代码较多,大家可以在**文末评论区找到源码链接,直接阅读源码**...
测试平台:STM32G030C8T6
OLED:096寸OLED(IIC接口)
此部分参考:https://blog.csdn.net/weixin_42700740/article/details/113624909
IIC的协议就不多说了,网络上有很多讲的很形象的例子,接下来主要看代码实现就可以了
先定义一个IIC的“类”,主要包含用到的IO,IIC底层驱动函数等
- //定义IIC类
- typedef struct IIC_Type
- {
- //属性
- GPIO_TypeDef *GPIOx_SCL; //GPIO_SCL所属的GPIO组(如:GPIOA)
- GPIO_TypeDef *GPIOx_SDA; //GPIO_SDA所属的GPIO组(如:GPIOA)
- uint32_t GPIO_SCL; //GPIO_SCL的IO引脚(如:GPIO_PIN_0)
- uint32_t GPIO_SDA; //GPIO_SDA的IO引脚(如:GPIO_PIN_0)
- //操作
- void (*IIC_Init)(const struct IIC_Type*); //IIC_Init
- void (*IIC_Start)(const struct IIC_Type*); //IIC_Start
- void (*IIC_Stop)(const struct IIC_Type*); //IIC_Stop
- uint8_t (*IIC_Wait_Ack)(const struct IIC_Type*); //IIC_Wait_ack,返回wait失败或是成功
- void (*IIC_Ack)(const struct IIC_Type*); //IIC_Ack,IIC发送ACK信号
- void (*IIC_NAck)(const struct IIC_Type*); //IIC_NAck,IIC发送NACK信号
- void (*IIC_Send_Byte)(const struct IIC_Type*,uint8_t); //IIC_Send_Byte,入口参数为要发送的字节
- uint8_t (*IIC_Read_Byte)(const struct IIC_Type*,uint8_t); //IIC_Send_Byte,入口参数为是否要发送ACK信号
- void (*delay_us)(uint32_t); //us延时
- }IIC_TypeDef;
-
接下来封装
IO时钟、PIN脚:
- //设置SDA为输入模式
- static void SDA_IN(const struct IIC_Type *IIC_Type_t)
- {
- uint8_t io_num = 0; //定义io Num号
- switch (IIC_Type_t->GPIO_SDA)
- {
- case GPIO_PIN_0:
- io_num = 0;
- break;
- case GPIO_PIN_1:
- io_num = 1;
- break;
- case GPIO_PIN_2:
- io_num = 2;
- break;
- case GPIO_PIN_3:
- io_num = 3;
- break;
- case GPIO_PIN_4:
- io_num = 4;
- break;
- case GPIO_PIN_5:
- io_num = 5;
- break;
- case GPIO_PIN_6:
- io_num = 6;
- break;
- case GPIO_PIN_7:
- io_num = 7;
- break;
- case GPIO_PIN_8:
- io_num = 8;
- break;
- case GPIO_PIN_9:
- io_num = 9;
- break;
- case GPIO_PIN_10:
- io_num = 10;
- break;
- case GPIO_PIN_11:
- io_num = 11;
- break;
- case GPIO_PIN_12:
- io_num = 12;
- break;
- case GPIO_PIN_13:
- io_num = 13;
- break;
- case GPIO_PIN_14:
- io_num = 14;
- break;
- case GPIO_PIN_15:
- io_num = 15;
- break;
- }
- IIC_Type_t->GPIOx_SDA->MODER &= ~(3 << (io_num * 2)); //将GPIOx_SDA->GPIO_SDA清零
- IIC_Type_t->GPIOx_SDA->MODER |= 0 << (io_num * 2); //将GPIOx_SDA->GPIO_SDA设置为输入模式
- }
-
- //设置SDA为输出模式
- static void SDA_OUT(const struct IIC_Type *IIC_Type_t)
- {
- uint8_t io_num = 0; //定义io Num号
- switch (IIC_Type_t->GPIO_SDA)
- {
- case GPIO_PIN_0:
- io_num = 0;
- break;
- case GPIO_PIN_1:
- io_num = 1;
- break;
- case GPIO_PIN_2:
- io_num = 2;
- break;
- case GPIO_PIN_3:
- io_num = 3;
- break;
- case GPIO_PIN_4:
- io_num = 4;
- break;
- case GPIO_PIN_5:
- io_num = 5;
- break;
- case GPIO_PIN_6:
- io_num = 6;
- break;
- case GPIO_PIN_7:
- io_num = 7;
- break;
- case GPIO_PIN_8:
- io_num = 8;
- break;
- case GPIO_PIN_9:
- io_num = 9;
- break;
- case GPIO_PIN_10:
- io_num = 10;
- break;
- case GPIO_PIN_11:
- io_num = 11;
- break;
- case GPIO_PIN_12:
- io_num = 12;
- break;
- case GPIO_PIN_13:
- io_num = 13;
- break;
- case GPIO_PIN_14:
- io_num = 14;
- break;
- case GPIO_PIN_15:
- io_num = 15;
- break;
- }
- IIC_Type_t->GPIOx_SDA->MODER &= ~(3 << (io_num * 2)); //将GPIOx_SDA->GPIO_SDA清零
- IIC_Type_t->GPIOx_SDA->MODER |= 1 << (io_num * 2); //将GPIOx_SDA->GPIO_SDA设置为输出模式
- }
- //设置SCL电平
- static void IIC_SCL(const struct IIC_Type *IIC_Type_t, int n)
- {
- if (n == 1)
- {
- HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL, IIC_Type_t->GPIO_SCL, GPIO_PIN_SET); //设置SCL为高电平
- }
- else
- {
- HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL, IIC_Type_t->GPIO_SCL, GPIO_PIN_RESET); //设置SCL为低电平
- }
- }
- //设置SDA电平
- static void IIC_SDA(const struct IIC_Type *IIC_Type_t, int n)
- {
- if (n == 1)
- {
- HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA, IIC_Type_t->GPIO_SDA, GPIO_PIN_SET); //设置SDA为高电平
- }
- else
- {
- HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA, IIC_Type_t->GPIO_SDA, GPIO_PIN_RESET); //设置SDA为低电平
- }
- }
- //读取SDA电平
- static uint8_t READ_SDA(const struct IIC_Type *IIC_Type_t)
- {
- return HAL_GPIO_ReadPin(IIC_Type_t->GPIOx_SDA, IIC_Type_t->GPIO_SDA); //读取SDA电平
- }
- // IIC初始化
- void IIC_Init_t(const struct IIC_Type *IIC_Type_t)
- {
- GPIO_InitTypeDef GPIO_Initure;
-
- //根据GPIO组初始化GPIO时钟
- if (IIC_Type_t->GPIOx_SCL == GPIOA || IIC_Type_t->GPIOx_SDA == GPIOA)
- {
- __HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟
- }
- if (IIC_Type_t->GPIOx_SCL == GPIOB || IIC_Type_t->GPIOx_SDA == GPIOB)
- {
- __HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB时钟
- }
- if (IIC_Type_t->GPIOx_SCL == GPIOC || IIC_Type_t->GPIOx_SDA == GPIOC)
- {
- __HAL_RCC_GPIOC_CLK_ENABLE(); //使能GPIOC时钟
- }
- if (IIC_Type_t->GPIOx_SCL == GPIOD || IIC_Type_t->GPIOx_SDA == GPIOD)
- {
- __HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD时钟
- }
-
- // GPIO_SCL初始化设置
- GPIO_Initure.Pin = IIC_Type_t->GPIO_SCL;
- GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出
- GPIO_Initure.Pull = GPIO_PULLUP; //上拉
- GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; //快速
- HAL_GPIO_Init(IIC_Type_t->GPIOx_SCL, &GPIO_Initure);
- // GPIO_SDA初始化设置
- GPIO_Initure.Pin = IIC_Type_t->GPIO_SDA;
- GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出
- GPIO_Initure.Pull = GPIO_PULLUP; //上拉
- GPIO_Initure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; //快速
- HAL_GPIO_Init(IIC_Type_t->GPIOx_SDA, &GPIO_Initure);
-
- // SCL与SDA的初始化均为高电平
- IIC_SCL(IIC_Type_t, 1);
- IIC_SDA(IIC_Type_t, 1);
- }
-
起始信号:
- // IIC Start
- void IIC_Start_t(const struct IIC_Type *IIC_Type_t)
- {
- SDA_OUT(IIC_Type_t); // sda线输出
- IIC_SDA(IIC_Type_t, 1);
- IIC_SCL(IIC_Type_t, 1);
- IIC_Type_t->delay_us(4);
- IIC_SDA(IIC_Type_t, 0); // START:when CLK is high,DATA change form high to low
- IIC_Type_t->delay_us(4);
- IIC_SCL(IIC_Type_t, 0); //钳住I2C总线,准备发送或接收数据
- }
停止信号:
- // IIC Stop
- void IIC_Stop_t(const struct IIC_Type *IIC_Type_t)
- {
- SDA_OUT(IIC_Type_t); // sda线输出
- IIC_SCL(IIC_Type_t, 0);
- IIC_SDA(IIC_Type_t, 0); // STOP:when CLK is high DATA change form low to high
- IIC_Type_t->delay_us(4);
- IIC_SCL(IIC_Type_t, 1);
- IIC_SDA(IIC_Type_t, 1); //发送I2C总线结束信号
- IIC_Type_t->delay_us(4);
- }
等待应答信号:
- // IIC_Wait_ack 返回HAL_OK表示wait成功,返回HAL_ERROR表示wait失败
- uint8_t IIC_Wait_Ack_t(const struct IIC_Type *IIC_Type_t) // IIC_Wait_ack,返回wait失败或是成功
- {
- uint8_t ucErrTime = 0;
- SDA_IN(IIC_Type_t); // SDA设置为输入
- IIC_SDA(IIC_Type_t, 1);
- IIC_Type_t->delay_us(1);
- IIC_SCL(IIC_Type_t, 1);
- IIC_Type_t->delay_us(1);
- while (READ_SDA(IIC_Type_t))
- {
- ucErrTime++;
- if (ucErrTime > 250)
- {
- IIC_Type_t->IIC_Stop(IIC_Type_t);
- return HAL_ERROR;
- }
- }
- IIC_SCL(IIC_Type_t, 0); //时钟输出0
- return HAL_OK;
- }
产生ACK信号:
- //产生ACK应答
- void IIC_Ack_t(const struct IIC_Type *IIC_Type_t)
- {
- IIC_SCL(IIC_Type_t, 0);
- SDA_OUT(IIC_Type_t);
- IIC_SDA(IIC_Type_t, 0);
- IIC_Type_t->delay_us(2);
- IIC_SCL(IIC_Type_t, 1);
- IIC_Type_t->delay_us(2);
- IIC_SCL(IIC_Type_t, 0);
- }
产生NACK信号:
- //产生NACK应答
- void IIC_NAck_t(const struct IIC_Type *IIC_Type_t)
- {
- IIC_SCL(IIC_Type_t, 0);
- SDA_OUT(IIC_Type_t);
- IIC_SDA(IIC_Type_t, 1);
- IIC_Type_t->delay_us(2);
- IIC_SCL(IIC_Type_t, 1);
- IIC_Type_t->delay_us(2);
- IIC_SCL(IIC_Type_t, 0);
- }
发送一字节:
- // IIC_Send_Byte,入口参数为要发送的字节
- void IIC_Send_Byte_t(const struct IIC_Type *IIC_Type_t, uint8_t txd)
- {
- uint8_t t = 0;
- SDA_OUT(IIC_Type_t);
- IIC_SCL(IIC_Type_t, 0); //拉低时钟开始数据传输
- for (t = 0; t < 8; t++)
- {
- IIC_SDA(IIC_Type_t, (txd & 0x80) >> 7);
- txd <<= 1;
- IIC_Type_t->delay_us(2); //对TEA5767这三个延时都是必须的
- IIC_SCL(IIC_Type_t, 1);
- IIC_Type_t->delay_us(2);
- IIC_SCL(IIC_Type_t, 0);
- IIC_Type_t->delay_us(2);
- }
- }
读取一字节:
- uint8_t IIC_Read_Byte_t(const struct IIC_Type *IIC_Type_t, uint8_t ack)
- {
- uint8_t i, receive = 0;
- SDA_IN(IIC_Type_t); // SDA设置为输入
- for (i = 0; i < 8; i++)
- {
- IIC_SCL(IIC_Type_t, 0);
- IIC_Type_t->delay_us(2);
- IIC_SCL(IIC_Type_t, 1);
- receive <<= 1;
- if (READ_SDA(IIC_Type_t))
- receive++;
- IIC_Type_t->delay_us(1);
- }
- if (!ack)
- IIC_Type_t->IIC_NAck(IIC_Type_t); //发送nACK
- else
- IIC_Type_t->IIC_Ack(IIC_Type_t); //发送ACK
- return receive;
- }
最后,来实例化一个“对象”,主要包含了供外部调用的一些成员,对于外部用户来说,他只需要关注这个结构体里面的成员,而不需要去关注内部如何实现的
- //实例化一个IIC1外设,相当于一个结构体变量,可以直接在其他文件中使用
- IIC_TypeDef IIC1 = {
- .GPIOx_SCL = GPIOB, // GPIO组为GPIOB
- .GPIOx_SDA = GPIOB, // GPIO组为GPIOB
- .GPIO_SCL = GPIO_PIN_9, // GPIO为PIN9
- .GPIO_SDA = GPIO_PIN_8, // GPIO为PIN8
- .IIC_Init = IIC_Init_t,
- .IIC_Start = IIC_Start_t,
- .IIC_Stop = IIC_Stop_t,
- .IIC_Wait_Ack = IIC_Wait_Ack_t,
- .IIC_Ack = IIC_Ack_t,
- .IIC_NAck = IIC_NAck_t,
- .IIC_Send_Byte = IIC_Send_Byte_t,
- .IIC_Read_Byte = IIC_Read_Byte_t,
- .delay_us = delay_us //需自己外部实现delay_us函数
- };
依然是先封装一个“OLED类”
- //定义RT_OLED类
- typedef struct RT_OLED_TYPE
- {
- //操作
- IIC_TypeDef IIC; //IIC驱动
-
- void (*rt_oled_write_byte)(const struct RT_OLED_TYPE*,uint8_t,uint8_t,uint8_t);
- void (*rt_oled_init)(const struct RT_OLED_TYPE*);
- void (*rt_oled_display_on)(const struct RT_OLED_TYPE*,uint8_t);
- void (*rt_oled_clear)(const struct RT_OLED_TYPE*);
- void (*rt_oled_displayall)(const struct RT_OLED_TYPE*);
- void (*rt_oled_showchar)(const struct RT_OLED_TYPE*,uint8_t,uint8_t,uint8_t,uint8_t);
- void (*rt_oled_shownum)(const struct RT_OLED_TYPE*,uint8_t,uint8_t,uint32_t,uint8_t,uint8_t);
- void (*rt_oled_showstring)(const struct RT_OLED_TYPE*,uint8_t,uint8_t,uint8_t *,uint8_t);
- void (*rt_oled_showchinese)(const struct RT_OLED_TYPE*,uint8_t,uint8_t,uint8_t);
- void (*rt_oled_showbmp)(const struct RT_OLED_TYPE*,uint8_t,uint8_t,uint8_t,uint8_t,unsigned char *);
- void (*rt_oled_fillpicture)(const struct RT_OLED_TYPE*,unsigned char);
- }RT_OLED_TypeDef;
-
- extern RT_OLED_TypeDef rt_oled; //外部声明实例化RT_OLED对象
写数据、命令封装:
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled写数据
- * @param
- * @return NULL
- */
- static void rt_oled_write_data_t(const struct RT_OLED_TYPE *rt_oled_type_t, uint8_t chipid, uint8_t dat)
- {
- rt_oled_type_t->IIC.IIC_Start(&rt_oled_type_t->IIC);
- rt_oled_type_t->IIC.IIC_Send_Byte(&rt_oled_type_t->IIC, chipid); // D/C#=0; R/W#=0
- rt_oled_type_t->IIC.IIC_Ack(&rt_oled_type_t->IIC);
- rt_oled_type_t->IIC.IIC_Send_Byte(&rt_oled_type_t->IIC, 0x40);
- rt_oled_type_t->IIC.IIC_Ack(&rt_oled_type_t->IIC);
- rt_oled_type_t->IIC.IIC_Send_Byte(&rt_oled_type_t->IIC, dat);
- rt_oled_type_t->IIC.IIC_Ack(&rt_oled_type_t->IIC);
- rt_oled_type_t->IIC.IIC_Stop(&rt_oled_type_t->IIC);
- }
-
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled写命令
- * @param
- * @return NULL
- */
- static void rt_oled_write_cmd_t(const struct RT_OLED_TYPE *rt_oled_type_t, uint8_t chipid, uint8_t cmd)
- {
- rt_oled_type_t->IIC.IIC_Start(&rt_oled_type_t->IIC);
- rt_oled_type_t->IIC.IIC_Send_Byte(&rt_oled_type_t->IIC, chipid); // D/C#=0; R/W#=0
- rt_oled_type_t->IIC.IIC_Ack(&rt_oled_type_t->IIC);
- rt_oled_type_t->IIC.IIC_Send_Byte(&rt_oled_type_t->IIC, 0x00);
- rt_oled_type_t->IIC.IIC_Ack(&rt_oled_type_t->IIC);
- rt_oled_type_t->IIC.IIC_Send_Byte(&rt_oled_type_t->IIC, cmd);
- rt_oled_type_t->IIC.IIC_Ack(&rt_oled_type_t->IIC);
- rt_oled_type_t->IIC.IIC_Stop(&rt_oled_type_t->IIC);
- }
-
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled写数据或者写命令
- * @param
- * @return NULL
- */
- static void rt_oled_write_byte_t(const struct RT_OLED_TYPE *rt_oled_type_t, uint8_t chipid, uint8_t dat, uint8_t cmd)
- {
- if (cmd) //写数据
- {
- rt_oled_write_data_t(rt_oled_type_t, chipid, dat);
- }
- else //写命令
- {
- rt_oled_write_cmd_t(rt_oled_type_t, chipid, dat);
- }
- }
接下来是一些对OLED的显示操作,就不一一介绍了:
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled坐标设置
- * @param
- * @return NULL
- */
-
- static void rt_oled_setpos_t(const struct RT_OLED_TYPE *rt_oled_type_t, uint8_t x, uint8_t y)
- {
-
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0xb0 + y, OLED_CMD);
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, ((x & 0xf0) >> 4) | 0x10, OLED_CMD);
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, (x & 0x0f), OLED_CMD);
- }
-
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled显示开关
- * @param
- * @return NULL
- */
-
- static void rt_oled_display_on_t(const struct RT_OLED_TYPE *rt_oled_type_t, uint8_t ON)
- {
- if (ON)
- {
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0X8D, OLED_CMD);
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0X14, OLED_CMD);
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0XAF, OLED_CMD);
- }
- else
- {
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0X8D, OLED_CMD);
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0X14, OLED_CMD);
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0XAE, OLED_CMD);
- }
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled清屏
- * @param
- * @return NULL
- */
- static void rt_oled_clear_t(const struct RT_OLED_TYPE *rt_oled_type_t)
- {
- uint8_t i, n;
- for (i = 0; i < 8; i++)
- {
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0xb0 + i, OLED_CMD);
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0x00, OLED_CMD);
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0x10, OLED_CMD);
-
- for (n = 0; n < 128; n++)
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0, OLED_DATA);
- } //更新显示
- }
-
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled全显示
- * @param
- * @return NULL
- */
- static void rt_oled_displayall_t(const struct RT_OLED_TYPE *rt_oled_type_t)
- {
- uint8_t i, n;
- for (i = 0; i < 8; i++)
- {
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0xb0 + i, OLED_CMD);
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0x00, OLED_CMD);
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0x10, OLED_CMD);
-
- for (n = 0; n < 128; n++)
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 1, OLED_DATA);
- } //更新显示
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled显示一个字符
- * @param
- * @return NULL
- */
- static void rt_oled_showchar_t(const struct RT_OLED_TYPE *rt_oled_type_t, uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size)
- {
- unsigned char c = 0, i = 0;
- c = chr - ' '; //得到偏移后的值
-
- if (x > Max_Column - 1)
- {
- x = 0;
- y = y + 2;
- }
-
- if (Char_Size == 16)
- {
- rt_oled_setpos_t(rt_oled_type_t, x, y);
- for (i = 0; i < 8; i++)
- {
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, F8X16[c * 16 + i], OLED_DATA);
- }
- rt_oled_setpos_t(rt_oled_type_t, x, y + 1);
-
- for (i = 0; i < 8; i++)
- {
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, F8X16[c * 16 + i + 8], OLED_DATA);
- }
- }
- else
- {
- rt_oled_setpos_t(rt_oled_type_t, x, y);
- for (i = 0; i < 6; i++)
- {
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, F6x8[c][i], OLED_DATA);
- }
- }
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled m^n
- * @param
- * @return NULL
- */
- static uint32_t rt_oled_pow_t(uint8_t m, uint8_t n)
- {
- uint32_t result = 1;
- while (n--)
- result *= m;
- return result;
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled显示一个字符
- * @param
- * @return NULL
- //显示2个数字
- //x,y :起点坐标
- //len :数字的位数
- //size:字体大小
- //mode:模式 0,填充模式;1,叠加模式
- //num:数值(0~4294967295);
- */
- static void rt_oled_shownum_t(const struct RT_OLED_TYPE *rt_oled_type_t, uint8_t x, uint8_t y, uint32_t num, uint8_t size2, uint8_t len)
- {
- uint8_t t, temp;
- uint8_t enshow = 0;
- for (t = 0; t < len; t++)
- {
- temp = (num / rt_oled_pow_t(10, len - t - 1)) % 10;
- if (enshow == 0 && t < (len - 1))
- {
- if (temp == 0)
- {
- rt_oled_showchar_t(rt_oled_type_t, x + (size2 / 2) * t, y, ' ', size2);
- continue;
- }
- else
- enshow = 1;
- }
- rt_oled_showchar_t(rt_oled_type_t, x + (size2 / 2) * t, y, temp + '0', size2);
- }
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled显示一个字符号串
- * @param
- * @return NULL
- */
- static void rt_oled_showstring_t(const struct RT_OLED_TYPE *rt_oled_type_t, uint8_t x, uint8_t y, uint8_t *chr, uint8_t charsize)
- {
- unsigned char j = 0;
- while (chr[j] != '\0')
- {
- rt_oled_showchar_t(rt_oled_type_t, x, y, chr[j], charsize);
- x += 8;
- if (x > 120)
- {
- x = 0;
- y += 2;
- }
- j++;
- }
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled显示汉字
- * @param
- * @return NULL
- */
- static void rt_oled_showchinese_t(const struct RT_OLED_TYPE *rt_oled_type_t, uint8_t x, uint8_t y, uint8_t no)
- {
- uint8_t t, adder = 0;
- rt_oled_setpos_t(rt_oled_type_t, x, y);
- for (t = 0; t < 16; t++)
- {
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, Hzk[2 * no][t], OLED_DATA);
- adder += 1;
- }
- rt_oled_setpos_t(rt_oled_type_t, x, y + 1);
- for (t = 0; t < 16; t++)
- {
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, Hzk[2 * no + 1][t], OLED_DATA);
- adder += 1;
- }
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: 显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7
- * @param
- * @return NULL
- */
- static void rt_oled_showbmp_t(const struct RT_OLED_TYPE *rt_oled_type_t, uint8_t x0, uint8_t y0, uint8_t x1, uint8_t 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++)
- {
- rt_oled_setpos_t(rt_oled_type_t, x0, y);
- for (x = x0; x < x1; x++)
- {
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, BMP[j++], OLED_DATA);
- }
- }
- }
- /**
- * @author:小飞哥玩嵌入式-小飞哥
- * @TODO: oled写数据或者写命令
- * @param
- * @return NULL
- */
- static void rt_oled_fillpicture_t(const struct RT_OLED_TYPE *rt_oled_type_t, unsigned char fill_Data)
- {
- unsigned char m, n;
- for (m = 0; m < 8; m++)
- {
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0xb0 + m, OLED_CMD);
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0x00, OLED_CMD);
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, 0x10, OLED_CMD);
-
- for (n = 0; n < 128; n++)
- {
- rt_oled_write_byte_t(rt_oled_type_t, 0x78, fill_Data, OLED_DATA);
- }
- }
- }
-
- //初始化SSD1306
- void rt_oled_init_t(const struct RT_OLED_TYPE *rt_oled_type_t)
- {
- rt_oled_type_t->IIC.IIC_Init(&rt_oled_type_t->IIC); // IIC初始化
-
- HAL_Delay(800);
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xAE, OLED_CMD); //--display off
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x00, OLED_CMD); //---set low column address
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x10, OLED_CMD); //---set high column address
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x40, OLED_CMD); //--set start line address
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xB0, OLED_CMD); //--set page address
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x81, OLED_CMD); // contract control
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xFF, OLED_CMD); //--128
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xA1, OLED_CMD); // set segment remap
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xA6, OLED_CMD); //--normal / reverse
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xA8, OLED_CMD); //--set multiplex ratio(1 to 64)
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x3F, OLED_CMD); //--1/32 duty
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xC8, OLED_CMD); // Com scan direction
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xD3, OLED_CMD); //-set display offset
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x00, OLED_CMD); //
-
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xD5, OLED_CMD); // set osc division
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x80, OLED_CMD); //
-
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xD8, OLED_CMD); // set area color mode off
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x05, OLED_CMD); //
-
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xD9, OLED_CMD); // Set Pre-Charge Period
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xF1, OLED_CMD); //
-
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xDA, OLED_CMD); // set com pin configuartion
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x12, OLED_CMD); //
-
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xDB, OLED_CMD); // set Vcomh
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x30, OLED_CMD); //
-
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x8D, OLED_CMD); // set charge pump enable
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0x14, OLED_CMD); //
-
- rt_oled_write_byte_t(rt_oled_type_t, CHIPID, 0xAF, OLED_CMD); //--turn on oled panel
- }
实例化OLED对象:
- //实例化RT_OLED对象
- RT_OLED_TypeDef rt_oled = {
- //操作
- .IIC = {
- .GPIOx_SCL = GPIOB,
- .GPIOx_SDA = GPIOB,
- .GPIO_SCL = OLED_SCL_Pin,
- .GPIO_SDA = OLED_SDA_Pin,
- .IIC_Init = IIC_Init_t,
- .IIC_Start = IIC_Start_t,
- .IIC_Stop = IIC_Stop_t,
- .IIC_Wait_Ack = IIC_Wait_Ack_t,
- .IIC_Ack = IIC_Ack_t,
- .IIC_NAck = IIC_NAck_t,
- .IIC_Send_Byte = IIC_Send_Byte_t,
- .IIC_Read_Byte = IIC_Read_Byte_t,
- .delay_us = delay_us}, // IIC驱动
- .rt_oled_write_byte = rt_oled_write_byte_t,
- .rt_oled_init = rt_oled_init_t,
- .rt_oled_display_on = rt_oled_display_on_t,
- .rt_oled_displayall = rt_oled_displayall_t,
- .rt_oled_showchar = rt_oled_showchar_t,
- .rt_oled_shownum = rt_oled_shownum_t,
- .rt_oled_showstring = rt_oled_showstring_t,
- .rt_oled_showchinese = rt_oled_showchinese_t,
- .rt_oled_showbmp = rt_oled_showbmp_t,
- .rt_oled_fillpicture = rt_oled_fillpicture_t,
- .rt_oled_clear = rt_oled_clear_t
- };
对于使用者来讲,面向对象最终要实现的效果是他不需要关注底层驱动,只需要应用层即可,直接调用“类”中的“方法”即可,非常简单

看看实现效果:

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