关于野火STM32的I2C发送/接收通讯过程的理解(纠错)

在看了I2C的通讯过程的主发送器通讯过程以后,发现有个地方很难理解。如下图:

就是如图所示的红色方框,按照野火所说的,在发送地址并被从机响应(A)之后,会产生两个事件:一个是地址被响应,从而将状态寄存器2(SR2)的ADDR位写1,表示地址匹配上了从机并返回了响应(A);另一个就是将状态寄存器2(SR2)的TxE位写1了,表示发送数据寄存器此时为空,可以往里面写数据,也就是发送准备就绪了。

其实说的没错,但是对照代码就很难理解了。如下:

/**
  * @brief   写一个字节到I2C EEPROM中
  * @param   
  *		@arg pBuffer:缓冲区指针
  *		@arg WriteAddr:写地址 
  * @retval  无
  */
uint32_t I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr) 
{
  /* Send STRAT condition */
  I2C_GenerateSTART(EEPROM_I2Cx, ENABLE);

  I2CTimeout = I2CT_FLAG_TIMEOUT;  
  /* Test on EV5 and clear it */
  while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_MODE_SELECT))  
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(0);
  } 
  
  I2CTimeout = I2CT_FLAG_TIMEOUT;
  /* Send EEPROM address for write */
  I2C_Send7bitAddress(EEPROM_I2Cx, EEPROM_ADDRESS, I2C_Direction_Transmitter);
  
  /* 检测EV6事件 */
  while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
  }  
  /* Send the EEPROM's internal address to write to */
  I2C_SendData(EEPROM_I2Cx, WriteAddr);
  
  I2CTimeout = I2CT_FLAG_TIMEOUT;
  /* Test on EV8 and clear it */
  while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);
  } 
  
  /* Send the byte to be written */
  I2C_SendData(EEPROM_I2Cx, *pBuffer); 
  
  I2CTimeout = I2CT_FLAG_TIMEOUT;  
  /* Test on EV8 and clear it */
  while(!I2C_CheckEvent(EEPROM_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
  } 
  
  /* Send STOP condition */
  I2C_GenerateSTOP(EEPROM_I2Cx, ENABLE);
  
  return 1;
}

 代码中,/* 检测EV6事件 */这段,在发送了EEPROM的地址以后,只检测了EV6事件,按照野火的说法,产生了EV6和EV8事件才能继续下面的操作,代码只执行了EV6的检测,不得不让人怀疑代码的正确性。

实际上,代码没有错,通过查看I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED的宏替换以及I2C_CheckEvent函数(此处不贴出),如下:

/* --EV6 */
#define  I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED        ((uint32_t)0x00070082)  /* BUSY, MSL, ADDR, TXE and TRA flags */

 I2C_CheckEvent函数体内,就是SR1和SR2两个寄存器的操作,而上面的宏就是来对SR1和SR2赋值的。也就是说EV6事件,对SR1和SR2的对应位赋值1了。那么分别是哪些位呢?只需要关注0x00070082里的‘8’和‘2’,也就是SR2的1位和7位(0位开始),对应的就是SR2的ADDR位和TxE位,也就是说,库函数里的EV6其实应该是野火说的EV6个EV8事件野火的说法反正是让我困扰了好一会,起码是一知半解吧!所以其实通讯图里,EV6应该是ADDR=1 & TxE=1;后面的EV8只是TxE=1就行了。不然,看代码以为在发送地址并且从机响应了地址之后,只检测了EV6(ADDR=1),而没有检测EV8(TxE=1)呢。

其实对比主机接收的通讯过程就好理解了。主机接收的时候页有EV6事件,这个事件的宏替换如下:

#define  I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED           ((uint32_t)0x00030002)  /* BUSY, MSL and ADDR flags */

也只看低位的'2',这个2表示SR2的1位,也就是ADDR位,也就是在接收通讯中EV6事件单指响应了主机发送的地址,而不等待发送数据寄存器为空这个事件。因为接收通讯中,用不到发送数据寄存器,不会往外发数据了。

发送接收的事件是不一样,这个要清楚。否则会产生误解,阅读代码的时候也会产生困惑。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值