- #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, 下载次数: 23)