单片机 > 单片机程序设计 > 详情

STM32L151 I2C从机实现

发布时间:2020-06-09 发布时间:
|

 网上很多STM32的I2C都是基于F系列去实现的,其他的系列的芯片实现很少。


 而对于STM32L151系列的I2C从机设计,用STM32CubeMX生成的简单DEMO里,就会有提供库接口实现,比如:


 HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout);


 HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout);


 但其实,如果是调用库接口,只能实现从机接收或者是只实现从机发送实现,调用现成接口貌似很难做到既接收有发送(至少个人没有试验出来)。


  不过如果使用中断,实现起来就非常简单了。


  首先使用STM32CubeMX生成一个简单的I2C demo,设置在MX_I2C1_Init接口里面设置好从机的一些基本信息(从机地址,使用几位从机地址等);


/* I2C1 init function */


void MX_I2C1_Init(void)


{

 

  hi2c1.Instance = I2C1;


  hi2c1.Init.ClockSpeed = 100000;


  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;


  hi2c1.Init.OwnAddress1 = 0x90;


  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;


  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;


  hi2c1.Init.OwnAddress2 = 0;


  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;


  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;


  if (HAL_I2C_Init(&hi2c1) != HAL_OK)


  {


    _Error_Handler(__FILE__, __LINE__);


  }

 

}


    然后重写I2C1_EV_IRQHandler中断函数,并使能中断;


void I2C1_EV_IRQHandler(void)


{


  if (hi2c1.Instance->SR1 & (I2C_FLAG_BERR | I2C_FLAG_ARLO | I2C_FLAG_OVR)) {


    HAL_I2C_ER_IRQHandler(&hi2c1);


  } else {


    HAL_I2C_EV_IRQHandler(&hi2c1);


  }


}


   至于中断函数就直接使用工具生成的就可以了。


值得注意的是:


STM32L151芯片在工具生成的DEMO里面,从机模式无论是接收还是发送都是一个字节一个字节进行的,如果你需要接收或者是发送多个字节,需要稍微更改一下接收和发送的函数。


static HAL_StatusTypeDef I2C_SlaveTransmit_TXE(I2C_HandleTypeDef *hi2c)


{   


while(hi2c->XferSize > 0U)


    {


      /* Wait until TXE flag is set */

      

if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, 0xffffffff, 0) != HAL_OK)

      

{


        /* Disable Address Acknowledge */


        CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);


        if(hi2c->ErrorCode == HAL_I2C_ERROR_AF)


        {


          return HAL_ERROR;


        }


        else


        {


          return HAL_TIMEOUT;


        }


      }

 

      /* Write data to DR */


      hi2c->Instance->DR = (*hi2c->pBuffPtr++);


      hi2c->XferCount--;


      hi2c->XferSize--;


    }


    if((hi2c->XferCount == 0U) && (hi2c->State == HAL_I2C_STATE_BUSY_TX_LISTEN))


    {


      /* Last Byte is received, disable Interrupt */


      __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF);


       /* Set state at HAL_I2C_STATE_LISTEN */

 

      hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_TX;


      hi2c->State = HAL_I2C_STATE_LISTEN;

 

      /* Call the Tx complete callback to inform upper layer of the end of receive process */


      HAL_I2C_SlaveTxCpltCallback(hi2c);


    }

  return HAL_OK;


}


static HAL_StatusTypeDef I2C_SlaveReceive_RXNE(I2C_HandleTypeDef *hi2c)


{


  while(hi2c->XferCount != 0U)


  {

  

      /* Wait until RXNE flag is set */


      if(I2C_WaitOnRXNEFlagUntilTimeout(hi2c, 0xffffffff, 0) != HAL_OK)      


      {


        /* Disable Address Acknowledge */


        CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);


        if(hi2c->ErrorCode == HAL_I2C_ERROR_TIMEOUT)


        {


          return HAL_TIMEOUT;


        }


        else


        {


          return HAL_ERROR;


        }


      }


    /* Read data from DR */

 

   (*hi2c->pBuffPtr++) = hi2c->Instance->DR;


    hi2c->XferCount--;

 

    if((hi2c->XferCount == 0U) && (hi2c->State == HAL_I2C_STATE_BUSY_RX_LISTEN))


    {


      /* Last Byte is received, disable Interrupt */


      __HAL_I2C_DISABLE_IT(hi2c, I2C_IT_BUF);

 

      /* Set state at HAL_I2C_STATE_LISTEN */


      hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_RX;


      hi2c->State = HAL_I2C_STATE_LISTEN;

 

      /* Call the Rx complete callback to inform upper layer of the end of receive process */


      HAL_I2C_SlaveRxCpltCallback(hi2c);


    }


  }


  return HAL_OK;


}


    改造了之后,就可以直接接收/发送多个字节的数据啦啦啦~

关键字:STM32L151  I2C  从机 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
PIC单片机基础知识之二