GD32F310G8 -【6】硬件I2C&软件I2C驱动0.96OLED
时间:2023-09-08 07:07:00
GD32F310-硬件I2C&软件I2C驱动OLED
I2C 简介及特点
- 并行总线至 I2C 转换和接口总线协议;
- 同一接口可实现主机功能和从机功能;
- 主从机之间的双向数据传输;
- 支持 7 位和 10 地址模式和广播寻址;
- 支持 I2C 多主机模式;
- 支持标速(最高) 100 kHz),快速(最高 400 kHz) 和快速 模式(最高 1MHz);
- 可以在从机模式下配置 SCL 主动拉低;
- 支持 DMA 模式;
- 兼容 SMBus 2.0 和 PMBus;
- 两个中断:字节成功发送中断和错误事件中断;
- 可选择的 PEC (报文错误校验) 生成和校验;
I2C (内部集成电路总线) 模块提供符合工业标准的两线串行接口,可用于 MCU 和外部
I2C 设备通信。 I2C 总线使用两条串行线:串行数据线 SDA 串行时钟线 SCL。
I2C 实现了接口模块 I2C 协议的速度模式、快速模式和快速模式 模式,具备 CRC 计算和验证工作
能、支持 SMBus(系统管理总线) 和 PMBus 此外,还支持多主机 I2C 总线
架构。 I2C 也支持接口模块 DMA 模式,可有效减轻 CPU 的负担。
开发环境&参考文档
- Keil-MDK 5.34
- Windows10
- 固件库-GD32F3x0_Firmware_Library_V2.2.0
- GD32F310xx-数据手册-Rev1.1
- GD32F3x0-用户手册-Rev2.5
- GD32F3x0-固件库使用指南-Rev1.2
代码部分
I2C 初始化配置
I2C.h 文件
#ifndef _IIC_H_ #define _IIC_H_ #include "gd32f3x0.h" void HW_I2cInit(void); #endif
I2C.c 文件
#include "iic.h" void HW_I2cInit(void) {
rcu_periph_clock_enable(RCU_GPIOB);///启用外设时钟功能 rcu_periph_clock_enable(RCU_I2C0); gpio_af_set(GPIOB,GPIO_AF_1,GPIO_PIN_6);///端口复用串口模式 gpio_af_set(GPIOB,GPIO_AF_1,GPIO_PIN_7); gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);//设置GPIO模式 gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);//设置GPIO输出类型和速度 gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7); gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7); i2c_deinit(I2C0);//复位I2C0 i2c_clock_config(I2C0, 100000, I2C_DTCY_2);//设置波特率 i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x78);//设置模式、传输数据长度、主机地址 i2c_enable (I2C0);//使能外设 i2c_ack_config(I2C0,I2C_ACK_ENABLE); }
OLED 初始化函数
oled.h 文件
#ifndef __OLED_H #define __OLED_H #include "iic.h" #include "stdlib.h" #define OLED_MODE 0 #define SIZE 8 #define XLevelL 0x00 #define XLevelH 0x10 #define Max_Column 128 #define Max_Row 32 #define Brightness 0xFF #define X_WIDTH 128 #define Y_WIDTH 32 //-----------------OLED 软件I2C端口定义---------------- #define OLED_SCLK_Clr() gpio_bit_reset(GPIOA, GPIO_PIN_2)//设置Pin脚为高电平//SCL IIC接口的时钟信号 #define OLED_SCLK_Set() gpio_bit_set(GPIOA, GPIO_PIN_2) #define OLED_SDIN_Clr() gpio_bit_reset(GPIOA, GPIO_PIN_3)//SCL IIC接口的数据信号 #define OLED_SDIN_Set() gpio_bit_set(GPIOA, GPIO_PIN_3) #define OLED_CMD 0 //写命令 #define OLED_DATA 1 //写数据 #define S_I2C 0//软件IIC或硬件IIC
开关 #define u8 unsigned char #define u32 unsigned int //OLED控制用函数 void fill_picture(unsigned char fill_Data); void IIC_Start(void); void IIC_Stop(void); void IIC_Wait_Ack(void); void Write_IIC_Command(unsigned char IIC_Command); void Write_IIC_Data(unsigned char IIC_Data); void Write_IIC_Byte(unsigned char IIC_Byte); void OLED_WR_Byte(unsigned dat,unsigned cmd); void OLED_Display_On(void); void OLED_Display_Off(void); void OLED_Init(void); void OLED_Clear(void); void OLED_DrawPoint(u8 x,u8 y,u8 t); void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot); void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size); void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size); void OLED_ShowString(u8 x,u8 y, u8 *p,u8 Char_Size); void OLED_Set_Pos(unsigned char x, unsigned char y); void OLED_ShowCHinese(u8 x,u8 y,u8 no); void OLED_DrawBMP(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char BMP[]); #endif
oled.c 文件
软件I2C与硬件I2C的选定在 .h 文件中有说明。#define S_I2C 0//软件IIC或硬件IIC开关
具体区别在下列两个函数中
Write_IIC_Command()
Write_IIC_Data()
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
#include "iic.h"
//OLED 的显存
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127
/********************************************** //Software IIC Start **********************************************/
void IIC_Start(void)
{
OLED_SCLK_Set();
OLED_SDIN_Set();
OLED_SDIN_Clr();
OLED_SCLK_Clr();
}
/********************************************** //Software IIC Stop **********************************************/
void IIC_Stop(void)
{
OLED_SCLK_Set();
OLED_SDIN_Clr();
OLED_SDIN_Set();
}
/********************************************** //Software IIC Ack **********************************************/
void IIC_Wait_Ack(void)
{
OLED_SCLK_Set() ;
OLED_SCLK_Clr();
}
/********************************************** // IIC Write byte **********************************************/
void Write_IIC_Byte(unsigned char IIC_Byte)
{
unsigned char i;
unsigned char m,da;
da=IIC_Byte;
OLED_SCLK_Clr();
for(i=0;i<8;i++)
{
m=da;
m=m&0x80;
if(m==0x80)
{
OLED_SDIN_Set();
}
else
OLED_SDIN_Clr();
da=da<<1;
OLED_SCLK_Set();
OLED_SCLK_Clr();
}
}
/********************************************** // IIC Write Command **********************************************/
void Write_IIC_Command(unsigned char IIC_Command)
{
#if S_I2C
IIC_Start();
Write_IIC_Byte(0x78); //Slave address,SA0=0
IIC_Wait_Ack();
Write_IIC_Byte(0x00); //write command
IIC_Wait_Ack();
Write_IIC_Byte(IIC_Command);
IIC_Wait_Ack();
IIC_Stop();
#else
while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));
i2c_start_on_bus (I2C0);
while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));//进入主机模式
i2c_master_addressing(I2C0, 0x78, I2C_TRANSMITTER);
while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));//判断地址发送出去
i2c_flag_clear (I2C0, I2C_FLAG_ADDSEND);//清除ADDSEND位
while(SET != i2c_flag_get(I2C0, I2C_FLAG_TBE));//进入数据发送状态
i2c_data_transmit (I2C0, 0x00);
while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
i2c_data_transmit (I2C0, IIC_Command);
while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
i2c_stop_on_bus (I2C0);
while(I2C_CTL0(I2C0)&0x0200);
#endif
}
/********************************************** // IIC Write Data **********************************************/
void Write_IIC_Data(unsigned char IIC_Data)
{
#if S_I2C
IIC_Start();
Write_IIC_Byte(0x78); //Slave address,SA0=0
IIC_Wait_Ack();
Write_IIC_Byte(0x40); //write data
IIC_Wait_Ack();
Write_IIC_Byte(IIC_Data);
IIC_Wait_Ack();
IIC_Stop();
#else
while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));
i2c_start_on_bus (I2C0);
while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));//进入主机模式
i2c_master_addressing(I2C0, 0x78, I2C_TRANSMITTER);
while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));//判断地址发送出去
i2c_flag_clear (I2C0, I2C_FLAG_ADDSEND);//清除ADDSEND位
while(SET != i2c_flag_get(I2C0, I2C_FLAG_TBE));//进入数据发送状态
i2c_data_transmit (I2C0, 0x40);
while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
i2c_data_transmit (I2C0, IIC_Data);
while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
i2c_stop_on_bus (I2C0);
while(I2C_CTL0(I2C0)&0x0200);
#endif
}
void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
if(cmd)
{
Write_IIC_Data(dat);
}
else
{
Write_IIC_Command(dat);
}
}
/******************************************** //Fill Picture ********************************************/
void fill_picture(unsigned char fill_Data)
{
unsigned char m,n;
for(m=0;m<8;m++)
{
OLED_WR_Byte(0xb0+m,0); //page0-page1
OLED_WR_Byte(0x00,0); //low column start address
OLED_WR_Byte(0x10,0); //high column start address
for(n=0;n<128;n++)
{
OLED_WR_Byte(fill_Data,1);
}
}
}
/********************************************** //Set Position //坐标设置 **********************************************/
void OLED_Set_Pos(unsigned char x, unsigned char y)
{
OLED_WR_Byte(0xb0+y,OLED_CMD);
OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
OLED_WR_Byte((x&0x0f),OLED_CMD);
}
/********************************************** //Turn on OLED display //开启OLED显示 **********************************************/
void OLED_Display_On(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON
OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
}
/********************************************** //Turn off OLED display //关闭OLED显示 **********************************************/
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}
/********************************************** //清屏函数,清完屏,整个屏幕是黑色的! **********************************************/
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
} //更新显示
}
/********************************************** //亮屏函数,整个屏幕点亮! **********************************************/
void OLED_On(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA);
} //更新显示
}
/********************************************** //在指定位置显示一个字符,包括部分字符 //x:0~127 //y:0~63 //mode:0,反白显示;1,正常显示 //chr:要显示的字符 //size:选择字体 16/12 **********************************************/
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{
unsigned char c=0,i=0;
c=chr-' ';//得到偏移后的值,为什么做偏移可查看 ASCII 表
if(x>Max_Column-1){
x=0;y=y+2;}
if(Char_Size ==16)
{
OLED_Set_Pos(x,y);
for(i=0;i<8;i++)
OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
OLED_Set_Pos(x,y+1);
for(i=0;i<8;i++)
OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
}
else
{
OLED_Set_Pos(x,y);
for(i=0;i<6;i++)
OLED_WR_Byte(F6x8[c][i],OLED_DATA);
}
}
/********************************************** //m^n函数 **********************************************/
u32 oled_pow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
/********************************************** //显示2个数字 //x:0~127 //y:0~63 //num:数值(0~4294967295); //len :数字的位数 //size:字体大小 **********************************************/
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
{
u8 t,temp;
u8 enshow=0;
for(t=0;t<len;t++)
{
temp=(num/元器件数据手册、IC替代型号,打造电子元器件IC百科大全!