作者:153290557
转自:http://www.amobbs.com/thread-4786750-1-1.html
主设备:STM32F103C8T6
从设备:AT24C02
看见很多人用都出现死在I2C_CheckEvent,或经常不稳定
很多时候是死在AF标志上,在发送完后从设备如果一定时间内不返回ACK,STM32_I2C就置位AF不应答标志
用示波器测了下,带库时偶尔收到ACK,说明通讯有问题
例如
发送器件地址流程是:START->DEVICE_ADDRESS->ACK
因为用了固件库START跟DEVICE_ADDRESS时序会出现偏差,结果从设备偶尔能收到正确数据,偶尔返回ACK造成不稳定
如果ACK一段时间没返回主设备马上AF。。结果经常死在I2C_CheckEvent
解决办法:
一:不要用库,每一段START->ACK尽量写短,写简洁!
二:降低I2C速度!我测试在10KHZ时很稳定,20KHZ非常少,不稳定,50KHZ几乎不稳定
还有一种是中途传输字节,某些原因,主设备复位!结果I2C总线锁死,这种问题另外谈!
带库测试函数:
void I2C_EE_WaitEepromStandbyState(I2C_TypeDef *I2Cx,u8 EEPROM_Addr)
{
vu16 SR1_Tmp = 0;
while(1){
do
{
/* Send START condition */
//I2C_GenerateSTART(I2Cx, ENABLE);
/* Send EEPROM address for write */
//I2C_Send7bitAddress(I2Cx, EEPROM_Addr, I2C_Direction_Transmitter);//EEPROM_Addr=0xA0
}while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//检查最近一次 I2C事件是否是输入的事件
}
/* Clear AF flag */
I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
}
不带库测试:
void I2C_EE_WaitEepromStandbyState(I2C_TypeDef *I2Cx,u8 EEPROM_Addr)
{
vu16 SR1_Tmp = 0;
while(1){
do
{
/* Send START condition */
I2Cx->CR1 |= 0x0100;
/* Send EEPROM address for write */
I2Cx->DR = EEPROM_Addr&0xFFFE;);//EEPROM_Addr=0xA0
}while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//检查最近一次 I2C事件是否是输入的事件
}
/* Clear AF flag */
I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
}
下面是带库测试图:
细心看,发送器件地址0xA0,有时不能收到ACK,(长低最后那部分那尖刺就是ACK)
(原文件名:I2C-10KHZ带库.jpg)
(原文件名:I2C-50KHZ带库.jpg)
(原文件名:I2C-60KHZ带库.jpg)
(原文件名:I2C―50KHZ带库1.jpg)
(原文件名:I2C―50KHZ带库.jpg)
(原文件名:I2C―100KHZ带库1.jpg)
(原文件名:I2C―100KHZ带库2.jpg)
(原文件名:I2C―100KHZ带库3.jpg)
(原文件名:I2C―100KHZ带库4.jpg)
(原文件名:I2C―100KHZ带库.jpg)
不带库测试图:
(原文件名:I2C―50KHZ不带库.jpg)
(原文件名:I2C―100KHZ不带库1.jpg)
(原文件名:I2C―100KHZ不带库.jpg)
整个程序关键是那个SR2,官方的读SR2有些没关中断,我用的时候偶尔会出错,后来在读SR2前加关闭中断,读完再开启,暂时就没发现有问题!
附件有!
void I2C_EE_BufferRead(I2C_TypeDef *I2Cx ,vu8 EEPROM_Addr,vu16 ReadAddr,vu8 *pBuffer,vu16 NumByteToRead )//将EEPROM的数据读入缓冲器
{
vu32 iErr,nErr;
iErr = EE_TimeOut;
nErr = EE_Error;
do{
//at24c02选择性读时序:START->DEVICE_ADDRESS_WRITE->ACK->BYTE_ADDRESS(n)->ACK----------------------------------------------------------------------------------------------------
I2C_EE_WaitEepromStandbyState(I2Cx,EEPROM_Addr);//EEPROM设为待命状态
iErr = EE_TimeOut;
I2Cx->CR1 |= 0x0100;//Send START condition
while((I2Cx->SR1&0x0001) != 0x0001){
if(iErr-- == 0)
goto EE_END;
}
iErr = EE_TimeOut;
I2Cx->DR= EEPROM_Addr&0xFFFE;// Send EEPROM address for write
/* Wait until ADDR is set: EV6 */
while((I2Cx->SR1 &0x0002) != 0x0002){//Test on EV6 and clear it
if(iErr-- == 0)
goto EE_END;
}
__disable_irq();
/* Clear ADDR flag by reading SR2 register */
Readtemp = I2Cx->SR2; /*读SR2时,必须关闭中断,不关闭示波器看偶尔会发送9个CLK!,或者发送时,卡在EV8上!总之在读SR2时关闭中断读写就正常了!*/
/* Re-enable IRQs */
__enable_irq();
连接原理图
(原文件名:24C64.jpg)
我这要接22PF,不然偶尔会通讯失败!想不明白!
点击此处下载 ourdev_721314E8GQ27.rar(文件大小:7K) (原文件名:EEPROM-I2C驱动.rar)