用的国民技术031芯片与8815进行I2C通讯,发现执行写操作时经常会卡死进入BUSY,从而进入超时,导致程序不正常,以下是部分程序代码
以下是初始化:
int i2c_master_init(void)
{
I2C_InitType i2c1_master;
GPIO_InitType i2c1_gpio;
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_I2C1, ENABLE);
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
GPIO_InitStruct(&i2c1_gpio);
/*PA9 -- SCL; PA10 -- SDA*/
i2c1_gpio.Pin = I2Cx_SCL_PIN | I2Cx_SDA_PIN;
i2c1_gpio.GPIO_Speed = GPIO_SPEED_LOW;//GPIO_SPEED_HIGH;
i2c1_gpio.GPIO_Mode = GPIO_MODE_AF_OD;
i2c1_gpio.GPIO_Alternate = GPIO_AF_I2C;
i2c1_gpio.GPIO_Pull = GPIO_PULL_UP;
GPIO_InitPeripheral(GPIOx, &i2c1_gpio);
I2C_DeInit(I2Cx);
i2c1_master.BusMode = I2C_BUSMODE_I2C;
i2c1_master.FmDutyCycle = I2C_FMDUTYCYCLE_2; //if the spped greater than 400KHz, the FmDutyCycle mast be configured to I2C_FMDUTYCYCLE_2
i2c1_master.OwnAddr1 = I2C_MASTER_ADDR;
i2c1_master.AckEnable = I2C_ACKEN;
i2c1_master.AddrMode = I2C_ADDR_MODE_7BIT;
i2c1_master.ClkSpeed = 100000;
I2C_Init(I2Cx, &i2c1_master);
I2C_Enable(I2Cx, ENABLE);
return 0;
}
以下是写函数:
```c
uint8_t I2C_EE_PageWrite(u8* pBuffer, u16 WriteAddr, u16 NumByteToWrite)
{
uint8_t state = I2C_START;
uint16_t timeout = 0;
uint8_t i2c_timeout_flag = 0;
uint8_t Return_Stat_W=0;
sEETimeout = sEE_LONG_TIMEOUT;
while(!(i2c_timeout_flag)){
switch(state) {
case I2C_START:
while (I2C_GetFlag(I2Cx, I2C_FLAG_BUSY)&&(timeout < I2C_TIME_OUT)){
timeout++;
}
if(timeout < I2C_TIME_OUT) {
/** Send START condition */
I2C_GenerateStart(I2Cx, ENABLE);
timeout = 0;
state = I2C_SEND_ADDRESS;
}else {
timeout = 0;
state = I2C_TIMEOUT_END;//I2C_START;
}
break;
case I2C_SEND_ADDRESS:
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_MODE_FLAG) && (timeout < I2C_TIME_OUT)){
timeout++;
}
if(timeout < I2C_TIME_OUT){
/** Send EEPROM address for write */
I2C_SendAddr7bit(I2Cx, EEPROM_ADDRESS, I2C_DIRECTION_SEND);
timeout = 0;
state = I2C_CLEAR_ADDRESS_FLAG;
} else {
timeout = 0;
state = I2C_TIMEOUT_END;//I2C_START;
}
break;
case I2C_CLEAR_ADDRESS_FLAG:
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_TXMODE_FLAG) && (timeout < I2C_TIME_OUT)){
timeout++;
}
if(timeout < I2C_TIME_OUT) {
/** Send the EEPROM's internal address to write to */
I2C_SendData(I2Cx, WriteAddr);
/** Test on EV8 and clear it */
timeout = 0;
state = I2C_TRANSMIT_DATA;
} else {
timeout = 0;
state = I2C_TIMEOUT_END;//I2C_START;
}
break;
case I2C_TRANSMIT_DATA:
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_DATA_SENDED) && (timeout < I2C_TIME_OUT)){
timeout++;
}
if(timeout < I2C_TIME_OUT) {
timeout = 0;
} else {
timeout = 0;
state = I2C_TIMEOUT_END;//I2C_START;
}
/** While there is data to be written */
while (NumByteToWrite--)
{
/** Send the current byte */
I2C_SendData(I2Cx, *pBuffer);
/** Point to the next byte to be written */
pBuffer++;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_DATA_SENDED) && (timeout < I2C_TIME_OUT)){
timeout++;
}
if(timeout < I2C_TIME_OUT) {
timeout = 0;
} else {
timeout = 0;
state = I2C_TIMEOUT_END;//I2C_START;
}
}
timeout = 0;
state = I2C_STOP;
break;
case I2C_STOP:
/** Send STOP condition */
I2C_GenerateStop(I2Cx, ENABLE);
// I2C_EE_WaitEepromStandbyState();
I2C_EE_WriteOnePageCompleted();
i2c_timeout_flag = I2C_OK;
state = I2C_END;
break;
case I2C_TIMEOUT_END:
i2c_timeout_flag = 1;
Return_Stat_W = 1;
break;
default:
state = I2C_START;
i2c_timeout_flag = I2C_OK;
timeout = 0;
break;
}
}
return Return_Stat_W;
}
总是会卡在:
```c
while (I2C_GetFlag(I2Cx, I2C_FLAG_BUSY)&&(timeout < I2C_TIME_OUT)){
timeout++;
}
求能实际解决的软件方案!
参考gpt:
根据您提供的代码,问题出现在写函数的第一个状态(I2C_START)中的循环中,其中卡住在等待I2C总线忙碌的判断中。这可能是由于以下原因导致的:
I2C总线冲突:在执行写操作之前,请确保没有其他设备正在使用I2C总线。如果存在其他设备与您的031芯片或8815模块之间连接到同一条I2C总线上,确保它们的地址不冲突,并且在写操作期间没有竞争。
硬件连接问题:请仔细检查芯片和模块的I2C连接,确保连接正确。确保SCL(时钟线)和SDA(数据线)正确连接到芯片和模块,并且没有短路或接触不良的情况。
I2C配置错误:请确保在初始化函数中正确配置了I2C控制器和GPIO引脚。检查I2C控制器的时钟配置、引脚模式(GPIO_MODE_AF_OD)以及上拉电阻(GPIO_PULL_UP)是否正确设置。
I2C操作顺序错误:请确保在写操作之前正确执行了必要的步骤,例如发送START条件和设备地址。根据代码,似乎缺少一些必要的操作步骤,例如等待事件标志。
以下是一些可能的解决方案:
确保在执行写操作之前,没有其他设备与您的031芯片或8815模块连接到相同的I2C总线上。
检查硬件连接,确保SCL和SDA线正确连接,并且没有短路或接触不良的情况。
检查I2C的初始化代码,确保正确配置了时钟、引脚模式和上拉电阻。
根据I2C规范,正确执行I2C通信的操作序列,例如发送START条件、设备地址等。
考虑增加适当的错误处理机制,例如在超时时进行错误处理或重试操作。
卡在 while (I2C_GetFlag(I2Cx, I2C_FLAG_BUSY)&&(timeout < I2C_TIME_OUT)) 的问题可能是由于硬件或软件方面的原因导致的。
你可以检查检查硬件连接:确保 I2C 总线上的硬件连接正确。检查 SCL(时钟线)和 SDA(数据线)是否正确连接,并且没有短路或断开连接的问题。