上一章节主要介绍了什么怎么样实现C语言面向对象编程,本章节来实战看看如何运用在嵌入式开发
面向对象
...有对象的面向她,没对象的,面向我,开课了...,说起面向对象编程,不得不说说面向过程编程
C语言中一般使用面向过程编程,就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步调用,在函数中对数据结构进行处理(执行算法),也就是说数据结构和算法是分开的。
C 语言把数据和算法封装在一起,形成一个整体,无论是对它的属性进行操作、还是对它的行为进行调用,都是通过一个对象来执行,这就是面向对象编程思想(摘自道哥:IOT物联网小镇)。
既然本次要实现面向对象编写OLED驱动,那就要具备上面所说的面向对象的特性,代码较多,大家可以在文末评论区找到源码链接,直接阅读源码...
IIC底层驱动封装
- 测试平台:STM32G030C8T6
- OLED:096寸OLED(IIC接口)
此部分参考:https://blog.csdn.net/weixin_42700740/article/details/113624909
IIC的协议就不多说了,网络上有很多讲的很形象的例子,接下来主要看代码实现就可以了
先定义一个IIC的“类”,主要包含用到的IO,IIC底层驱动函数等
代码语言:javascript复制//定义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脚:
代码语言:javascript复制//设置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);
}
起始信号:
代码语言:javascript复制// 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总线,准备发送或接收数据
}
停止信号:
代码语言:javascript复制// 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);
}
等待应答信号:
代码语言:javascript复制// 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信号:
代码语言:javascript复制//产生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信号:
代码语言:javascript复制//产生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);
}
发送一字节:
代码语言:javascript复制// 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);
}
}
读取一字节:
代码语言:javascript复制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;
}
最后,来实例化一个“对象”,主要包含了供外部调用的一些成员,对于外部用户来说,他只需要关注这个结构体里面的成员,而不需要去关注内部如何实现的
代码语言:javascript复制//实例化一个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封装
依然是先封装一个“OLED类”
代码语言:javascript复制//定义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对象
写数据、命令封装:
代码语言:javascript复制/**
* @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的显示操作,就不一一介绍了:
代码语言:javascript复制/**
* @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] != '