四、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 使用注意事项
-
I2C总线需要上拉;
-
I2C引脚需要配置为复用开漏模式;
-
若采用查询方式进行I2C数据传输,有可能会由于总线干扰,导致I2C卡死,可以在查询方式上增加超时机制,如果超时重配IIC恢复总线通信(注意重配IIC时,建议先将I2C模块Deinit,然后 在调用Init函数进行初始化)。
-
若采用软件模拟IIC的方式,在移植过程中出现问题,可能是由于代码执行效率的问题,可以排查软件延迟时间和其他芯片上的软件延迟时间是否相同,可以通过调整软件延迟时间进行测试;或者有可能是由于初始化配置IO端口的时候可能会引入干扰,可以先配置IO口输出高,然后再配置为推挽或开漏模式。
本章内容每日持续更新,如有兴趣,请关注收藏
更多GD32 MCU相关咨询:https://www.gd32bbs.com/
相关文章:

四、GD32 MCU 常见外设介绍 (7) 7.I2C 模块介绍
7.1.I2C 基础知识 I2C(Inter-Integrated Circuit)总线是一种由Philips公司开发的两线式串行总线,用于内部IC控制的具有多端控制能力的双线双向串行数据总线系统,能够用于替代标准的并行总线,连接各种集成 电路和功能模块。I2C器件能够减少电…...

Apollo 配置中心的部署与使用经验
前言 Apollo(阿波罗)是携程开源的分布式配置管理中心。 本文主要介绍其基于 Docker-Compose 的部署安装和一些使用的经验 特点 成熟,稳定支持管理多环境/多集群/多命名空间的配置配置修改发布实时(1s)通知到应用程序支…...

Perl中的设计模式革新:命令模式的实现与应用
Perl中的设计模式革新:命令模式的实现与应用 在面向对象编程中,设计模式是解决特定问题的成熟模板。命令模式作为行为设计模式之一,它将请求封装为对象,从而允许用户根据不同的请求对客户进行参数化。本文将深入探讨如何在Perl中…...

Java8-求两个集合取交集
在Java8中,求两个集合的交集可以使用不同的三种方式:传统的循环遍历、使用Stream API的filter操作和使用Stream API的Collection操作。 方法一:传统的循环遍历 首先,我们创建两个集合list1和list2,并给它们添加一些元…...

爬虫学习4:爬取王者荣耀技能信息
爬虫:爬取王者荣耀技能信息(代码和代码流程) 代码 # 王者荣耀英雄信息获取 import time from selenium import webdriver from selenium.webdriver.common.by import By if __name__ __main__:fp open("./honorKing.txt", "…...

在Ubuntu 14.04上安装和使用Memcache的方法
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 简介 随着您的网站的增长和流量的增加,最快显示压力的组件之一是后端数据库。如果您的数据库没有分布式和配置来处理高负载…...

PCDN技术如何降低运营成本?
PCDN技术通过以下几种方式降低运营商的运营成本: 1.利用用户设备作为缓存节点: PCDN技术将用户设备纳入内容分发网络,利用这些设备的闲置带宽和存储资源来缓存和分发内容。这种方式不需要运营商投入大量的高成本服务器和带宽资源,从而降低了硬件和带宽…...

服务器数据恢复—V7000存储硬盘故障脱机的数据恢复案例
服务器存储数据恢复环境: 某品牌P740小型机AIXSybaseV7000磁盘阵列柜,磁盘阵列柜中有12块SAS机械硬盘(其中包括一块热备盘)。 服务器存储故障: 磁盘阵列柜中有一块磁盘出现故障,运维人员用新硬盘替换掉故障…...

BSV区块链在人工智能时代的数字化转型中的角色
发表时间:2024年6月13日 企业数字化转型已有约30年的历史,而人工智能(以下简称AI)将这种转型提升到了一个全新的高度。这并不难理解,因为AI终于使企业能够发挥其潜力,实现更宏大的目标。然而࿰…...

android audio 相机按键音:(二)加载与修改
相机按键音资源,加载文件路径: frameworks/av/services/camera/libcameraservice/CameraService.cpp 按键音,加载函数: void CameraService::loadSoundLocked(sound_kind kind) { ATRACE_CALL(); LOG1("Cam…...

Linux grep技巧 提取log中的json数据
目录 一. 前提1.1 数据准备1.2 需求1.3 分析 二. 数据提取2.1 提取所有的json数据2.2 提取子项目的全部json数据2.3 提取指定项目的json数据 一. 前提 1.1 数据准备 545-1 2024/07/20 18:20:21 [ERROR] MPX001 eventControlleraupay transactionIdA545 {"event":&q…...

HDShredder 7 企业版案例分享: 依照国际权威标准,安全清除企业数据
HDShredder 7 企业版用户案例 天津鸿萌科贸发展有限公司是德国 Miray 公司 HDShredder 数据清除软件的授权代理商。近日,上海某网络科技有限公司采购 HDShredder 7 企业版x4,为公司数据存储资产的安全清除工作流程配备高效的执行工具。HDShredder 7 企业…...

centos系统使用mysqldump数据备份与恢复
文章目录 使用mysqldump备份数据库一、数据库备份1. 基础备份2. 额外选项(一般组合使用) 二、数据库恢复 使用mysqldump备份数据库 一、数据库备份 1. 基础备份 #备份单个数据库 mysqldump -u 用户名 -p 数据库名 > 备份文件.sql#备份多个数据库 mysqldump -u 用户名 -p …...

【element ui】input输入控件绑定粘贴事件,从 Excel 复制的数据粘贴到输入框(el-input)时自动转换为逗号分隔的数据
目录 1、需求2、实现思路:3、控件绑定粘贴事件事件修饰符说明: 4、代码实现🚀写在最后 1、需求 在 Vue 2 和 Element UI 中,要实现从 Excel 复制空格分隔的数据,并在粘贴到输入框(el-input)时自动转换为逗号分隔的数据…...

Chapter18 基于物理的渲染——Shader入门精要学习
Chapter18 基于物理的渲染 一、PBS理论和数学基础1.光是什么微表面模型 2.渲染方程3.精确光源4.双向反射分布函数 BRDF5.漫反射项(Lambert 模型)Lambertian BRDF为:Disney BRDF中漫反射项 6.高光反射项微面元理论BRDF的高光反射项①菲涅尔反射…...

DolphinScheduler学习
1.查看文档 点击访问:https://dolphinscheduler.apache.org/zh-cn/docs 我们可以看到相关的文档简介里有 介绍 DolphinScheduler是Apache DolphinScheduler 是一个分布式易扩展的可视化DAG工作流任务调度开源系统。适用于企业级场景,提供了一个可视化…...

我用Tauri开发的待办效率工具开源了!
开源仓库地址 gitee Git仓库地址:https://gitee.com/zhanhongzhu/zhanhongzhu.git 应用地址 windows应用地址下载 https://kestrel-task.cn 具体内容 也可以看🎉使用Taurivitekoa2mysql开发了一款待办效率应用 这篇文章。 💻技术栈 Tauri: Tauri…...

【黑科技】:Laravel 项目性能提升 20 倍
令人激动的黑科技:Laravel 项目性能提升 20 倍 这个项目能够在无需修改任何代码且无需第三方扩展的前提下,将你的 Laravel 项目性能提高 20 倍。它仅依赖于 PHP 原生的 pcntl、posix、fiber 和 sockets。 项目灵感 起因是看到官方发布的 PHP 8.1 更新…...

User Allocation In MEC: A DRL Approach 论文笔记
论文:ICWS 2021 移动边缘计算中的用户分配:一种深度强化学习方法 代码地址:使用强化学习在移动边缘计算环境中进行用户分配 目录 Ⅰ.Introduction II. MOTIVATION-A.验证假设的观察结果 II. MOTIVATION-A Motivating Example 数据驱动…...

leetcode 69. x 的平方根
可以使用二分查找法或牛顿迭代法来实现 LeetCode 问题 69. x 的平方根。下面是使用二分查找法和牛顿迭代法的 C 实现。 二分查找法 #include <iostream>class Solution { public:int mySqrt(int x) {if (x 0) return 0;int left 1, right x, ans 0;while (left <…...

基于词级ngram的词袋模型对twitter数据进行情感分析
按照阿光的项目做出了学习笔记,pytorch深度学习实战项目100例 基于词级ngram的词袋模型对twitter数据进行情感分析 什么是 N 符? N 格是指给定文本或语音样本中 n 个项目的连续序列。这些项目可以是音素、音节、字母、单词或碱基对,具体取…...

Linux-Centos-改密码(单用户登陆)
笔记一: centos7单用户修改root密码 在CentOS 7中,如果您是唯一的用户或者您确信其他用户不会登录,您可以按照以下步骤来修改root密码: 1.重启系统。 2.启动时出现引导界面时,按任意键进入GRUB菜单。 3.选择要启动的内…...

java实现OCR图片识别,RapidOcr开源免费
先看一下识别效果(自我感觉很牛逼),比Tess4J Tesseract省事,这个还需要训练,安装软件、下载语言包什么的 很费事,关键识别率不高 RapidOcr不管文字的横竖,还是斜的都能识别(代码实现…...

PCB工艺边设计准则
在PCB设计时,通常会在电路板的边缘预留一定的空间,这部分空间被称为工艺边。它有助于在生产过程中确保电路板的尺寸和形状的准确性。以使得组装时更加顺畅、便捷。而工艺边的加工,使得线路板上的元件可以精准地与设备对接,从而提高…...

CTF-NSSCTF题单[GKCTF2020]
[GKCTF 2020]CheckIN 这道题目考察:php7-gc-bypass漏洞 打开这道题目,开始以为考察反序列化,但实际并不是,这里直接用$_REQUEST传入了参数便可以利用了。这里出现了一个eval()函数,猜测考察命…...

redis的分片集群(仅供自己参考)
前言:为什么使用分片集群:因为redis的主从和哨兵机制主要是用来解决redis的高并发读的问题,还有redis的高并发的写的问题没有解决。使用分片集群就可以很好的解决redis写的问题,有多个master就可以实现并发的写。同时,…...

自动驾驶-机器人-slam-定位面经和面试知识系列01之常考公式推导(01)
李群李代数扰动bundle adjustment 这个博客系列会分为C STL-面经、常考公式推导和SLAM面经面试题等三个系列进行更新,基本涵盖了自己秋招历程被问过的面试内容(除了实习和学校项目相关的具体细节)。在知乎和牛客也会同步更新,全网…...

netty入门-5 ServerBootstrap与Bootstarp
前言 本来这篇应该紧接着说明Future和Promise。 但是考虑前文第三篇即用到了ServerBootstrap来启动一个服务器,并且我读的闪电侠netty,先写的服务器与客户端启动这部分。索性就先写出来了。主要内容来自闪电侠netty ServerBootstrap ServerBootstrap就…...

JavaEE - Spring Boot 简介
1.Maven 1.1 什么是Maven 翻译过来就是: Maven是⼀个项⽬管理⼯具。基于POM(Project Object Model,项⽬对象模型)的概念,Maven可以通 过⼀⼩段描述信息来管理项⽬的构建,报告和⽂档的项⽬管理⼯具软件。 可以理解为:Maven是一个项目管理工具…...

SwiftUI革新:Xcode UI开发的新纪元
SwiftUI革新:Xcode UI开发的新纪元 SwiftUI作为Apple推出的声明式UI框架,彻底改变了在Xcode中构建用户界面的方式。它不仅简化了代码,还提高了开发效率,并且使得UI设计更加直观和灵活。本文将深入探讨如何在Xcode中使用SwiftUI进…...