STM32_I2C,不稳定,死在I2C_CheckEvent解决办法

作者: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)

  • 5
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STM32F030标准库中,确实没有提供i2c_checkevent函数,但我们可以通过使用标准库中提供的其他函数来进行替代。在检查I2C事件方面,最常用的函数是I2C_GetLastEvent函数。 I2C_GetLastEvent函数可以用于获取上一次I2C的事件状态。我们可以通过查看I2C的状态是否与特定的事件相匹配,来判断I2C是否发生了目标事件。 以下是一个示例代码,展示如何在STM32F030中代替i2c_checkevent函数: ```c // 假设我们的I2C外设为I2C1 // 定义I2C的状态常量 #define I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) // 主模式选择事件 #define I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00830004) // 主发送模式选择事件 // 检查I2C事件 uint32_t checkI2CEvent(I2C_TypeDef* I2Cx, uint32_t event) { uint32_t lastEvent = 0; lastEvent = I2C_GetLastEvent(I2Cx); if (lastEvent == event) { return 1; // 事件匹配 } else { return 0; // 事件不匹配 } } // 示例函数:向从设备发送数据 void sendData(I2C_TypeDef* I2Cx, uint8_t slaveAddress, uint8_t* data, uint8_t dataSize) { // 向从设备发送开始信号 I2C_GenerateSTART(I2Cx, ENABLE); // 等待主模式选择事件 while (!checkI2CEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)) {} // 发送从设备地址(写模式) I2C_Send7bitAddress(I2Cx, slaveAddress, I2C_Direction_Transmitter); // 等待主发送模式选择事件 while (!checkI2CEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {} // 发送数据 for (uint8_t i = 0; i < dataSize; i++) { I2C_SendData(I2Cx, data[i]); // ...等待传输完成事件,或者设置适当的超时时间 } // 发送停止信号 I2C_GenerateSTOP (I2Cx, ENABLE); } ``` 在上述示例代码中,checkI2CEvent函数用于检查I2C的事件是否与目标事件匹配。如果匹配则返回1,不匹配则返回0。通过不断循环检查事件,可以在事件发生时执行相应的操作。 需要注意的是,以上代码仅为一种替代i2c_checkevent函数的示例,实际使用时需要根据具体的需求和I2C外设的配置做出相应的调整。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值