GD32F103的I2C模块有I2C0和I2C1;本程序使用I2C0功能模块;
I2C0引脚复用和重映射:
当I2C0_REMAP=0时,I2C0引脚复用功能,I2C0_SCL映射到PB6引脚,I2C0_SDA映射到PB7引脚;
当I2C0_REMAP=1时,I2C0引脚重映射,I2C0_SCL映射到PB8引脚,I2C0_SDA映射到PB9引脚;
I2C1引脚只有复用引脚:
I2C1_SCL映射到PB10引脚,I2C1_SDA映射到PB11引脚;
I2C标速模式:最快100kbit/s;
I2C快速模式:最快400kbit/s;
当clkspeed<=100000位/秒,配置I2C为标速模式;
当100000位/秒<clkspeed<=400000位/秒,配置I2C为快速模式;
系统复位以后,I2C默认工作在从机模式下;
主机和从机模式切换如下:
通过软件设置START位置1,使I2C在总线上发送一个START起始位之后,I2C变为主机模式;
通过软件设置STOP位置1,使I2C在总线上发送一个STOP结束位后,I2C就会自动变为从机模式;
I2C接口:
串行数据SDA和串行时钟SCL;
START起始位定义:在SCL为高时,SDA线上出现一个从高到低的电平转换;
STOP结束位定义:在SCL为高时,SDA线上出现一个从低到高的电平转换;
I2C主机:负责产生START起始位和STOP结束位,并且负责产生SCL时钟;
#include "24LC256.h"
/*
GD32F103的I2C模块有I2C0和I2C1;本程序使用I2C0功能模块;
I2C0引脚复用和重映射:
当I2C0_REMAP=0时,I2C0引脚复用功能,I2C0_SCL映射到PB6引脚,I2C0_SDA映射到PB7引脚;
当I2C0_REMAP=1时,I2C0引脚重映射,I2C0_SCL映射到PB8引脚,I2C0_SDA映射到PB9引脚;
I2C1引脚只有复用引脚:
I2C1_SCL映射到PB10引脚,I2C1_SDA映射到PB11引脚;
I2C标速模式:最快100kbit/s;
I2C快速模式:最快400kbit/s;
当clkspeed<=100000位/秒,配置I2C为标速模式;
当100000位/秒<clkspeed<=400000位/秒,配置I2C为快速模式;
系统复位以后,I2C默认工作在从机模式下;
主机和从机模式切换如下:
通过软件设置START位置1,使I2C在总线上发送一个START起始位之后,I2C变为主机模式;
通过软件设置STOP位置1,使I2C在总线上发送一个STOP结束位后,I2C就会自动变为从机模式;
I2C接口:
串行数据SDA和串行时钟SCL;
START起始位定义:在SCL为高时,SDA线上出现一个从高到低的电平转换;
STOP结束位定义:在SCL为高时,SDA线上出现一个从低到高的电平转换;
I2C主机:负责产生START起始位和STOP结束位,并且负责产生SCL时钟;
*/
/*
7位地址的I2C通讯流程:
START(1位) + "7位地址+读命令(1位)" + 从机应答ACK(1位)
+ 从机发送数据1(8位) + 主机应答ACK(1位) +... 从机发送数据N(8位) + 主机应答NACK(1位) + STOP(1位)
START(1位) + "7位地址+写命令(1位)" + 从机应答ACK(1位)
+ 主机发送数据1(8位) + 从机应答ACK(1位) +... 主机发送数据N(8位) + 从机应答ACK(1位) + STOP(1位)
*/
/*
10位地址的I2C通讯流程:
START(1位) + "11110+从机地址最高2位+写命令(1位)" + 从机应答ACK(1位)
+ "从机地址低8位" + 从机应答ACK(1位) + 主机发送数据1(8位) + 从机应答ACK(1位)
+... 主机发送数据N(8位) + 从机应答ACK(1位) + STOP(1位)
START(1位) + "11110+从机地址最高2位+写命令(1位)" + 从机应答ACK(1位)+ "从机地址低8位" + 从机应答ACK(1位)
+START(1位) + "11110+从机地址最高2位+读命令(1位)" + 从机应答ACK(1位)
+ 从机发送数据1(8位) + 主机应答ACK(1位)+... 从机发送数据N(8位) + 主机应答ACK(1位) + STOP(1位)
*/
/*
设置I2C发送或接收CRC校验值:
I2C模块中有一个PEC模块,它使用CRC-8计算器来执行I2C数据的报文校验,
CRC多项式为x8+ x2+ x + 1,和SMBus协议兼容;
将PECEN位置1就可以使能PEC功能,PEC将会计算所有通过I2C总线发送的数据(包括地址);
在非DMA模式下,设置PECTRANS位置1,可以控制I2C在最后一个字节发送完毕后发送PEC值,
或者在接收完成后检查接收到的PEC值是否正确;
在DMA模式下,如果PECEN位置1,I2CI将自动发送或者检查PEC值;
*/
//SMBus:系统管理总线;
//PMBus:电源管理总线;
void EEPROM_PIN_Init(void);
void EEPROM_U8_Data_Write(u8 x,u16 addr);
void EEPROM_Buffer_Data_Write(u8 *p_buffer,u8 number_of_byte,u16 addr);
u8 EEPROM_U8_Data_Read1(u16 addr);
void EEPROM_Buffer_Data_Read(u8 *p_buffer,u8 number_of_byte,u16 addr);
//函数功能:I2C0_SCL映射到PB8引脚,I2C0_SDA映射到PB9引脚,配置I2C为快速模式400KHz
void EEPROM_PIN_Init(void)
{
rcu_periph_clock_enable(RCU_AF);//使能映射功能的时钟
rcu_periph_clock_enable(RCU_GPIOB);//使能GPIOB端口的外设时钟
// gpio_pin_remap_config(GPIO_I2C0_REMAP,DISABLE);
//设置AFIO_PCF0寄存器的I2C0_REMAP=0;
// gpio_init(GPIOB,GPIO_MODE_AF_OD,GPIO_OSPEED_50MHZ,GPIO_PIN_6|GPIO_PIN_7);
//I2C0复用功能:I2C0_SCL映射到PB6引脚,I2C0_SDA映射到PB7引脚;
//GPIO_MODE_AF_OD配置PB6和PB7引脚为复用功能IO开漏极输出
gpio_pin_remap_config(GPIO_I2C0_REMAP,ENABLE);
//使能I2C0重映射到GPIO;
//设置AFIO_PCF0寄存器的I2C0_REMAP=1;
gpio_init(GPIOB,GPIO_MODE_AF_OD,GPIO_OSPEED_50MHZ,GPIO_PIN_8|GPIO_PIN_9);
//I2C0_SCL映射到PB8引脚,I2C0_SDA映射到PB9引脚;
//GPIO_MODE_AF_OD配置PB8和PB9引脚为复用功能IO开漏极输出
rcu_periph_clock_enable(RCU_I2C0);//使能RCU_I2C0时钟
i2c_clock_config(I2C0,I2C0_SPEED,I2C_DTCY_2);
//I2C0_SPEED=400000位/秒,配置I2C为快速模式,Tlow/Thigh=2;
//clkspeed<=100000位/秒,配置I2C为标速模式;
//100000位/秒<clkspeed<=400000位/秒,配置I2C为快速模式;
i2c_mode_addr_config(I2C0,I2C_I2CMODE_ENABLE,I2C_ADDFORMAT_7BITS,I2C0_SLAVE_ADDRESS7);
//配置为I2C模式,I2C从机设备使用7位地址为I2C0_SLAVE_ADDRESS7(0xA0)
i2c_enable(I2C0);//使能I2C外设
i2c_ack_config(I2C0,I2C_ACK_ENABLE);//I2C_ACK_ENABLE:ACKEN=1,允许发送ACK应答
}
//函数功能:将p_buffer[]中number_of_byte个数据写入首地址为addr的EEPROM中
void eeprom_page_write(uint8_t* p_buffer, uint8_t addr, uint8_t number_of_byte)
{
FlagStatus flag;
uint8_t x;
union EEPROM_Addr_TYPE temp;
temp.Address=addr;
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_I2CBSY);
//I2C忙标志位I2CBSY=1表示I2C正在通讯
}while(flag==SET);
发送I2C启动条件开始/
i2c_start_on_bus(I2C0);//主机发送I2C启动条件
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_SBSEND);
//读取主机"I2C启动条件"已发送标志
}while(flag==RESET );//等待SBSEND=1,进入主机模式
发送I2C启动条件结束/
发送I2C从机写器件地址开始/
i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_TRANSMITTER);
//发送"I2C从机地址0xA0+0",设置I2C为发送方,SBSEND=0
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_ADDSEND);
//读取"主机已发送从机地址标志"
}while(flag==RESET );//等待ADDSEND=1
i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
//通过读取I2C_STAT0和I2C_STAT1寄存器,令ADDSEND=0;
//clear the ADDSEND bit
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_TBE);
//读取"I2C_DATA发送寄存器空标志"
}while( flag==RESET );//等待TBE=1,I2C_DATA发送寄存器空
发送I2C从机写器件地址结束/
发送I2C从机器件子地址开始/
i2c_data_transmit(I2C0, temp.b[1]);
//将read_address的值写入"I2C传送缓冲区寄存器"
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_BTC);
//读取"I2C数据发送完成标志"
}while(flag==RESET);//等待BTC=1,I2C数据发送完成
i2c_data_transmit(I2C0, temp.b[0]);
//将read_address的值写入"I2C传送缓冲区寄存器"
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_BTC);
//读取"I2C数据发送完成标志"
}while(flag==RESET);//等待BTC=1,I2C数据发送完成
发送I2C从机器件子地址结束/
发送x的值给I2C从机开始/
//while there is data to be written
while(number_of_byte--)
{
x=*p_buffer;
i2c_data_transmit(I2C0, x);
//将x的值写入"I2C传送缓冲区寄存器"
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_BTC);
//读取"I2C数据发送完成标志"
}while(flag==RESET);//等待BTC=1,I2C数据发送完成
p_buffer++;//修改指针,为发送数据做准备
}
发送x的值给I2C从机结束/
发送I2C结束条件开始/
i2c_stop_on_bus(I2C0); //主机发送I2C停止条件
while( I2C_CTL0(I2C0)&0x0200 );//等待STOP=1,主机发送I2C停止条件完成
发送I2C结束条件结束/
}
//函数功能:等待"I2C从机响应"
void eeprom_wait_standby_state(void)
{
FlagStatus flag;
__IO uint32_t val = 0;
while(1)//若I2C从机响应,则退出循环
{
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_I2CBSY);
//I2C忙标志位I2CBSY=1表示I2C正在通讯
}while(flag==SET);//wait until I2C bus is idle
发送I2C启动条件开始/
i2c_start_on_bus(I2C0);//主机发送I2C启动条件
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_SBSEND);
//读取主机"I2C启动条件"已发送标志
}while(flag==RESET );//等待SBSEND=1,进入主机模式
发送I2C启动条件结束/
发送I2C从机写器件地址开始/
i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_TRANSMITTER);
//发送"I2C从机地址0xA0+0",设置I2C为发送方,SBSEND=0
do
{//get the current value of the I2C_STAT0 register
val = I2C_STAT0(I2C0);
}while(0 == (val & (I2C_STAT0_ADDSEND | I2C_STAT0_AERR)));
//等待ADDSEND=1
//I2C_STAT0_ADDSEND主机模式下成功发送了地址标志
//I2C_STAT0_AERR应答错误
if(val & I2C_STAT0_ADDSEND)//ADDSEND=1
{//clear ADDSEND flag
i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
//通过读取I2C_STAT0和I2C_STAT1寄存器,令ADDSEND=0
i2c_stop_on_bus(I2C0);//主机发送I2C停止条件
return ;//I2C从机响应,则立即返回
}
else//AERR位被置1
{
i2c_flag_clear(I2C0,I2C_FLAG_AERR);//清除"I2C应答错误标志"
}
发送I2C从机写器件地址结束/
发送I2C结束条件开始/
i2c_stop_on_bus(I2C0); //主机发送I2C停止条件
while( I2C_CTL0(I2C0)&0x0200 );//等待STOP=1,主机发送I2C停止条件完成
发送I2C结束条件结束/
}
}
//函数功能:将p_buffer[]中number_of_byte个数据写入首地址为addr的EEPROM中
void EEPROM_Buffer_Data_Write(u8 *p_buffer,u8 number_of_byte,u16 addr)
{
uint8_t number_of_page = 0, number_of_single = 0, address = 0, count = 0;
address = addr % I2C_PAGE_SIZE; //计算addr在"待写首页"内的偏移地址
count = I2C_PAGE_SIZE - address;//计算"待写首页"的剩余字节数
number_of_page = number_of_byte / I2C_PAGE_SIZE;//计算"待写数据"可以写满多少个整页
number_of_single = number_of_byte % I2C_PAGE_SIZE;//计算"待写数据"超出整页有多少个字节数
if(0 == address)//addr位于"某个页的首地址"
{
while(number_of_page--)//写number_of_page个页数据
{
eeprom_page_write(p_buffer, addr, I2C_PAGE_SIZE);
//将p_buffer[]中I2C_PAGE_SIZE个数据写入首地址为addr的EEPROM中
eeprom_wait_standby_state();//等待"I2C从机响应"
addr += I2C_PAGE_SIZE; //修改EEPROM的存储地址
p_buffer += I2C_PAGE_SIZE; //修改指针
}
if(0 != number_of_single)//将"超出整页的number_of_single个字节数据"写入EEPROM
{
eeprom_page_write(p_buffer, addr, number_of_single);
//将p_buffer[]中number_of_single个数据写入首地址为addr的EEPROM中
eeprom_wait_standby_state();//等待"I2C从机响应"
}
}
else//addr位于"某个页的页内"
{/* if addr is not I2C_PAGE_SIZE aligned */
if(number_of_byte < count)//所写字节数小于"待写首页"空间
{
eeprom_page_write(p_buffer, addr, number_of_byte);
//将p_buffer[]中number_of_byte个数据写入首地址为addr的EEPROM中
eeprom_wait_standby_state();//等待"I2C从机响应"
}
else//所写字节数超过"待写首页"空间
{
number_of_byte -= count;//计算去掉"待写首页"空间的字节数,还有多少个字节需要写入EEPROM
number_of_page = number_of_byte / I2C_PAGE_SIZE;//计算"待写数据"可以写满多少个整页
number_of_single = number_of_byte % I2C_PAGE_SIZE;//计算"待写数据"超出整页有多少个字节数
if(0 != count)//写count个字节到"待写首页"
{
eeprom_page_write(p_buffer, addr, count);
//将p_buffer[]中count个数据写入首地址为addr的EEPROM中
eeprom_wait_standby_state();//等待"I2C从机响应"
addr += count; //修改EEPROM的存储地址
p_buffer += count; //修改指针
}
while(number_of_page--)//写number_of_page个页数据
{
eeprom_page_write(p_buffer, addr, I2C_PAGE_SIZE);
//将p_buffer[]中I2C_PAGE_SIZE个数据写入首地址为addr的EEPROM中
eeprom_wait_standby_state();//等待"I2C从机响应"
addr += I2C_PAGE_SIZE; //修改EEPROM的存储地址
p_buffer += I2C_PAGE_SIZE; //修改指针
}
if(0 != number_of_single)//写剩余数据
{
eeprom_page_write(p_buffer, addr, number_of_single);
//将p_buffer[]中number_of_single个数据写入首地址为addr的EEPROM中
eeprom_wait_standby_state();//等待"I2C从机响应"
}
}
}
}
//函数功能:将p_buffer[0]发送给从机设备0xA0,器件子地址为addr
void EEPROM_U8_Data_Write(u8 x,u16 addr)
{
FlagStatus flag;
union EEPROM_Addr_TYPE temp;
temp.Address=addr;
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_I2CBSY);
//I2C忙标志位I2CBSY=1表示I2C正在通讯
}while(flag==SET);
发送I2C启动条件开始/
i2c_start_on_bus(I2C0);//主机发送I2C启动条件
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_SBSEND);
//读取主机"I2C启动条件"已发送标志
}while(flag==RESET );//等待SBSEND=1,进入主机模式
发送I2C启动条件结束/
发送I2C从机写器件地址开始/
i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_TRANSMITTER);
//发送"I2C从机地址0xA0+0",设置I2C为发送方,SBSEND=0
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_ADDSEND);
//读取"主机已发送从机地址标志"
}while(flag==RESET );//等待ADDSEND=1
i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
//通过读取I2C_STAT0和I2C_STAT1寄存器,令ADDSEND=0;
//clear the ADDSEND bit
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_TBE);
//读取"I2C_DATA发送寄存器空标志"
}while( flag==RESET );//等待TBE=1,I2C_DATA发送寄存器空
发送I2C从机写器件地址结束/
发送I2C从机器件子地址开始/
i2c_data_transmit(I2C0, temp.b[1]);
//将read_address的值写入"I2C传送缓冲区寄存器"
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_BTC);
//读取"I2C数据发送完成标志"
}while(flag==RESET);//等待BTC=1,I2C数据发送完成
i2c_data_transmit(I2C0, temp.b[0]);
//将read_address的值写入"I2C传送缓冲区寄存器"
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_BTC);
//读取"I2C数据发送完成标志"
}while(flag==RESET);//等待BTC=1,I2C数据发送完成
发送I2C从机器件子地址结束/
发送x的值给I2C从机开始/
//while there is data to be written
i2c_data_transmit(I2C0, x);
//将x的值写入"I2C传送缓冲区寄存器"
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_BTC);
//读取"I2C数据发送完成标志"
}while(flag==RESET);//等待BTC=1,I2C数据发送完成
发送x的值给I2C从机结束/
发送I2C结束条件开始/
i2c_stop_on_bus(I2C0); //主机发送I2C停止条件
while( I2C_CTL0(I2C0)&0x0200 );//等待STOP=1,主机发送I2C停止条件完成
发送I2C结束条件结束/
eeprom_wait_standby_state();//等待"I2C从机响应"
}
//函数功能:从EEPROM地址为addr中读取一个字节数据
u8 EEPROM_U8_Data_Read1(u16 addr)
{
FlagStatus flag;
uint8_t rerurn_value;
union EEPROM_Addr_TYPE temp;
temp.Address=addr;
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_I2CBSY);
//I2C忙标志位I2CBSY=1表示I2C正在通讯
}while(flag==SET);//wait until I2C bus is idle
发送I2C启动条件开始/
i2c_start_on_bus(I2C0);//主机发送I2C启动条件
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_SBSEND);
//读取主机"I2C启动条件"已发送标志
}while(flag==RESET );//等待SBSEND=1,进入主机模式
发送I2C启动条件结束/
发送I2C从机写器件地址开始/
i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_TRANSMITTER);
//发送"I2C从机地址0xA0+0",设置I2C为发送方,设置I2C为发送方,SBSEND=0
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_ADDSEND);
//读取"主机已发送从机地址标志"
}while(flag==RESET );//等待ADDSEND=1
i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
//通过读取I2C_STAT0和I2C_STAT1寄存器,令ADDSEND=0
//clear the ADDSEND bit
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_TBE);
//读取"I2C_DATA发送寄存器空标志"
}while( flag==RESET );//等待TBE=1,I2C_DATA发送寄存器空
发送I2C从机写器件地址结束/
i2c_enable(I2C0);
//使能I2C外设
//很奇怪,怎么要添加这条语句
发送I2C从机器件子地址开始/
i2c_data_transmit(I2C0, temp.b[1]);
//将read_address的值写入"I2C传送缓冲区寄存器"
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_BTC);
//读取"I2C数据发送完成标志"
}while(flag==RESET);//等待BTC=1,I2C数据发送完成
i2c_data_transmit(I2C0, temp.b[0]);
//将read_address的值写入"I2C传送缓冲区寄存器"
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_BTC);
//读取"I2C数据发送完成标志"
}while(flag==RESET);//等待BTC=1,I2C数据发送完成
发送I2C从机器件子地址结束/
发送I2C重启条件开始/
i2c_start_on_bus(I2C0);//主机发送I2C启动条件
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_SBSEND);
//读取主机"I2C启动条件"已发送标志
}while(flag==RESET );//等待SBSEND=1,进入主机模式
发送I2C重启条件结束/
发送I2C从机读器件地址开始/
i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_RECEIVER);
//发送"I2C从机地址0xA0+1",设置I2C为接收方,SBSEND=0
i2c_ack_config(I2C0,I2C_ACK_DISABLE);
//ACKEN=0,不允许发送ACK应答
//注意:I2C接收最后一个字节,主机不需要发送应答
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_ADDSEND);
//读取"主机已发送从机地址标志"
}while(flag==RESET );//等待ADDSEND=1
i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
//通过读取I2C_STAT0和I2C_STAT1寄存器,令ADDSEND=0
//clear the ADDSEND bit
发送I2C从机读器件地址结束/
i2c_stop_on_bus(I2C0);//主机发送I2C停止条件
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_RBNE);
//读取"I2C_DATA接收寄存器非空标志"
}while(flag==RESET );
if(flag)//RBNE=1,"I2C_DATA接收寄存器"有新数据待读
{
rerurn_value = i2c_data_receive(I2C0);//读"I2C传送缓冲区寄存器"
}
while(I2C_CTL0(I2C0)&0x0200);
//等待STOP=1,主机发送I2C停止条件完成
//wait until the stop condition is finished
i2c_ack_config(I2C0,I2C_ACK_ENABLE);//I2C_ACK_ENABLE:ACKEN=1,允许发送ACK应答
i2c_ackpos_config(I2C0,I2C_ACKPOS_CURRENT);//I2C_ACKPOS_CURRENT:POAP=0
//POAP=0且ACKEN=1表示对当前正在接收的字节发送ACK应答
return(rerurn_value);
}
//函数功能:从EEPROM首地址为addr中,恋雪读取number_of_byte个字节数据,保存到p_buffer[]中
void EEPROM_Buffer_Data_Read(u8 *p_buffer,u8 number_of_byte,u16 addr)
{
FlagStatus flag;
union EEPROM_Addr_TYPE temp;
temp.Address=addr;
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_I2CBSY);
//I2C忙标志位I2CBSY=1表示I2C正在通讯
}while(flag==SET);//wait until I2C bus is idle
if(2 == number_of_byte)
{
i2c_ackpos_config(I2C0,I2C_ACKPOS_NEXT);
//I2C_ACKPOS_NEXT:POAP=1
//POAP=1且ACKEN=1对下一个字节发送ACK应答;
}
发送I2C启动条件开始/
i2c_start_on_bus(I2C0);//主机发送I2C启动条件
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_SBSEND);
//读取主机"I2C启动条件"已发送标志
}while(flag==RESET );//等待SBSEND=1,进入主机模式
发送I2C启动条件结束/
发送I2C从机写器件地址开始/
i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_TRANSMITTER);
//发送"I2C从机地址0xA0+0",设置I2C为发送方,SBSEND=0
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_ADDSEND);
//读取"主机已发送从机地址标志"
}while(flag==RESET );//等待ADDSEND=1
i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
//通过读取I2C_STAT0和I2C_STAT1寄存器,令ADDSEND=0
//clear the ADDSEND bit
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_TBE);
//读取"I2C_DATA发送寄存器空标志"
}while( flag==RESET );//等待TBE=1,I2C_DATA发送寄存器空
发送I2C从机写器件地址结束/
i2c_enable(I2C0);//使能I2C外设
发送I2C从机器件子地址开始/
i2c_data_transmit(I2C0, temp.b[1]);
//将read_address的值写入"I2C传送缓冲区寄存器"
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_BTC);
//读取"I2C数据发送完成标志"
}while(flag==RESET);//等待BTC=1,I2C数据发送完成
i2c_data_transmit(I2C0, temp.b[0]);
//将read_address的值写入"I2C传送缓冲区寄存器"
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_BTC);
//读取"I2C数据发送完成标志"
}while(flag==RESET);//等待BTC=1,I2C数据发送完成
发送I2C从机器件子地址结束/
发送I2C重启条件开始/
i2c_start_on_bus(I2C0);//主机发送I2C启动条件
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_SBSEND);
//读取主机"I2C启动条件"已发送标志
}while(flag==RESET );//等待SBSEND=1,进入主机模式
发送I2C重启条件结束/
发送I2C从机读器件地址开始/
i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_RECEIVER);
//发送"I2C从机地址0xA0+1",设置I2C为接收方,SBSEND=0
if(number_of_byte < 3)
{// disable acknowledge
i2c_ack_config(I2C0,I2C_ACK_DISABLE);
//ACKEN=0,不允许发送ACK应答
//注意:I2C接收最后一个字节,主机不需要发送应答
}
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_ADDSEND);
//读取"主机已发送从机地址标志"
}while(flag==RESET );//等待ADDSEND=1
i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
//通过读取I2C_STAT0和I2C_STAT1寄存器,令ADDSEND=0;
//clear the ADDSEND bit
发送I2C从机读器件地址结束/
if(1 == number_of_byte)//I2C接收完成,立即发送停止条件
{//send a stop condition to I2C bus
i2c_stop_on_bus(I2C0);//主机发送I2C停止条件
}
while(number_of_byte)
{
if(3 == number_of_byte)//读取第(number_of_byte-3)字节数据,清除ACKEN
{
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_BTC);
//读取"I2C数据发送完成标志"
}while(flag==RESET);//等待BTC=1,"I2C接收数据移位时钟"发送完成
i2c_ack_config(I2C0,I2C_ACK_DISABLE);
//ACKEN=0,不允许发送ACK应答
//注意:I2C接收最后一个字节,主机不需要发送应答
}
if(2 == number_of_byte)//读取第(number_of_byte-2)字节数据,设置STOP
{
do
{
flag=i2c_flag_get(I2C0, I2C_FLAG_BTC);
//读取"I2C数据发送完成标志"
}while(flag==RESET);//等待BTC=1,"I2C接收数据移位时钟"发送完成
i2c_stop_on_bus(I2C0); //主机发送I2C停止条件
}
flag=i2c_flag_get(I2C0, I2C_FLAG_RBNE);//读取"I2C_DATA接收寄存器非空标志"
if(flag)//RBNE=1,"I2C_DATA接收寄存器"有新数据待读
{
*p_buffer = i2c_data_receive(I2C0);//读"I2C传送缓冲区寄存器"
p_buffer++;
number_of_byte--;
}
}
while(I2C_CTL0(I2C0)&0x0200);
//等待STOP=1,主机发送I2C停止条件完成
//wait until the stop condition is finished
i2c_ack_config(I2C0,I2C_ACK_ENABLE);//I2C_ACK_ENABLE:ACKEN=1,允许发送ACK应答
i2c_ackpos_config(I2C0,I2C_ACKPOS_CURRENT);//I2C_ACKPOS_CURRENT:POAP=0
//POAP=0且ACKEN=1表示对当前正在接收的字节发送ACK应答
}
main.c如下:
#include "gd32f10x.h" //使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t,bool
#include "delay.h"
//#include "IWDG.h"
//#include "WWDGT.h"
#include "stdio.h" //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "string.h" //使能strcpy(),strlen(),memset()
#include "UART3.h"
#include "24LC256.h"
const char CPU_Reset_REG[]="\r\nCPU reset!\r\n";
const char CPU_Is_Running_REG[]="\r\nCPU is running!\r\n";
int main(void)
{
uint8_t d;
uint16_t i;
u8 buf[11];
//NVIC_PRIGROUP_PRE4_SUB0:抢占优先级为4bit(取值为0~15),子优先级为0bit(没有响应优先级)
//NVIC_PRIGROUP_PRE3_SUB1:抢占优先级为3bit(取值为0~7),子优先级为1bit(取值为0~1)
//NVIC_PRIGROUP_PRE2_SUB2:抢占优先级为2bit(取值为0~3),子优先级为2bit(取值为0~3)
//NVIC_PRIGROUP_PRE1_SUB3:抢占优先级为1bit(取值为0~1),子优先级为3bit(取值为0~7)
//NVIC_PRIGROUP_PRE0_SUB4:抢占优先级为0bit(没有抢占优先级),子优先级为3bit(取值为0~15)
nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);//设置系统中断优先级"抢占优先级为4bit,子优先级为0bit"
INTX_ENABLE();//开启所有中断
GD32F103_UART3_Init(115200);
printf("%s",CPU_Reset_REG);//调试串口输出"\r\nCPU reset!\r\n"
delay_init();
EEPROM_PIN_Init();
//I2C0_SCL映射到PB8引脚,I2C0_SDA映射到PB9引脚,配置I2C为快速模式400KHz
strcpy((char*)buf,"9876543210");
EEPROM_Buffer_Data_Write(buf,10,0);
memset(buf,0,sizeof(buf));//清除buf[]
EEPROM_Buffer_Data_Read(buf,10,0);
printf("\r\nbuf1[]=%s",buf);
for(i=0;i<10;i++)
{
d=EEPROM_U8_Data_Read1(i);
printf("\r\nd=%c",d);
}
EEPROM_U8_Data_Write('0',0);
EEPROM_U8_Data_Write('1',1);
EEPROM_U8_Data_Write('2',2);
EEPROM_U8_Data_Write('3',3);
EEPROM_U8_Data_Write('4',4);
EEPROM_U8_Data_Write('5',5);
EEPROM_U8_Data_Write('6',6);
EEPROM_U8_Data_Write('7',7);
EEPROM_U8_Data_Write('8',8);
EEPROM_U8_Data_Write('9',9);
memset(buf,0,sizeof(buf));//清除buf[]
EEPROM_Buffer_Data_Read(buf,10,0);
printf("\r\nbuf2[]=%s",buf);
for(i=0;i<10;i++)
{
d=EEPROM_U8_Data_Read1(i);
printf("\r\nd=%c",d);
}
while(1)
{
}
}
文章来源:https://www.toymoban.com/news/detail-648167.html
文章来源地址https://www.toymoban.com/news/detail-648167.html
到了这里,关于GD32F103硬件I2C0通讯的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!