网站首页 > 编程文章 正文
I2C 模块介绍
5.7.1. I2C 基础知识
I2C(Inter-Integrated Circuit)总线是一种由Philips公司开发的两线式串行总线,用于内部IC控制的具有多端控制能力的双线双向串行数据总线系统,能够用于替代标准的并行总线,连接各种集成电路和功能模块。I2C器件能够减少电路间的连接,减少电路板的尺寸,降低硬件成本并提高系统的可靠性。I2C总线传输模式具有向下兼容性,传输速率标准模式下可达100kbps,快速模式下可达400kbps,高速模式下可达3.4Mbps。
为了清楚起见,在此对I2C通信中关于设备的基本概念进行简要讲解。
① 发送设备:发送数据到总线上的设备。
② 接收设备:从总线上接收数据的设备。
③ 主设备:启动数据传输并产生时钟信号的设备。
④ 从设备:被主设备寻址的设备。
(1)I2C设备连接原理
I2C设备连接示意图如图 5-13 I2C设备连接示意图所示。I2C总线是由数据线SDA和时钟线SCL构成的串行总线,可发送和接收数据。在GD32 MCU与被控IC(集成电路)之间、IC与IC之间进行双向传送,最高传送速率1Mbps。各种设备均并联在总线上,两条总线都被上拉电阻上拉到VCC,所有设备地位对等,都可作为主机或从机,就像电话机一样只要拨通各自的号码就能正常工作,所以,每个设备都有唯一的地址。在信息的传输过程中,I2C总线上并接的每个设备既是主设备(或从设备),又是发送设备(或接收设备),这取决于它所要完成的功能。每个设备都可以把总线接地拉低,却不允许把总线电平直接连到VCC上置高。把总线电平拉低称为占用总线,总线电平为高等待被拉低则称为总线被释放。
由于SDA和SCL均为双向I/O线,都是开漏极端(输出1时,为高阻状态),因此I2C总线上的所有设备的SDA和SCL引脚都要外接上拉电阻。
(2)I2C数据通信协议
I2C数据通信时序图如图 5-14 I2C数据通信时序图所示。下面首先介绍起始位和停止位,起始位和停止位都是由主设备产生的,如图中虚线所示。当SCL时钟线为高电平时,SDA数据线上由高到低的跳变,产生一个开始信号,即起始位。当SCL时钟线为高电平时,SDA数据线上由低到高的跳变,将产生一个停止信号,即停止位。起始位之后,总线被认为忙,即有数据在传输,传输的第一个字节,即7位从地址和R/W 位。当R/W 位为0时,主机向从机发送数据;当R/W 位为1时,主机接收来自从机的数据。在每个字节后的第九个SCL时钟上,接收机发送ACK位。停止位之后,总线被认为闲,空闲状态时,SDA和SCL都是高电平。
注意:当SCL位为高电平时,SDA的数据必须保持稳定,否则,由于起始位和停止位的电气边沿特性,SDA上数据发生改变将被识别为起始位或停止位。所以,只有当SCL为低电平时才允许SDA上的数据改变。
3)I2C的寻址方式
GD32 MCU的I2C模块支持7位和10位两种寻址模式,7位寻址模式最多寻址128个设备,10位寻址模式最多寻址1024个设备。I2C总线理论上可以允许的最大设备数是以总线上所有器件的电容总和不超过400pF为限(其中,包括连线本身的电容和其连接端的引出等效电容),总线上所有器件要依靠SDA发送的地址信号寻址,不需要片选信号。
① 7位寻址模式
图 5-16 7位寻址模式数据格式为7位地址方式下的I2C数据传输格式,第一个字节由7位从地址和R/W 读/写位组成。不论总线上传送的是地址还是数据信息,每个字节传输完毕,接收设备都会发送响应位(ACK)。地址类信息传输之后是数据信息,直到接收到停止信息。
② 10位寻址模式
图 5-17 10位寻址模式数据格式为10位地址方式下的I2C数据传输格式。第一个字节由二进制位11110、从地址的最高两位及R/W 读/写控制位组成。第一个字节传输完毕后是ACK响应位。第二个字节就是10位从地址的低8位,后面是响应位和数据。
③ 二次发送从地址模式(重复产生起始条件)
主机可以在不停止数据传输的情况下,通过产生重复的起始条件,改变SDA上数据流的方向,这称为RESTART。再次发送起始信号后,需重新发送从地址和R/W 读/写控制位。重新产生起始条件数据传输格式如图 5-18重新产生其实条件数据传输格式所示。
5.7.2. GD32 I2C 外设原理简介
因篇幅有限,本文无法详细介绍GD32所有系列I2C外设接口,下面以GD32F30x为列,着重介绍下GD32F30x的I2C外设简介和结构框图,后介绍下各个系列的差异。
GD32 I2C 主要特性
GD32F30X系列I2C 接口模块实现了 I2C 协议的标速模式,快速模式以及快速+ 模式,具备
CRC 计算和校验功能、支持 SMBus(系统管理总线) 和 PMBus(电源管理总线),此外还支持多主机 I2C 总线架构。 I2C 接口模块也支持 DMA 模式,可有效减轻 CPU 的负担。
GD32 MCU I2C模块
主要特性描述如下:
并行总线至 I2C 总线协议的转换及接口;
同一接口既可实现主机功能又可实现从机功能;
主从机之间的双向数据传输;
支持 7 位和 10 位的地址模式和广播寻址;
支持 I2C 多主机模式;
支持标速(最高 100 KHz),快速(最高 400 KHz) 和快速+ 模式(最高 1MHz);
从机模式下可配置的 SCL 主动拉低;
支持 DMA 模式;
兼容 SMBus 2.0 和 PMBus;
两个中断:字节成功发送中断和错误事件中断;
可选择的 PEC(报文错误校验) 生成和校验;
I2C 结构框图介绍
I2C内部结构框图如图 5-19 I2C
结构框图所示,该结构框图可分为五个部分:
1、用于产生I2C通信时序;
2、用于收发I2C数据,当有数据需要发送时,会首先将数据填充到数据寄存器,然后数
据被自动移位到移位寄存器,通过SDA引脚发送出去,当有数据需要接受时,首先会根据SCL选择的时钟边沿在移位寄存器中锁存SDA数据,当数据接受到后,数据被移到数据缓冲寄存器,并置位接受缓冲区非空标志;
3、用于收发数据CRC计算;
4、用于I2C模块控制及相关标志位查询;
5、系统通过APB总线对I2C数据寄存器及控制寄存器进行操作。
各系列 I2C 功能差异
GD32各系列MCU有关IIC功能差异如表 5-11各系列I2C功能差异表所示。
5.7.3. 硬件连接说明
如图 5-20 AT24C02C EEPROM IIC接口参考电路图所示,AT24C02C为IIC接口的EEPROM,该电路图为其典型参考电路,其中5脚为I2C SDA引脚,6脚为I2C SCL引脚,I2C总线需要通过4.7K欧姆电阻上拉。
5.7.4. 软件配置说明
本小节讲解I2C_Example下的I2C0主机历程,本例程讲解IIC作为主机情况下对从机的读写,并引入超时恢复机制。
IIC 初始化配置
IIC初始化配置代码如代码清单 5-23 I2C初始化配置所示,首先进行GPIO初始化,然后对IIC外设进行初始化。
注意本例程仅讲解IIC0的外设引脚及模块初始化,若其他IIC模块可参考修改。
时钟及 GPIO 引脚配置
时钟及GPIO引脚配置如代码清单 5-24 I2C时钟及GPIO引脚配置所示,在历程中PB6、PB7引脚需要配置为复用开漏模式。
代码清单 5-24 I2C 时钟及 GPIO 引脚配置
void GPIO_Configuration_I2C(uint32_t I2Cx)
{
uint32_t GPIO_SDA;
uint32_t GPIO_SCL;
uint32_t GPIO_Pin_SDA,GPIO_Pin_SCL;
rcu_periph_reset_enable(RCU_I2C0RST);
rcu_periph_reset_disable(RCU_I2C0RST);
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F4XX || GD32F3X0 ||
GD32E23X
/* enable GPIOB clock */
rcu_periph_clock_enable(RCU_GPIOB);
/* enable I2C0 clock */
rcu_periph_clock_enable(RCU_I2C0);
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X
rcu_periph_clock_enable(RCU_AF);
#elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X
#endif
GPIO_SCL=GPIOB;
GPIO_Pin_SCL=GPIO_PIN_6;
GPIO_SDA=GPIOB;
GPIO_Pin_SDA=GPIO_PIN_7;
#endif
/* Reset I2C1 IP */
// I2C_DeInit(I2Cx);
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X
/* I2C0 GPIO ports */
/* connect PB6 to I2C0_SCL */
gpio_init(GPIO_SCL, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SCL);
/* connect PB7 to I2C0_SDA */
gpio_init(GPIO_SDA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SDA);
#elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X
#if defined GD32F1X0 || GD32F3X0 || GD32E23X
/* I2C GPIO ports */
/* connect I2C_SCL_GPIO_PIN to I2C_SCL */
gpio_af_set(GPIO_SCL, GPIO_AF_1, GPIO_Pin_SCL);
/* connect I2C_SDA_GPIO_PIN to I2C_SDA */
gpio_af_set(GPIO_SDA, GPIO_AF_1, GPIO_Pin_SDA);
#elif defined GD32F4XX
gpio_af_set(GPIO_SCL, GPIO_AF_4, GPIO_Pin_SCL);
gpio_af_set(GPIO_SDA, GPIO_AF_4, GPIO_Pin_SDA);
#endif
gpio_mode_set(GPIO_SCL, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_Pin_SCL);
gpio_output_options_set(GPIO_SCL, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SCL);
gpio_mode_set(GPIO_SDA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_Pin_SDA);
gpio_output_options_set(GPIO_SDA, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SDA);
#endif
}
I2C 多字节写操作
I2C多字节写操作如代码清单 5-25 IIC写多字节操作所示,该函数接口实现IIC外设对IIC从机的多字节写操作。
代码清单 5-25 IIC 写多字节操作
/*!
\brief I2Cx Write NBytes
\param[in] i2c_periph : I2Cx(x=0,1)
\param[in] addr : slave address
\param[in] start_Addr : reg
\param[in] number_Bytes: number to Write
\param[in] ADDR_Length : number of the addr
*/
I2C_Status I2Cx_Write_NBytes(uint32_t I2Cx,uint8_t driver_Addr, uint16_t start_Addr, uint8_t number_Bytes, uint8_t
*write_Buffer,uint8_t ADDR_Length)
{
uint32_t I2C_Timeout = I2C_SHORT_TIMEOUT;
i2c_ack_config(I2Cx,I2C_ACK_ENABLE);
while(i2c_flag_get(I2Cx, I2C_FLAG_I2CBSY))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
i2c_start_on_bus(I2Cx);
I2C_Timeout = I2C_SHORT_TIMEOUT;
while(!i2c_flag_get(I2Cx, I2C_FLAG_SBSEND))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
i2c_master_addressing(I2Cx, driver_Addr, I2C_TRANSMITTER);
I2C_Timeout = I2C_SHORT_TIMEOUT;
while(!i2c_flag_get(I2Cx, I2C_FLAG_ADDSEND))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
i2c_flag_clear(I2Cx,I2C_FLAG_ADDSEND);
I2C_Timeout = I2C_SHORT_TIMEOUT;
while(SET != i2c_flag_get( I2Cx , I2C_FLAG_TBE ))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
i2c_enable(I2Cx);
if(ADDR_Length)//'A 1/2 ×"O 1/2 'UμO"O·
{
i2c_data_transmit(I2Cx, (uint8_t)((start_Addr & 0xFF00) >> 8));
I2C_Timeout = I2C_SHORT_TIMEOUT;
while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
i2c_data_transmit(I2Cx, (uint8_t)(start_Addr & 0x00FF));
}
else
{
i2c_data_transmit(I2Cx, start_Addr);
}
I2C_Timeout = I2C_SHORT_TIMEOUT;
while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
while(number_Bytes)
{
i2c_data_transmit(I2Cx, *write_Buffer);
I2C_Timeout = I2C_SHORT_TIMEOUT;
//while (!I2C_CheckEvent(I2Cx,
I2C_EVENT_MASTER_BYTE_TRANSMITTED))//5
// while(!i2c_flag_get(I2Cx, I2C_BTC))//
while(!i2c_flag_get(I2Cx, I2C_FLAG_TBE))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
/* point to the next location where the byte read will be saved */
write_Buffer++;
/* decrement the read bytes counter */
number_Bytes--;
}
// while(!i2c_flag_get(I2C1, I2C_BTC))
// {
// if((I2C_Timeout--) == 0)
// {
// Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
// return I2C_FAIL;
// }
// }
/* send a stop condition to I2C bus */
i2c_stop_on_bus(I2Cx);
I2C_Timeout = I2C_SHORT_TIMEOUT;
while (I2C_CTL0(I2Cx) & 0x0200)
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
i2c_ack_config(I2Cx,I2C_ACK_ENABLE);
return I2C_OK;
}
IIC 多字节读操作
IIC多字节读操作如代码清单 5-26 IIC多字节读操作所示,该函数接口可实现对IIC从机的多字节读功能。
代码清单 5-26 IIC 多字节读操作
I2C_Status I2Cx_Read_NBytes(uint32_t I2Cx,uint8_t driver_Addr, uint16_t start_Addr, uint8_t number_Bytes, uint8_t
*read_Buffer,uint8_t ADDR_Length)
{
uint32_t I2C_Timeout = I2C_SHORT_TIMEOUT;
i2c_ack_config(I2Cx,I2C_ACK_ENABLE);
while(i2c_flag_get(I2Cx, I2C_FLAG_I2CBSY))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
if(number_Bytes==2)
{
i2c_ackpos_config(I2Cx,I2C_ACKPOS_NEXT);
}
i2c_start_on_bus(I2Cx);
I2C_Timeout = I2C_SHORT_TIMEOUT;
while(!i2c_flag_get(I2Cx, I2C_FLAG_SBSEND))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
i2c_master_addressing(I2Cx, driver_Addr, I2C_TRANSMITTER);
I2C_Timeout = I2C_SHORT_TIMEOUT;
while(!i2c_flag_get(I2Cx, I2C_FLAG_ADDSEND))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
/* clear the ADDSEND bit */
i2c_flag_clear(I2Cx,I2C_FLAG_ADDSEND);
I2C_Timeout = I2C_SHORT_TIMEOUT;
while(SET != i2c_flag_get( I2Cx , I2C_FLAG_TBE ))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
i2c_enable(I2Cx);
if(ADDR_Length)//'A 1/2 ×"O 1/2 'UμO"O·
{
i2c_data_transmit(I2Cx, (uint8_t)((start_Addr & 0xFF00) >> 8));
I2C_Timeout = I2C_SHORT_TIMEOUT;
//while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
i2c_data_transmit(I2Cx, (uint8_t)(start_Addr & 0x00FF));
}
else
{
i2c_data_transmit(I2Cx, start_Addr);
}
I2C_Timeout = I2C_SHORT_TIMEOUT;
while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
i2c_start_on_bus(I2Cx);
I2C_Timeout = I2C_SHORT_TIMEOUT;
while(!i2c_flag_get(I2Cx, I2C_FLAG_SBSEND))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
i2c_master_addressing(I2Cx, driver_Addr, I2C_RECEIVER);
I2C_Timeout = I2C_SHORT_TIMEOUT;
if(number_Bytes<3)
{
i2c_ack_config(I2Cx,I2C_ACK_DISABLE);
}
while(!i2c_flag_get(I2Cx, I2C_FLAG_ADDSEND))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
/* clear the ADDSEND bit */
i2c_flag_clear(I2Cx,I2C_FLAG_ADDSEND);
if(number_Bytes==1)
{
i2c_stop_on_bus(I2Cx);
}
while(number_Bytes)
{
if(3 == number_Bytes){
/* wait until BTC bit is set */
I2C_Timeout = I2C_LONG_TIMEOUT;
while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
/* disable acknowledge */
/* disable acknowledge */
i2c_ack_config(I2Cx,I2C_ACK_DISABLE);
}
if(2 == number_Bytes){
/* wait until BTC bit is set */
I2C_Timeout = I2C_LONG_TIMEOUT;
while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC))
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
/* send a stop condition to I2C bus */
i2c_stop_on_bus(I2Cx);
I2C_Timeout = I2C_SHORT_TIMEOUT;
while (I2C_CTL0(I2Cx) & 0x0200)
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
}
/* wait until the RBNE bit is set and clear it */
if(i2c_flag_get(I2Cx, I2C_FLAG_RBNE)){
/* read a byte from the EEPROM */
*read_Buffer = i2c_data_receive(I2Cx);
/* point to the next location where the byte read will be saved */
read_Buffer++;
/* decrement the read bytes counter */
number_Bytes--;
}
}
while(I2C_CTL0(I2Cx)&0x0200)
{
if((I2C_Timeout--) == 0)
{
Resume_IIC(I2C_LONG_TIMEOUT,I2Cx);
return I2C_FAIL;
}
}
/* enable acknowledge */
i2c_ack_config(I2Cx,I2C_ACK_ENABLE);
i2c_ackpos_config(I2Cx,I2C_ACKPOS_CURRENT);
return I2C_OK;
}
IIC 超时恢复机制
IIC超时恢复机制实现如代码清单 5-27 IIC超时恢复机制所示。
代码清单 5-27 IIC 超时恢复机制
uint32_t I2C_Timeout;
void Delay_I2C(uint32_t i)
{
while(i--);
}
void Resume_IIC(uint32_t Timeout,uint32_t I2Cx )
{
uint32_t GPIO_SDA;
uint32_t GPIO_SCL;
uint32_t GPIO_Pin_SDA,GPIO_Pin_SCL;
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F4XX || GD32F3X0 ||
GD32E23X
/* enable GPIOB clock */
rcu_periph_clock_enable(RCU_GPIOB);
/* enable I2C0 clock */
rcu_periph_clock_enable(RCU_I2C0);
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X
rcu_periph_clock_enable(RCU_AF);
#elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X
#endif
#endif
GPIO_SCL=GPIOB;
GPIO_Pin_SCL=GPIO_PIN_6;
GPIO_SDA=GPIOB;
GPIO_Pin_SDA=GPIO_PIN_7;
do{
#if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X
/* I2C0 GPIO ports */
/* connect PB6 to I2C0_SCL */
gpio_init(GPIO_SCL, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SCL);
/* connect PB7 to I2C0_SDA */
gpio_init(GPIO_SDA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SDA);
#elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X
#if defined GD32F1X0 || GD32F3X0 || GD32E23X
/* I2C GPIO ports */
/* connect I2C_SCL_GPIO_PIN to I2C_SCL */
gpio_af_set(GPIO_SCL, GPIO_AF_1, GPIO_Pin_SCL);
/* connect I2C_SDA_GPIO_PIN to I2C_SDA */
gpio_af_set(GPIO_SDA, GPIO_AF_1, GPIO_Pin_SDA);
#elif defined GD32F4XX
gpio_af_set(GPIO_SCL, GPIO_AF_4, GPIO_Pin_SCL);
gpio_af_set(GPIO_SDA, GPIO_AF_4, GPIO_Pin_SDA);
#endif
gpio_mode_set(GPIO_SCL, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_Pin_SCL);
gpio_output_options_set(GPIO_SCL, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SCL);
gpio_mode_set(GPIO_SDA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_Pin_SDA);
gpio_output_options_set(GPIO_SDA, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SDA);
#endif
gpio_bit_reset(GPIO_SCL, GPIO_Pin_SCL);
Delay_I2C(20);
gpio_bit_reset(GPIO_SDA, GPIO_Pin_SDA);
Delay_I2C(20);
gpio_bit_set(GPIO_SCL, GPIO_Pin_SCL);
Delay_I2C(20);
gpio_bit_set(GPIO_SDA, GPIO_Pin_SDA);
Delay_I2C(20);
if(Timeout-- == 0) return;
}while((!gpio_input_bit_get(GPIO_SDA, GPIO_Pin_SDA))&(!gpio_input_bit_get(GPIO_SCL, GPIO_Pin_SCL)));
I2C_init(I2Cx);
}
主函数说明
本例程主函数如代码清单 5-28 I2C例程主函数所示。
代码清单 5-28 I2C 例程主函数
int main(void)
{
I2C_init(I2C0);
I2Cx_Write_NBytes(I2C0,0xA0, 0,8, Write_Buf,0);
I2Cx_Read_NBytes(I2C0,0xA0, 0,8, Read_Buf,0);
while (1)
{
}
5.7.5. I2C 使用注意事项
1. I2C总线需要上拉;
2. I2C引脚需要配置为复用开漏模式;
3. 若采用查询方式进行I2C数据传输,有可能会由于总线干扰,导致I2C卡死,可以在查询方式上增加超时机制,如果超时重配IIC恢复总线通信(注意重配IIC时,建议先将I2C模块Deinit,然后在调用Init函数进行初始化)。
4. 若采用软件模拟IIC的方式,在移植过程中出现问题,可能是由于代码执行效率的问题,可以排查软件延迟时间和其他芯片上的软件延迟时间是否相同,可以通过调整软件延迟时间进行测试;
或者有可能是由于初始化配置IO端口的时候可能会引入干扰,可以先配置IO口输出高,然后再配置为推挽或开漏模式。
猜你喜欢
- 2025-05-11 带来极致静音体验:酷冷至尊新款1100W电源采用被动散热
- 2025-05-11 CUI 的3 kW 白金前端Ac-Dc电源瞄准以太网供电(PoE)应用
- 2025-05-11 STM32单片机详细教学(二):STM32系列单片机的介绍
- 2025-05-11 赛灵思FPGA原理图设计3-参考板电源时序探究
- 2025-05-11 常用数字接口(3) I2C(数字接口技术)
- 2025-05-11 你敢信吗!酷冷至尊1100W电源不需要风扇
- 2025-05-11 慧易芯受邀出席“申威产品发布暨申威产业联盟发展大会”
- 2025-05-11 Vicor 最新 270V—28V DCM5614 以 96% 的效率提供 1300W 的功率
- 2025-05-11 1100W电源不需要风扇!酷冷至尊做到了
- 2025-05-11 基于STM32和GPRS的无线油井监控器*
你 发表评论:
欢迎- 最近发表
-
- 数据不丢失 从Windows 11的DEV版降级到正式版
- Win11学院:在Windows11 25905预览版中如何启用Dev Drive
- DEVC++的卸载(devcon卸载驱动)
- win11 dev 开发版 升级攻略完整版
- 最新Windows11+Windows10系统各种版本永久激活密钥以及下载链接
- 想学Python,却还记不住语法?神仙书籍 python背记手册双手奉上
- 如何用Python语言开发大型服务器程序
- 30天Python 入门到精通(python零基础入门到精通)
- 入门扫盲:9本自学Python PDF书籍,让你避免踩坑,轻松变大神!
- 学好Python需要看的4本书推荐(学python好用的书)
- 标签列表
-
- spire.doc (59)
- system.data.oracleclient (61)
- 按键小精灵源码提取 (66)
- pyqt5designer教程 (65)
- 联想刷bios工具 (66)
- c#源码 (64)
- graphics.h头文件 (62)
- mysqldump下载 (66)
- sqljdbc4.jar下载 (56)
- libmp3lame (60)
- maven3.3.9 (63)
- 二调符号库 (57)
- 苹果ios字体下载 (56)
- git.exe下载 (68)
- diskgenius_winpe (72)
- pythoncrc16 (57)
- solidworks宏文件下载 (59)
- qt帮助文档中文版 (73)
- satacontroller (66)
- hgcad (64)
- bootimg.exe (69)
- android-gif-drawable (62)
- axure9元件库免费下载 (57)
- libmysqlclient.so.18 (58)
- springbootdemo (64)
本文暂时没有评论,来添加一个吧(●'◡'●)