打印
[其他ST产品]

关于STM32的IIC跟EEPROM通信为什么卡死在while

[复制链接]
681|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
csv7k1|  楼主 | 2023-6-28 20:48 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
关于STM32的IIC跟EEPROM通信为什么卡死在while(I2C_CheckEvent)的EV6事件还有为什么检测的是标志位及其怎样写等待写入操作完成函数问题跟解决方法

我们在写IIC跟EEPROM 通信的时候,会遇到读不出来的一个问题
实际上这是EEPROM这时候还在写入数据,然后我们的STM32的执行速度过快,然后就会卡死在while中
为什么会卡死在这个地方呢,
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) == ERROR); 而不是起始信号的地方?我们这里就有疑问了,明明前面还有一个检测应答啊,为什么这里没卡死


使用特权

评论回复
沙发
csv7k1|  楼主 | 2023-6-28 20:49 | 只看该作者
while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
为什么在这卡死了呢。


大家看这个图,一开始是起始信号,然后紧接着是EV5事件,我们用while判断了这个事件,EV5事件代表的是SR1寄存器的位置1,这里肯定是没问题的,因为他判断的是32是否发送出去起始信号了,我们发送了,自然肯定是没毛病的。

使用特权

评论回复
板凳
csv7k1|  楼主 | 2023-6-28 20:51 | 只看该作者
第二个我们发送的地址,然后判断了EV6事件,然后程序在这个while中卡死,这是为什么呢,实际上是因为EEPROM在这个时候还在写入数据,我们发送了这个地址过去,然后没有产生应答,所以在这里出现了问题。
所以我们要解决的问题就是,让数据写入以后才继续读取,最简单的放大是写一个延时函数
上代码
   void SysTick_Init_ms(uint16_t x)
{
         uint32_t i;
    for(i=0;i<=x;i++);
}

int  main()
{

      USART_Configer();
          printf("这是一个IIC通讯实验\n");
          I2C_EEPROM_Configer();  
          I2C_EEPROM_Write_Byte(11 , 0x52);
          SysTick_Init_ms(0xffff);
          I2C_EEPROM_Write_Byte(12 , 0x55);
          EEPROM_WaitForWriteEnd();
       
          I2C_EEPROM_Read_Byte( 11, readData,2 );  
          printf("\r\n接收到数据为0x%x\r\n",readData[0]);
         while(1)
         {
         }
}```
可以看到我们采取一个延时是没毛病的,这里我就不上结果的图了

第二个解决方法就是我们检测写入完成没有
  void EEPROM_WaitForWriteEnd(void)
{
       
        do
        {
                //产生起始信号
                I2C_GenerateSTART(EEPROM_I2C,ENABLE);
               
                while(I2C_GetFlagStatus (EEPROM_I2C,I2C_FLAG_SB) == RESET);
               
                //EV5事件被检测到,发送设备地址
                I2C_Send7bitAddress(EEPROM_I2C,0XA0,I2C_Direction_Transmitter);
        }  
        while(I2C_GetFlagStatus (EEPROM_I2C,I2C_FLAG_ADDR) == RESET );

        //EEPROM内部时序完成传输完成
        I2C_GenerateSTOP(EEPROM_I2C,ENABLE);       
}
或者把这段代码写到读取函数中
   do
        {
                //产生起始信号
        I2C_GenerateSTART(EEPROM_I2C,ENABLE);
               
                while(I2C_GetFlagStatus (EEPROM_I2C,I2C_FLAG_SB) == RESET);
       
        //EV5事件被检测到,发送设备地址
                I2C_Send7bitAddress(EEPROM_I2C,0XA0,I2C_Direction_Transmitter);
        }  
        while(I2C_GetFlagStatus (EEPROM_I2C,I2C_FLAG_ADDR) == RESET );
I2C_GenerateSTOP(EEPROM_I2C,ENABLE);       
       
       
  I2C_GenerateSTART(EEPROM_I2C,ENABLE);  //产生起始信号
       
        while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) == ERROR); //检测EV5
       
  I2C_Send7bitAddress(EEPROM_I2C,0XA0,I2C_Direction_Transmitter);  //发送设备地址
       
        while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);  //检查EV6
       
  I2C_SendData(EEPROM_I2C,addr);  //发送到EEPROM哪一个位地址
       
  while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR);

       
        //第二次
        I2C_GenerateSTART(EEPROM_I2C,ENABLE);  
       
        while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
       
  I2C_Send7bitAddress(EEPROM_I2C,0XA0,I2C_Direction_Receiver);

        while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)==ERROR);
       
        while(num)
        {
                 if(num==1)
                 {
                 I2C_AcknowledgeConfig (EEPROM_I2C,DISABLE);
                 }
                         while(I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_RECEIVED ) == ERROR);//检测EV7事件
           *data=I2C_ReceiveData(EEPROM_I2C);
                 
                 data++;
                 num--;
        }
       
                //数据传输完成
        I2C_GenerateSTOP(EEPROM_I2C,ENABLE);       
       
        //重新配置ACK使能,以便下次通讯
        I2C_AcknowledgeConfig (EEPROM_I2C,ENABLE);
}
大家可能还会好奇为什么我们写一个停止信号,因为我们写了一个起始信号然后检测事件,发送地址,检测事件,我们要遵循I2C的,所以我们要发送结束信号,然后判断成功了以后,我们再重新发送起始信号等等操作

还有为什么要检测标志位,而不是检测事件呢,
while(I2C_GetFlagStatus (EEPROM_I2C,I2C_FLAG_SB) == RESET);

while(I2C_GetFlagStatus (EEPROM_I2C,I2C_FLAG_ADDR) == RESET );

  这个经过我的Debug调试,如果写检测事件,就会在写入函数卡死,具体我也没去仔细看,总之使用flag就不会出现问题
  大家也知道32跟EEPROM通信是有一些小问题的, 所以这里就不要去深究为什么判断标志位了

使用特权

评论回复
地板
星辰大海不退缩| | 2023-6-30 13:08 | 只看该作者
卡死肯定是置1了,而且没有复位掉所以一直循环,程序逻辑上的判断应该还有问题

使用特权

评论回复
5
小小蚂蚁举千斤| | 2023-6-30 14:51 | 只看该作者
楼主还是确认一下卡死的原因吧,理论上分析可能没问题,还得理论结合实际

使用特权

评论回复
6
Undshing| | 2023-7-1 22:51 | 只看该作者
查一下是不是程序写的有问题

使用特权

评论回复
7
backlugin| | 2023-7-5 10:34 | 只看该作者
需要更详细地分析程序和硬件环境,包括查看寄存器状态、信号波形以及相关的配置等

使用特权

评论回复
8
elsaflower| | 2023-7-5 11:46 | 只看该作者
确认所使用的引脚、电平转换电路等硬件连接是否正确。

使用特权

评论回复
9
maudlu| | 2023-7-5 15:16 | 只看该作者
IIC的短延时是非常重要的              

使用特权

评论回复
10
eefas| | 2023-7-5 15:27 | 只看该作者
通信从机应答缺失 ?              

使用特权

评论回复
11
AloneKaven| | 2023-7-5 18:15 | 只看该作者
是不是标志位的问题啊?

使用特权

评论回复
12
saservice| | 2023-7-5 22:16 | 只看该作者
确配置I2C控制器并使能相应的时钟。

使用特权

评论回复
13
wangdezhi| | 2023-7-6 11:35 | 只看该作者
在while循环内,可以判断状态寄存器的标志位来检测通信是否完成,并设置适当的超时时间,如果超过预定时间仍未完成,则跳出循环。

使用特权

评论回复
14
maqianqu| | 2023-7-6 11:41 | 只看该作者
IIC的应答出现死循环导致的无法初始化

使用特权

评论回复
15
kkzz| | 2023-7-6 12:00 | 只看该作者
I2C通信设置超时机制,以避免无限等待。

使用特权

评论回复
16
mikewalpole| | 2023-7-6 15:57 | 只看该作者
如果总线被其他设备锁定或者存在通信冲突,可能导致卡死现象。

使用特权

评论回复
17
hearstnorman323| | 2023-7-6 16:18 | 只看该作者
以通过其他方式(例如示波器)验证设备的响应和数据传输情况。

使用特权

评论回复
18
Jacquetry| | 2023-7-6 23:11 | 只看该作者
没收到应答信号吧

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

69

帖子

0

粉丝