四、GD32 MCU 常见外设介绍 (7) 7.I2C 模块介绍

7.1.I2C 基础知识

I2C(Inter-Integrated Circuit)总线是一种由Philips公司开发的两线式串行总线,用于内部IC控制的具有多端控制能力的双线双向串行数据总线系统,能够用于替代标准的并行总线,连接各种集成 电路和功能模块。I2C器件能够减少电路间的连接,减少电路板的尺寸,降低硬件成本并提高系统的可靠性。I2C总线传输模式具有向下兼容性,传输速率标准模式下可达100kbps,快速模式下可 达400kbps,高速模式下可达3.4Mbps。

为了清楚起见,在此对I2C通信中关于设备的基本概念进行简要讲解。

① 发送设备:发送数据到总线上的设备。

② 接收设备:从总线上接收数据的设备。

③ 主设备:启动数据传输并产生时钟信号的设备。

④ 从设备:被主设备寻址的设备。

多主:多个主设备可以尝试在不破坏信息的前提下同时控制线。

同步:同步两个或更多设备之间的时钟信号的过程。

仲裁:如果超过一个主设备同时试图控制总线,只有一个主设备被允许,且获胜主设备的信息不被破坏。

(1)I2C设备连接原理 I2C设备连接示意图如设备连接示意图所示。I2C总线是由数据线SDA和时钟线SCL构成的串行总线,可发送和接收数据。在GD32 MCU与被控IC(集成电路)之间、IC与IC之间进行双向传送,最高传送速率1Mbps。各种设备均并联在总线上,两条总线都被上拉电阻上拉到VCC,所有设备地位对等,都可作为主机或从机,就像电话机一样只要拨通各自的号码就能正常工作,所以,每个设备都有唯一的地址。在信息的传输过程中,I2C总线上并接的每个设备既是主设备(或从设备),又是发送设备(或接收设备),这取决于它所要完成的功能。每个设备都可以把总线接地拉低,却不允许把总线电平直接连到VCC上置高。把总线电平拉低称为占用总线,总线电平为高等待被拉低则称为总线被释放。

I2C 设备连接示意图

由于SDA和SCL均为双向I/O线,都是开漏极端(输出1时,为高阻状态),因此I2C总线上的所有设备的SDA和SCL引脚都要外接上拉电阻。

(2)I2C数据通信协议

I2C数据通信时序图如I2C数据通信时序图所示。下面首先介绍起始位和停止位,起始位和停止位都是由主设备产生的,如图中虚线所示。当SCL时钟线为高电平时,SDA数据线上由高到低的跳变,产生一个开始信号,即起始位。当SCL时钟线为高电平时,SDA数据线上由低到高的跳变,将产生一个停止信号,即停止位。起始位之后,总线被认为忙,即有数据在传输,传输的第一个字节,即7位从地址和R/ ̄W 位。当R/ ̄W位为0时,主机向从机发送数据;当R/ ̄W位为1时,主机接收来自从机的数据。在每个字节后的第九个SCL时钟上,接收机发送ACK位。停止位之后,总线被认为闲,空闲状态时,SDA和SCL都是高电平。

注意:当SCL位为高电平时,SDA的数据必须保持稳定,否则,由于起始位和停止位的电气边沿特性,SDA上数据发生改变将被识别为起始位或停止位。所以,只有当SCL为低电平时才允许SDA上的数据改变。

I2C 数据通信时序图

 I2C总线上每位数据传输的示意图

(3)I2C的寻址方式 GD32 MCU的I2C模块支持7位和10位两种寻址模式,7位寻址模式最多寻址128个设备,10位寻址模式最多寻址1024个设备。I2C总线理论上可以允许的最大设备数是以总线上所有器件的电容总和不超过400pF为限(其中,包括连线本身的电容和其连接端的引出等效电容),总线上所有器件要依靠SDA发送的地址信号寻址,不需要片选信号。

① 7位寻址模式

如图下图所示为7位地址方式下的I2C数据传输格式,第一个字节由7位从地址和R/ ̄W读/写位组成。不论总线上传送的是地址还是数据信息,每个字节传输完毕,接收设备都会发送响应位(ACK)。地址类信息传输之后是数据信息,直到接收到停止信息。

7 位寻址模式数据格式

② 10位寻址模式

如下图所示为10位地址方式下的I2C数据传输格式。第一个字节由二进制位11110、从地址的最高两位及R/ ̄W读/写控制位组成。第一个字节传输完毕后是ACK响应位。第二个字节就是10位从地址的低8位,后面是响应位和数据。

10 位寻址模式数据格式

③ 二次发送从地址模式(重复产生起始条件)

主机可以在不停止数据传输的情况下,通过产生重复的起始条件,改变SDA上数据流的方向,这称为RESTART。再次发送起始信号后,需重新发送从地址和R/ ̄W读/写控制位。重新产生起始条件数据传输格式如图所示。

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内部结构框图如下图所示,该结构框图可分为五个部分:1、用于产生I2C通信时序;2、用于收发I2C数据,当有数据需要发送时,会首先将数据填充到数据寄存器,然后数据被自动移位到移位寄存器,通过SDA引脚发送出去,当有数据需要接受时,首先会根据SCL选择的时钟边沿在移位寄存器中锁存SDA数据,当数据接受到后,数据被移到数据缓冲寄存器,并置位接受缓冲区非空标志;3、用于收发数据CRC计算;4、用于I2C模块控制及相关标志位查询;5、系统通过APB总线对I2C数据寄存器及控制寄存器进行操作。

 

各系列 I2C 功能差异

GD32各系列MCU有关IIC功能差异如各系列I2C功能差异表所示。

7.3.硬件连接说明

如AT24C02C EEPROM IIC接口参考电路图所示,AT24C02C为IIC接口的EEPROM,该电路图为其典型参考电路,其中5脚为I2C SDA引脚,6脚为I2C SCL引脚,I2C总线需要通过4.7K欧姆电阻上拉。

 

7.4.软件配置说明

本小节讲解I2C_Example下的I2C0主机历程,本例程讲解IIC作为主机情况下对从机的读写,并引入超时恢复机制。

IIC 初始化配置

IIC初始化配置代码如代码清单I2C初始化配置所示,首先进行GPIO初始化,然后对IIC外设进行初始化。注意本例程仅讲解IIC0的外设引脚及模块初始化,若其他IIC模块可参考修改。

void I2C_init(uint32_t I2Cx)
{ GPIO_Configuration_I2C(I2Cx);i2c_clock_config(I2Cx, 400000, I2C_DTCY_2);/* I2C address configure */i2c_mode_addr_config(I2Cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0);/* enable acknowledge */i2c_ack_config(I2Cx, I2C_ACK_DISABLE);/* enable I2Cx */i2c_enable(I2Cx);
}

时钟及 GPIO 引脚配置

时钟及GPIO引脚配置如代码清单I2C时钟及GPIO引脚配置所示,在例程中PB6、PB7引脚需要配置为复用开漏模式。

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
#endifGPIO_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 GD32F4XXgpio_af_set(GPIO_SCL, GPIO_AF_4, GPIO_Pin_SCL);gpio_af_set(GPIO_SDA, GPIO_AF_4, GPIO_Pin_SDA);
#endifgpio_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多字节写操作如代码清单IIC写多字节操作所示,该函数接口实现IIC外设对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)//Á½×Ö½ÚµØÖ·
{
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多字节读操作如代码清单IIC多字节读操作所示,该函数接口可实现对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)//Á½×Ö½ÚµØÖ·
{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超时恢复机制实现如代码清单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);
}

主函数说明

本例程主函数如代码清单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){ }

7.5.I2C 使用注意事项

  1. I2C总线需要上拉;

  2. I2C引脚需要配置为复用开漏模式;

  3. 若采用查询方式进行I2C数据传输,有可能会由于总线干扰,导致I2C卡死,可以在查询方式上增加超时机制,如果超时重配IIC恢复总线通信(注意重配IIC时,建议先将I2C模块Deinit,然后 在调用Init函数进行初始化)。

  4. 若采用软件模拟IIC的方式,在移植过程中出现问题,可能是由于代码执行效率的问题,可以排查软件延迟时间和其他芯片上的软件延迟时间是否相同,可以通过调整软件延迟时间进行测试;或者有可能是由于初始化配置IO端口的时候可能会引入干扰,可以先配置IO口输出高,然后再配置为推挽或开漏模式。

本章内容每日持续更新,如有兴趣,请关注收藏

更多GD32 MCU相关咨询:https://www.gd32bbs.com/ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/49815.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

整合StarRocks主键表全部知识点

总结StarRocks主键表的全部内容的集合&#xff08;V3.2版本&#xff09; 一、基本功能 主键非空约束&#xff0c;任何一个字段都不可以为空支持导入数据时删除数据操作(CDC)支持部分更新支持独立的排序键&#xff08;只有主键表支持独立排序键&#xff0c;而且可以不为key键&…

极限科技闪耀 2024 可信数据库发展大会,多款自研产品引领搜索技术新纪元

北京&#xff0c;7 月 16、17 日 —— 在由中国信息通信研究院&#xff08;中国信通院&#xff09;与中国通信标准化协会联合主办&#xff0c;InfoQ 协办的“2024 可信数据库发展大会”&#xff08;TDBC 2024&#xff09;上&#xff0c;极限科技凭借其前沿的搜索技术创新与卓越…

【相机与图像】1. 相机模型的介绍:内参、外参、畸变参数

想着整理下相机模型&#xff08;内容上参考 slam十四讲&#xff09;、相机的内外参标定。方便自己的使用和回顾。 不过&#xff0c;内外参标定啥时候记录随缘 -_- 概述 【构建相机模型】 相机将三位世界中的坐标点&#xff08;单位为米&#xff09;映射到二维图像平面&#xff…

py Qt5学习记录

1.Qt5的安装 可参考一些博客如&#xff1a;Python 小白从零开始 PyQt5 项目实战&#xff08;2&#xff09;菜单和工具栏_pyqt 二级菜单-CSDN博客 2.Qt5的界面显示 3.新建一个工具栏并打开本地文件方法 &#xff08;1&#xff09;在Qt5界面右下角有个“动作编辑器”&#xff…

每日一题~961div2A+B+C(阅读题,思维,数学log)

A 题意&#xff1a;给你 n*n 的表格和k 个筹码。每个格子上至多放一个 问至少占据多少对角线。 显然&#xff0c;要先 格数的多的格子去放。 n n-1 n-2 …1 只有n 的是一个&#xff08;主对角线&#xff09;&#xff0c;其他的是两个。 #include <bits/stdc.h> using na…

基于微信小程序图书馆座位预约管理系统设计与实现

1.1选题动因 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和工作的领域。随着电脑和笔记本的广泛运用&#xff0c;以及各种计算机硬件的完善和升级&#x…

JS 事件循环(Event Loop)机制

事件循环机制的作用 事件循环机制是 JS 的一种执行机制&#xff0c;一种可以实现异步编程的机制。 因为 JS 是单线程的&#xff0c;单线程意味着所有任务需要排队执行。但是有一些 API&#xff08;比如&#xff1a;定时器和 Ajax 等&#xff09;是需要等待一定的时间才能得到…

【Python】一文向您详细介绍 K-means 算法

【Python】一文向您详细介绍 K-means 算法 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的普通本硕&#xff…

Visual Studio 2022新建 cmake 工程测试 tensorRT 自带样例 sampleOnnxMNIST

1. 新建 cmake 工程 vs2022_cmake_sampleOnnxMNIST_test( 如何新建 cmake 工程&#xff0c;请参考博客&#xff1a;Visual Studio 2022新建 cmake 工程测试 opencv helloworld ) 2. 删除默认生成的 vs2022_cmake_sampleOnnxMNIST_test.h 头文件 3. 修改默认生成的 vs2022_cma…

BSV区块链在人工智能时代的数字化转型中的角色

​​发表时间&#xff1a;2024年6月13日 企业数字化转型已有约30年的历史&#xff0c;而人工智能&#xff08;以下简称AI&#xff09;将这种转型提升到了一个全新的高度。这并不难理解&#xff0c;因为AI终于使企业能够发挥其潜力&#xff0c;实现更宏大的目标。然而&#xff0…

MySQL中实现动态表单中JSON元素精准匹配的方法

目录 前言 一、动态表单技术 1、包含的主要信息 2、元素属性设置 3、表单内容 二、表单数据存储和查询 1、数据存储 2、数据的查询 3、在5.7版本中进行JSON检索 4、8.0后的优化查询 三、总结 前言 在很多有工作流设置的地方、比如需要在不同的流程中&#xff0c;需要…

服务器数据恢复—V7000存储硬盘故障脱机的数据恢复案例

服务器存储数据恢复环境&#xff1a; 某品牌P740小型机AIXSybaseV7000磁盘阵列柜&#xff0c;磁盘阵列柜中有12块SAS机械硬盘&#xff08;其中包括一块热备盘&#xff09;。 服务器存储故障&#xff1a; 磁盘阵列柜中有一块磁盘出现故障&#xff0c;运维人员用新硬盘替换掉故障…

网络安全等级保护解决方案的主打产品

网络安全等级保护解决方案的主打产品&#xff1a; HiSec Insight安全态势感知系统、 FireHunter6000沙箱、 SecoManager安全控制器、 HiSecEngine USG系列防火墙和HiSecEngine AntiDDoS防御系统。 华为HiSec Insight安全态势感知系统是基于商用大数据平台FusionInsight的A…

【LeetCode】201. 数字范围按位与

1. 题目 2. 分析 这题挺难想的&#xff0c;我到现在还没想明白&#xff0c;为啥只用左区间和右区间就能找到目标值了&#xff0c;而不用挨个做与操作&#xff1f; 3. 代码 class Solution:def rangeBitwiseAnd(self, left: int, right: int) -> int:left_bin bin(left).…

k8s集群可视化工具安装(dashboard)

可视化安装 2.1、下载相关的yaml文件 wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml Vim recommended.yaml 2.2、部署 kubectl apply -f recommended.yaml 查看那kubernetes-dashboard命令空间下的资源 kubectl get …

ZLMRTCClient配置说明与用法(含示例)

webRTC播放视频 后面在项目中会用到通过推拉播放视频流的技术&#xff0c;所以最近预研了一下webRTC 首先需要引入封装好的webRTC客户端的js文件ZLMRTCClient.js 下面是地址需要的自行下载 http://my.zsyou.top/2024/ZLMRTCClient.js 配置说明 new ZLMRTCClient.Endpoint…

技术分享!国产ARM + FPGA的SDIO通信开发介绍!

SDIO总线介绍 SDIO(Secure Digital lnput and Output),即安全数字输入输出接口。SDIO总线协议是由SD协议演化而来,它主要是对SD协议进行了一些扩展。 SDIO总线主要是为SDIO卡提供一个高速的I/O能力,并伴随着较低的功耗。SDIO总线不但支持SDIO卡,而且还兼容SD内存卡。支持…

韦东山嵌入式linux系列-具体单板的按键驱动程序(查询方式)

1 GPIO 操作回顾 &#xff08;1&#xff09;使能模块&#xff1b; &#xff08;2&#xff09;设置引脚的模式&#xff08;工作于GPIO模式&#xff09;&#xff1b; &#xff08;3&#xff09;设置GPIO本身&#xff08;输入/输出&#xff09;&#xff1b; &#xff08;4&…

在VMware创建Ubuntu24

目录 一、创建虚拟机 1. 自定义创建虚拟机 2. 设置虚拟机兼容 3. 选择镜像 4. 命名虚拟机&#xff0c;选择存放位置 5. 处理器配置 6. 内存配置 7. 网络类型配置 8. I/O控制器类型 9. 磁盘配置 10. 完成虚拟机创建 二、Ubuntu安装 1. 进入虚拟机中进行ubuntu的安…

浏览器打开PDF卡在加载(侧边翻译插件打不开PDF)

如果你的浏览器安装了一些翻译插件&#xff0c;那么可能会导致PDF加载不出来 比如我的浏览器中安装了“侧边翻译”&#xff0c;而我在view Elsever的论文时出现了加载不出来的问题—— 仍然以此扩展为例&#xff0c;那么解决办法是&#xff1a; 取消勾选——