#申请原创#
一、简介
使用面向的编程思想封装I2C驱动,将I2C属性、操作封装成库,在需要创建一个I2C设备时只需要实例化一个I2C对象,本文基于AT32F425和标准库做进一步封装。完成I2C驱动的封装后,依据继承特性实现OLED液晶屏的驱动开发及封装。
二、I2C驱动面向对象封装
hal_i2c.h头文件类定义如下:
#ifndef __HAL_I2C_H__
#define __HAL_I2C_H__
#include "at32f425.h"
#define HAL_ERROR 0
#define HAL_OK 1
//定义I2C类
typedef struct I2C_Type
{
//属性
gpio_type *GPIOx_SCL; //SCL所属gpio组,如:GPIOA
gpio_type *GPIOx_SDA; //SDA所属gpio组,如:GPIOA
unsigned int GPIO_SCL; //SCL引脚,如:GPIO_PINS_2
unsigned int GPIO_SDA; //SDA引脚,如:GPIO_PINS_2
//操作
void (*I2C_Init)(const struct I2C_Type*);
void (*I2C_Start)(const struct I2C_Type*);
void (*I2C_Stop)(const struct I2C_Type*);
unsigned char (*I2C_Wait_Ack)(const struct I2C_Type*);
void (*I2C_Ack)(const struct I2C_Type*);
void (*I2C_NAck)(const struct I2C_Type*);
void (*I2C_Send_Byte)(const struct I2C_Type*, unsigned char);
unsigned char (*I2C_Read_Byte)(const struct I2C_Type*, unsigned char);
void (*delay_us)(unsigned int);
} I2C_TypeDef;
extern I2C_TypeDef I2C_t;
#endif
hal_i2c.c文件具体操作函数如下:
#include "hal_i2c.h"
#include "delay.h"
//设置SDA输入模式
static void SDA_IN(const struct I2C_Type* I2C_Type_t)
{
gpio_init_type gpio_init_struct;
//GPIO_SDA初始化设置
gpio_init_struct.gpio_pins = I2C_Type_t->GPIO_SDA;
gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(I2C_Type_t->GPIOx_SDA, &gpio_init_struct);
}
//设置SDA为输出模式
static void SDA_OUT(const struct I2C_Type* I2C_Type_t)
{
gpio_init_type gpio_init_struct;
//GPIO_SDA初始化设置
gpio_init_struct.gpio_pins = I2C_Type_t->GPIO_SDA;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(I2C_Type_t->GPIOx_SDA, &gpio_init_struct);
}
//设置SCL电平
static void I2C_SCL(const struct I2C_Type* I2C_Type_t, int n)
{
if(n == 1)
{
gpio_bits_write(I2C_Type_t->GPIOx_SCL, I2C_Type_t->GPIO_SCL, TRUE); //设置SCL为高电平
}
else
{
gpio_bits_write(I2C_Type_t->GPIOx_SCL, I2C_Type_t->GPIO_SCL, FALSE); //设置SCL为低电平
}
}
//设置SDA电平
static void I2C_SDA(const struct I2C_Type* I2C_Type_t, int n)
{
if(n == 1)
{
gpio_bits_write(I2C_Type_t->GPIOx_SDA, I2C_Type_t->GPIO_SDA, TRUE); //设置SDA为高电平
}
else
{
gpio_bits_write(I2C_Type_t->GPIOx_SDA, I2C_Type_t->GPIO_SDA, FALSE); //设置SDA为低电平
}
}
//读取SDA电平
static unsigned char READ_SDA(const struct I2C_Type* I2C_Type_t)
{
return gpio_input_data_bit_read(I2C_Type_t->GPIOx_SDA, I2C_Type_t->GPIO_SDA); //读取SDA电平
}
//I2C初始化
static void I2C_Init_t(const struct I2C_Type* I2C_Type_t)
{
gpio_init_type gpio_init_struct;
//根据GPIO组初始化GPIO时钟
if(I2C_Type_t->GPIOx_SCL == GPIOA || I2C_Type_t->GPIOx_SDA == GPIOA)
{
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE); //使能GPIOA时钟
}
if(I2C_Type_t->GPIOx_SCL == GPIOB || I2C_Type_t->GPIOx_SDA == GPIOB)
{
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE); //使能GPIOB时钟
}
if(I2C_Type_t->GPIOx_SCL == GPIOC || I2C_Type_t->GPIOx_SDA == GPIOC)
{
crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE); //使能GPIOC时钟
}
if(I2C_Type_t->GPIOx_SCL == GPIOD || I2C_Type_t->GPIOx_SDA == GPIOD)
{
crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE); //使能GPIOD时钟
}
if(I2C_Type_t->GPIOx_SCL == GPIOF || I2C_Type_t->GPIOx_SDA == GPIOF)
{
crm_periph_clock_enable(CRM_GPIOF_PERIPH_CLOCK, TRUE); //使能GPIOF时钟
}
//GPIO_SCL初始化设置
gpio_init_struct.gpio_pins = I2C_Type_t->GPIO_SCL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT; //gpio output mode
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN; //output open-drain
gpio_init_struct.gpio_pull = GPIO_PULL_UP; //pull-up
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; //stronger sourcing/sinking strength
gpio_init(I2C_Type_t->GPIOx_SCL, &gpio_init_struct);
//GPIO_SDA初始化设置
gpio_init_struct.gpio_pins = I2C_Type_t->GPIO_SDA;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN; //output open-drain
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(I2C_Type_t->GPIOx_SDA, &gpio_init_struct);
//SCL、SDA的初始化均为高电平
I2C_SCL(I2C_Type_t, 1);
I2C_SDA(I2C_Type_t, 1);
}
//I2C Start
static void I2C_Start_t(const struct I2C_Type* I2C_Type_t)
{
SDA_OUT(I2C_Type_t);
I2C_SDA(I2C_Type_t, 1);
I2C_SCL(I2C_Type_t, 1);
I2C_Type_t->delay_us(4);
I2C_SDA(I2C_Type_t, 0); //START:when CLK is high,DATA change form high to low
I2C_Type_t->delay_us(4);
I2C_SCL(I2C_Type_t, 0); //钳住I2C总线,准备发送或接收数据
}
//I2C Stop
static void I2C_Stop_t(const struct I2C_Type* I2C_Type_t)
{
SDA_OUT(I2C_Type_t);
I2C_SCL(I2C_Type_t, 0);
I2C_SDA(I2C_Type_t, 0); //STOP:when CLK is high DATA change form low to high
I2C_Type_t->delay_us(4);
I2C_SCL(I2C_Type_t, 1);
I2C_SDA(I2C_Type_t, 1); //发送I2C总线结束信号
I2C_Type_t->delay_us(4);
}
//I2C_Wait_ack 返回HAL_OK表示wait成功,返回HAL_ERROR表示wait失败
static unsigned char I2C_Wait_Ack_t(const struct I2C_Type* I2C_Type_t) //IIC_Wait_ack,返回wait失败或是成功
{
unsigned char ucErrTime = 0;
SDA_IN(I2C_Type_t);
I2C_SDA(I2C_Type_t, 1);
I2C_Type_t->delay_us(1);
I2C_SCL(I2C_Type_t, 1);
I2C_Type_t->delay_us(1);
while(READ_SDA(I2C_Type_t))
{
ucErrTime++;
if(ucErrTime > 250)
{
I2C_Type_t->I2C_Stop(I2C_Type_t);
return HAL_ERROR;
}
}
I2C_SCL(I2C_Type_t, 0);
return HAL_OK;
}
//产生ACK应答
static void I2C_Ack_t(const struct I2C_Type* I2C_Type_t)
{
I2C_SCL(I2C_Type_t, 0);
SDA_OUT(I2C_Type_t);
I2C_SDA(I2C_Type_t, 0);
I2C_Type_t->delay_us(2);
I2C_SCL(I2C_Type_t, 1);
I2C_Type_t->delay_us(2);
I2C_SCL(I2C_Type_t, 0);
}
//产生NACK应答
static void I2C_NAck_t(const struct I2C_Type* I2C_Type_t)
{
I2C_SCL(I2C_Type_t, 0);
SDA_OUT(I2C_Type_t);
I2C_SDA(I2C_Type_t, 1);
I2C_Type_t->delay_us(2);
I2C_SCL(I2C_Type_t, 1);
I2C_Type_t->delay_us(2);
I2C_SCL(I2C_Type_t, 0);
}
//I2C_Send_Byte,入口参数为要发送的字节
static void I2C_Send_Byte_t(const struct I2C_Type* I2C_Type_t, unsigned char txd)
{
unsigned char cnt = 0;
SDA_OUT(I2C_Type_t);
I2C_SCL(I2C_Type_t, 0);
for(cnt = 0; cnt < 8; cnt++)
{
I2C_SDA(I2C_Type_t, (txd & 0x80) >> 7);
txd <<= 1;
//I2C_Type_t->delay_us(2); //OLED显示刷新慢,取消延时
I2C_SCL(I2C_Type_t, 1);
//I2C_Type_t->delay_us(2);
I2C_SCL(I2C_Type_t, 0);
//I2C_Type_t->delay_us(2);
}
}
//I2C_Read_Byte,入口参数为是否要发送ACK信号
static unsigned char I2C_Read_Byte_t(const struct I2C_Type* I2C_Type_t, unsigned char ack)
{
unsigned char cnt, rec = 0;
SDA_IN(I2C_Type_t);
for(cnt = 0; cnt < 8; cnt++)
{
I2C_SCL(I2C_Type_t, 0);
//I2C_Type_t->delay_us(2);
I2C_SCL(I2C_Type_t, 1);
rec <<= 1;
if(READ_SDA(I2C_Type_t))
{
rec++;
}
//I2C_Type_t->delay_us(1);
}
if(!ack)
{
I2C_Type_t->I2C_NAck(I2C_Type_t);
}
else
{
I2C_Type_t->I2C_Ack(I2C_Type_t);
}
return rec;
}
//实例化一个I2C外设,相当于一个结构体变量,可以直接在其他文件中使用
I2C_TypeDef I2C_t =
{
.GPIOx_SCL = GPIOF, //GPIO组为GPIOF
.GPIOx_SDA = GPIOF, //GPIO组为GPIOF
.GPIO_SCL = GPIO_PINS_5, //GPIO为PIN5
.GPIO_SDA = GPIO_PINS_4, //GPIO为PIN4
.I2C_Init = I2C_Init_t,
.I2C_Start = I2C_Start_t,
.I2C_Stop = I2C_Stop_t,
.I2C_Wait_Ack = I2C_Wait_Ack_t,
.I2C_Ack = I2C_Ack_t,
.I2C_NAck = I2C_NAck_t,
.I2C_Send_Byte = I2C_Send_Byte_t,
.I2C_Read_Byte = I2C_Read_Byte_t,
.delay_us = Delay_Us, //需自己外部实现delay_us函数
};
三、0.96OLED驱动封装
hal_0.96oled.h头文件类定义如下:
#ifndef __HAL_096OLED_H__
#define __HAL_096OLED_H__
#include "hal_i2c.h"
//定义0.96OLED类
typedef struct OLED_Type
{
//属性
//操作
I2C_TypeDef *I2C; //
void (*OLED_Write_CMD)(const struct OLED_Type*, unsigned char); //向设备写命令
void (*OLED_Write_Date)(const struct OLED_Type*, unsigned char); //向设备写数据
void (*OLED_Set_Pos)(const struct OLED_Type*, unsigned char, unsigned char); //坐标设置
void (*OLED_Display_On)(const struct OLED_Type*); //开启OLED显示
void (*OLED_Display_Off)(const struct OLED_Type*); //关闭OLED显示
void (*OLED_Clear)(const struct OLED_Type*); //OLED清屏
void (*OLED_Clear_Row)(const struct OLED_Type*, unsigned char); //OLED清行
void (*OLED_Fill)(const struct OLED_Type*); //OLED填满屏幕
void (*OLED_ShowChar)(const struct OLED_Type*, unsigned char, unsigned char, unsigned char, unsigned char); //指定位置显示一个字符
void (*OLED_ShowNum)(const struct OLED_Type*, unsigned char, unsigned char, unsigned int, unsigned char, unsigned char); //指定位置显示数字
void (*OLED_ShowString)(const struct OLED_Type*, unsigned char, unsigned char, unsigned char*, unsigned char); //指定位置显示字符串
void (*OLED_ShowCHinese)(const struct OLED_Type*, unsigned char, unsigned char, unsigned char); //显示汉字
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[]); //显示图片
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]); //显示动画
void (*OLED_Init)(const struct OLED_Type*); //初始化OLED
} OLED_TypeDef;
extern OLED_TypeDef _0_96OLED;
#endif
hal_0.96oled.c文件具体操作函数如下:
#include "hal_0.96oled.h"
#include "oledfont.h"
#include "delay.h"
//向设备写控制命令
static void OLED_Write_CMD_t(const struct OLED_Type* OLED_Type_t, unsigned char cmd)
{
OLED_Type_t->I2C->I2C_Start(OLED_Type_t->I2C);
OLED_Type_t->I2C->I2C_Send_Byte(OLED_Type_t->I2C, 0x78);
OLED_Type_t->I2C->I2C_Wait_Ack(OLED_Type_t->I2C);
OLED_Type_t->I2C->I2C_Send_Byte(OLED_Type_t->I2C, 0x00);
OLED_Type_t->I2C->I2C_Wait_Ack(OLED_Type_t->I2C);
OLED_Type_t->I2C->I2C_Send_Byte(OLED_Type_t->I2C, cmd);
OLED_Type_t->I2C->I2C_Wait_Ack(OLED_Type_t->I2C);
OLED_Type_t->I2C->I2C_Stop(OLED_Type_t->I2C);
}
//向设备写数据
static void OLED_Write_Date_t(const struct OLED_Type* OLED_Type_t, unsigned char date)
{
OLED_Type_t->I2C->I2C_Start(OLED_Type_t->I2C);
OLED_Type_t->I2C->I2C_Send_Byte(OLED_Type_t->I2C, 0x78);
OLED_Type_t->I2C->I2C_Wait_Ack(OLED_Type_t->I2C);
OLED_Type_t->I2C->I2C_Send_Byte(OLED_Type_t->I2C, 0x40);
OLED_Type_t->I2C->I2C_Wait_Ack(OLED_Type_t->I2C);
OLED_Type_t->I2C->I2C_Send_Byte(OLED_Type_t->I2C, date);
OLED_Type_t->I2C->I2C_Wait_Ack(OLED_Type_t->I2C);
OLED_Type_t->I2C->I2C_Stop(OLED_Type_t->I2C);
}
//坐标设置
static void OLED_Set_Pos_t(const struct OLED_Type* OLED_Type_t, unsigned char x, unsigned char y)
{
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xB0 + y);
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, ((x & 0xF0) >> 4) | 0x10);
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, x & 0x0F);
}
//开启OLED显示
static void OLED_Display_On_t(const struct OLED_Type* OLED_Type_t)
{
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x8D); //SET DCDC命令
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x14); //DCDC ON
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xAF); //DISPLAY ON
}
//关闭OLED显示
static void OLED_Display_Off_t(const struct OLED_Type* OLED_Type_t)
{
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x8D); //SET DCDC命令
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x10); //DCDC OFF
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xAE); //DISPLAY OFF
}
//OLED清屏
static void OLED_Clear_t(const struct OLED_Type* OLED_Type_t)
{
unsigned char cnt, count;
for(cnt = 0; cnt < 8; cnt++)
{
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xB0 + cnt);
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x00);
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x10);
for(count = 0; count < 128; count++)
{
OLED_Type_t->OLED_Write_Date(OLED_Type_t, 0x00);
}
}
}
//OLED清行
static void OLED_Clear_Row_t(const struct OLED_Type* OLED_Type_t, unsigned char n)
{
unsigned char count;
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xB0 + n);
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x00);
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x10);
for(count = 0; count < 128; count++)
{
OLED_Type_t->OLED_Write_Date(OLED_Type_t, 0x00);
}
}
//OLED填满屏幕
static void OLED_Fill_t(const struct OLED_Type* OLED_Type_t)
{
unsigned char cnt, count;
for(cnt = 0; cnt < 8; cnt++)
{
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xB0 + cnt); //设置页地址(0~7)
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x00); //设置显示位置—列低地址
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x10); //设置显示位置—列高地址
for(count = 0; count < 128; count++)
{
OLED_Type_t->OLED_Write_Date(OLED_Type_t, 0x01);
}
}
}
//指定位置显示一个字符
//x:0~127
//y:0~63
//chr:字符
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
static void OLED_ShowChar_t(const struct OLED_Type* OLED_Type_t, unsigned char x, unsigned char y, unsigned char chr, unsigned char size)
{
unsigned char offset = 0, cnt = 0;
offset = chr - ' '; //计算偏移量
if(x > 128 - 1)
{
x = 0;
y = y + 2;
}
if(size == 16)
{
OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x, y);
for(cnt = 0; cnt < 8; cnt++)
{
OLED_Type_t->OLED_Write_Date(OLED_Type_t, F8x16[offset * 16 + cnt]);
}
OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x, y + 1);
for(cnt = 0; cnt < 8; cnt++)
{
OLED_Type_t->OLED_Write_Date(OLED_Type_t, F8x16[offset * 16 + cnt + 8]);
}
}
else
{
OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x, y);
for(cnt = 0; cnt < 6; cnt++)
{
OLED_Type_t->OLED_Write_Date(OLED_Type_t, F6x8[offset][cnt]);
}
}
}
unsigned int oled_pow(unsigned char m, unsigned char n)
{
unsigned int result = 1;
while(n--)
{
result *= m;
}
return result;
}
//指定位置显示一个数字
//x,y:起点坐标
//num:数值(0~4294967295)
//len:数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
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)
{
unsigned char cnt, temp;
unsigned char show = 0;
for(cnt = 0; cnt < len; cnt++)
{
temp = (num / oled_pow(10, len - cnt - 1)) % 10;
if(show == 0 && cnt < (len - 1))
{
if(temp == 0)
{
OLED_Type_t->OLED_ShowChar(OLED_Type_t, x + (size / 2) * cnt, y, ' ', size);
continue;
}
else
{
show = 1;
}
}
OLED_Type_t->OLED_ShowChar(OLED_Type_t, x + (size / 2) * cnt, y, temp + '0', size);
}
}
//指定位置显示字符串
static void OLED_ShowString_t(const struct OLED_Type* OLED_Type_t, unsigned char x, unsigned char y, unsigned char *chr, unsigned char size)
{
unsigned char cnt = 0;
while(chr[cnt] != '\0')
{
OLED_Type_t->OLED_ShowChar(OLED_Type_t, x, y, chr[cnt], size);
x += 8;
if(x > 120)
{
x = 0;
y += 2;
}
cnt++;
}
}
//显示汉字
static void OLED_ShowCHinese_t(const struct OLED_Type* OLED_Type_t, unsigned char x, unsigned char y, unsigned char no)
{
unsigned char cnt, addr = 0;
OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x, y);
for(cnt = 0; cnt < 16; cnt++)
{
OLED_Type_t->OLED_Write_Date(OLED_Type_t, Hzk[2 * no][cnt]);
addr++;
}
OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x, y + 1);
for(cnt = 0; cnt < 16; cnt++)
{
OLED_Type_t->OLED_Write_Date(OLED_Type_t, Hzk[2 * no + 1][cnt]);
addr++;
}
}
//显示图片
/*
@brief 显示图片
@param x0:起始列地址
y0:起始页地址
x1:终止列地址
y1:终止页地址
BMP[]:存放图片代码的数组
@retval 无
*/
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[])
{
unsigned int j = 0; //定义变量
unsigned char x, y; //定义变量
if(y1 % 8 == 0)
{
y = y1 / 8; //判断终止页是否为8的整数倍
}
else
{
y = y1 / 8 + 1;
}
for(y = y0; y < y1; y++) //从起始页开始,画到终止页
{
OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x0, y); //在页的起始列开始画
for(x = x0; x < x1; x++) //画x1 - x0 列
{
OLED_Type_t->OLED_Write_Date(OLED_Type_t, BMP[j++]); //画图片的点
}
}
}
//显示动图
/*
@brief 显示动图
@param x0:起始列地址
y0:起始页地址
x1:终止列地址
y1:终止页地址
k: 帧个数
m: 单帧数组大小
BMP[][m]:存放动图代码的数组
@retval 无
*/
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])
{
unsigned int j = 0; //定义变量
unsigned char x, y, i; //定义变量
if(y1 % 8 == 0)
{
y = y1 / 8; //判断终止页是否为8的整数倍
}
else
{
y = y1 / 8 + 1;
}
for (i = 0; i < k; i++) //从第一帧开始画
{
j = 0;
for(y = y0; y < y1; y++) //从起始页开始,画到终止页
{
OLED_Type_t->OLED_Set_Pos(OLED_Type_t, x0, y); //在页的起始列开始画
for(x = x0; x < x1; x++) //画x1 - x0 列
{
OLED_Type_t->OLED_Write_Date(OLED_Type_t, GIF[i][j++]); //画图片的点
}
}
//delay_ms(80);
}
}
//OLED初始化
static void OLED_Init_t(const struct OLED_Type* OLED_Type_t)
{
OLED_Type_t->I2C->I2C_Init(OLED_Type_t->I2C);
Delay_Ms(200);
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xAE); //display off
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x00); //set low column address
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x10); //set high column address
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x40); //set start line address
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xB0); //set page address
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x81); //contract control
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xFF); //128
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xA1); //set segment remap
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xA6); //normal / reverse
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xA8); //set multiplex ratio(1 to 64)
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x3F); //1/32 duty
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xC8); //Com scan direction
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xD3); //set display offset
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x00); //
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xD5); //set osc division
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x80); //
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xD8); //set area color mode off
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x05); //
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xD9); //Set Pre-Charge Period
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xF1); //
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xDA); //set com pin configuartion
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x12); //
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xDB); //set Vcomh
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x30); //
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x8D); //set charge pump enable
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0x14); //
OLED_Type_t->OLED_Write_CMD(OLED_Type_t, 0xAF); //turn on oled panel
}
//实例化
OLED_TypeDef _0_96OLED =
{
.I2C = &I2C_t,
.OLED_Write_CMD = OLED_Write_CMD_t,
.OLED_Write_Date = OLED_Write_Date_t,
.OLED_Set_Pos = OLED_Set_Pos_t,
.OLED_Display_On = OLED_Display_On_t,
.OLED_Display_Off = OLED_Display_Off_t,
.OLED_Clear = OLED_Clear_t,
.OLED_Clear_Row = OLED_Clear_Row_t,
.OLED_Fill = OLED_Fill_t,
.OLED_ShowChar = OLED_ShowChar_t,
.OLED_ShowNum = OLED_ShowNum_t,
.OLED_ShowString = OLED_ShowString_t,
.OLED_ShowCHinese = OLED_ShowCHinese_t,
.OLED_DrawBMP = OLED_DrawBMP_t,
.OLED_DrawGIF = OLED_DrawGIF_t,
.OLED_Init = OLED_Init_t,
};
以上可看出OLED类中包含I2C类的成员对象,由于OLED的实现需要调用I2C的成员方法,I2C相当于OLED的下一层的驱动,因此将I2C类对象作为OLED类的成员;我们在使用OLED的时候需要实例化OLED类对象,由于I2C和OLED是分别在不同的.c文件中,在实例化OLED外设时,结构体中包含的是I2C设备的指针,而不是实体,同时在I2C.c文件中应完成实例化一个I2C对象;从而对外提供了OLED的封装接口。
四、main调用
在main中直接使用_0_96OLED来实现所有操作,如下:
int main(void)
{
/* initial system clock */
system_clock_config();
/* config nvic priority group */
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
Delay_Init();
hal_ledInit();
hal_timerInit();
//I2C_t.I2C_Init(&I2C_t);
_0_96OLED.OLED_Init(&_0_96OLED);
_0_96OLED.OLED_Clear(&_0_96OLED);
_0_96OLED.OLED_ShowString(&_0_96OLED, 16, 0, "www.21ic.com", 16);
_0_96OLED.OLED_ShowString(&_0_96OLED, 14, 2, "AT32F425 TEST", 16);
_0_96OLED.OLED_ShowString(&_0_96OLED, 28, 4, "2022/5/31", 16);
_0_96OLED.OLED_ShowString(&_0_96OLED, 14, 6, "ID:zhouminjie", 16);
Delay_Ms(1000);
while(1)
{
_0_96OLED.OLED_DrawGIF(&_0_96OLED, 0, 0, 128, 8, 29, 1024, GIF);
}
}
五、总结
面向对象方法实现I2C驱动封装及OLED驱动封装,对外仅提供一个OLED操作对象接口,提高了代码的复用性及封装性,方便了代码后期的维护修改。
参考:https://blog.csdn.net/weixin_42700740/article/details/113624909
六、效果及测试代码
AT32F425_SW_I2C_0.96OLED_oo.zip
(382.25 KB)
|
|