你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

stm32f0 iic从机

[复制链接]
乐乐棠 提问时间:2020-6-24 09:53 /
       最近在捣鼓stm32f0的IIC从机,之前一直使用的是IIC主机,IIC主机主要用的是IO口模拟的,实现起来没什么问题。但是转到IIC从机后,发现通信读取数据过程中偶尔会出现串码的现象,大概一小时会出现两三次。以下是IIC从机的部分代码:

/*-- defined -----------------------------------------------------------------*/
#define     SLAVE_ADDR               0x16


#define     POLYNOME                 0x07

#define     I2C_REC_BYTES            64
#define     I2C_TX_BYTES              64



/*-- private variables -------------------------------------------------------*/
static   I2C_HandleTypeDef  hi2c1;

static   u8_t     slaveTxBuff[I2C_TX_BYTES] = {0};
static   u8_t     slaveRxBuff[I2C_REC_BYTES] = {0};


static  u8_t     rsoc;
static  u16_t    battVolt;
static  s16_t    current;
static  u16_t    Temper;
static  u16_t    cellVolt[3];

/*-- functions ---------------------------------------------------------------*/
static  void  tx_match(u8_t cmd);


/**@brief  
  * @brief       IIC初始化
  * @param     
  * @return  
  */

void   hal_iic_init(void)
{
  u32_t  tmpisr = 0;
       
  /* Peripheral clock enable */
  __HAL_RCC_I2C1_CLK_ENABLE();
       
  hi2c1.Instance = I2C1;
  hi2c1.Init.Timing = 0x2000090E;
  hi2c1.Init.OwnAddress1 = SLAVE_ADDR;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_ENABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {

  }
       
  /* Configure Analogue filter */
  if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
  {

  }
       
  /* Configure Digital filter */
  if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
  {

  }
       
  /* I2C1 interrupt Init */
  HAL_NVIC_SetPriority(I2C1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(I2C1_IRQn);
       
  /**
      I2C_IT_ADDRI:     Address match interrupt.
      I2C_IT_STOPI:     STOP detection interrupt.
      I2C_IT_NACKI:     NACK received interrupt.
      I2C_IT_ERRI:      Errors interrupt.
      I2C_IT_TCI:       TC interrupt.
     I2C_XFER_RX_IT:   REC interrupt.
  */
  tmpisr |= I2C_IT_ADDRI | I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_ERRI | I2C_IT_RXI | I2C_IT_TXI;
  __HAL_I2C_ENABLE_IT(&hi2c1, tmpisr);
}


/**@brief  
  * @brief   
  * @param     
  * @return  
  */
void  i2c_err_irq_handler(I2C_HandleTypeDef *hi2c, u32_t isrFlag)     
{
  if((isrFlag & I2C_FLAG_ARLO) == I2C_FLAG_ARLO)
  { /* ARLO Err */
    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO);
  }

  if((isrFlag & I2C_FLAG_BERR) == I2C_FLAG_BERR)
  { /* BERR Err */
    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR);
  }

  if((isrFlag & I2C_FLAG_OVR) == I2C_FLAG_OVR)
  { /* OVR Err */
    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR);
  }       
}



/**@brief
  * @brief   
  * @param     
  * @return  
  */
void  i2c_evt_irq_handler(I2C_HandleTypeDef *hi2c, u32_t isrFlag)     
{
  static   u8_t   txCounter = 0;
  static   u8_t   rxCounter = 0;
  u32_t  transferDir = 0;
       
  if(hi2c->Instance == hi2c1.Instance)
  {
    if((isrFlag & I2C_FLAG_ADDR) == I2C_FLAG_ADDR)
    {
       /* EV1 */     
       transferDir = isrFlag & I2C_ISR_DIR;   
       /* 判断方向 */
       if(transferDir)
       {   
          /* 方向为从机发送 */
          I2C1->ISR |= I2C_ISR_TXE;
          I2C1->TXDR = slaveTxBuff[0];         
          txCounter = 1;   
        }  
       else
       {
          /* 方向为从机接收 */
          rxCounter = 0;
       }

       __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ADDR);      
    }   
    else if((isrFlag & I2C_FLAG_TXIS) == I2C_FLAG_TXIS)
    {
       /* EV3 */         
       I2C1->TXDR = slaveTxBuff[txCounter++];
    }   
    else if((isrFlag & I2C_FLAG_RXNE) == I2C_FLAG_RXNE)
    {
       /* EV2 */        
       if(rxCounter < I2C_REC_BYTES)  
       {
          slaveRxBuff[rxCounter] = hi2c->Instance->RXDR;

          /* 进行命令匹配 */
          if(rxCounter == 0)
          {
              tx_match(slaveRxBuff[0]);
          }

           rxCounter++;
       }
    }   
    else if((isrFlag & I2C_FLAG_STOPF) == I2C_FLAG_STOPF)
    {
       /* EV4 */
       hi2c->Instance->ISR |= I2C_ISR_TXE;
       hi2c->Instance->ISR |= I2C_ISR_TXIS;
       txCounter = 0;
       rxCounter = 0;
       __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);      
     }   
    else if((isrFlag & I2C_FLAG_AF) == I2C_FLAG_AF)
    {
       /* EV3_2 */
       __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);     
     }
  }
}



/**
  * @brief   This function handles I2C1 global interrupt.
  * @param   
  * @param   
  * @return  
  */
void I2C1_IRQHandler(void)
{
  u32_t isrFlag = 0;

  isrFlag = hi2c1.Instance->ISR;

  if (isrFlag & (I2C_FLAG_BERR | I2C_FLAG_ARLO | I2C_FLAG_OVR))
  {
     /* 异常处理 */
     //HAL_I2C_ER_IRQHandler(&hi2c1);
     i2c_err_irq_handler(&hi2c1, isrFlag);
  }
  else
  {
     /* 事件处理 */
     //HAL_I2C_EV_IRQHandler(&hi2c1);
     i2c_evt_irq_handler(&hi2c1, isrFlag);
  }
}


/** @function  
  * @brief       IIC从机匹配发送数据,发现如果使用switch-case出错率会更高,不知为何。
  * @param   
  * @return  
  */
static  void  tx_match(u8_t cmd)
{
  u8_t  counter = 0;

  if(cmd == 0x08)
  {
    slaveTxBuff[counter++] = Temper&0x00ff;
    slaveTxBuff[counter++] = (Temper&0xff00)>>8;
    Temper++;   
  }
  else if(cmd == 0x09)
  {
    slaveTxBuff[counter++] = battVolt&0x00ff;
    slaveTxBuff[counter++] = (battVolt&0xff00)>>8;
    battVolt++;   
  }
  else if(cmd == 0x0A)
  {
    slaveTxBuff[counter++] = current&0x00ff;
    slaveTxBuff[counter++] = (current&0xff00)>>8;   
  }   
  else if(cmd == 0x0D)
  {
    slaveTxBuff[counter++] = rsoc&0x00ff;
    slaveTxBuff[counter++] = (rsoc&0xff00)>>8;   
  }
  else if(cmd == 0x3F)
  {
    slaveTxBuff[counter++] = cellVolt[0]&0x00ff;
    slaveTxBuff[counter++] = (cellVolt[0]&0xff00)>>8;     
  }   
  else if(cmd == 0x3E)
  {
    slaveTxBuff[counter++] = cellVolt[1]&0x00ff;
    slaveTxBuff[counter++] = (cellVolt[1]&0xff00)>>8;     
  }  
  else if(cmd == 0x3D)
  {
    slaveTxBuff[counter++] = cellVolt[2]&0x00ff;
    slaveTxBuff[counter++] = (cellVolt[2]&0xff00)>>8;   
  }  

  slaveTxBuff[counter] = CRC8(slaveTxBuff, counter, POLYNOME);  
}

    可能是因为本人对IIC从机原理理解得不够深,折腾了两天还是没什么进展,望由此经验的朋友多多指教,谢谢!


收藏 评论7 发布时间:2020-6-24 09:53

举报

7个回答
butterflyspring 回答时间:2020-7-9 10:19:34
主机是模拟的做的,要注意对SCL的检测,因为从机使能了延展功能,延展期间要等等从机的响应。另外建议先调通简单的收发,再导入其他的分支处理程序。
乐乐棠 回答时间:2020-7-14 13:37:39
butterflyspring 发表于 2020-7-9 10:19
主机是模拟的做的,要注意对SCL的检测,因为从机使能了延展功能,延展期间要等等从机的响应。另外建议先调通 ...

请问NoStretchMode成员设置为I2C_NOSTRETCH_ENABLE是允许时钟延伸吗?
按字面意思我以为是禁止了时钟延伸。
butterflyspring 回答时间:2020-7-17 10:05:15
乐乐棠 发表于 2020-7-14 13:37
请问NoStretchMode成员设置为I2C_NOSTRETCH_ENABLE是允许时钟延伸吗?
按字面意思我以为是禁止了时钟延伸 ...

看字面的意思是使能为禁止的意思。不过最好的办法是对照手册,如图。可以调试观察这位在运行后设置的结果。
f0 i2c nostretch.PNG
乐乐棠 回答时间:2020-7-21 08:00:45
butterflyspring 发表于 2020-7-17 10:05
看字面的意思是使能为禁止的意思。不过最好的办法是对照手册,如图。可以调试观察这位在运行后设置的结果 ...

好的,谢谢,这个问题我只能先放一放,先处理急的事情,过段时间再弄一下。
liuyangbo86 回答时间:2020-7-22 17:53:40
时钟的偏移呢?
乐乐棠 回答时间:2020-7-24 15:04:38

“hi2c1.Init.Timing = 0x2000090E” 请问说的是这个吗?
乐乐棠 回答时间:2020-8-15 08:40:29
我把IIC从机中断优先级调整为最高级,经过几个小时的测试,数据一次都没有出错过,暂时认定为是其他中断影响了IIC从机中断的发送。

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版