stm32的HAL庫i2c從機實現

gcrisis發表於2018-08-30

stm32的i2c預設就是slave模式,本文基於HAL庫實現中斷方式的接收和傳送,首先是初始化gpio和i2c,程式碼如下:

I2C_HandleTypeDef I2cHandle;
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct; 
     __HAL_RCC_GPIOA_CLK_ENABLE() ;
     __HAL_RCC_GPIOC_CLK_ENABLE() ;
    /**I2C3 GPIO Configuration    
    PA8     ------> I2C3_SCL
    PC9     ------> I2C3_SDA 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;            //開漏輸出(i2c需要這種模式)
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
      
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* Peripheral clock enable */
    __HAL_RCC_I2C3_CLK_ENABLE();

    /* Peripheral interrupt init */
    HAL_NVIC_SetPriority(I2C3_EV_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(I2C3_EV_IRQn);
    HAL_NVIC_SetPriority(I2C3_ER_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(I2C3_ER_IRQn);
}
void I2c_config()
{
  I2cHandle.Instance             = I2C3;                           //此處使用i2c3

  I2cHandle.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;        //7位地址模式
  I2cHandle.Init.ClockSpeed      = 1000000;                        //時鐘支援最高1M
  I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;        //關閉雙地址模式
  I2cHandle.Init.DutyCycle       = I2C_DUTYCYCLE_16_9;             
  I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;        
  I2cHandle.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLE;          
  I2cHandle.Init.OwnAddress1     = 0X34;                           //器件地址
  I2cHandle.Init.OwnAddress2     = 0;        
  
  if(HAL_I2C_Init(&I2cHandle) != HAL_OK)                            //呼叫初始化函式
  {
    /* Initialization Error */
    Error_Handler();    
  }
  HAL_I2C_Slave_Receive_IT(&I2cHandle,i2c_slave_recv,I2C_REC_BYTES);  //開啟從機中斷接收
}

i2c3中斷回撥函式:

void I2C3_ER_IRQHandler()                 //異常回撥
{
    HAL_I2C_ER_IRQHandler(&I2cHandle);
}
void I2C3_EV_IRQHandler()                //事件回撥(接收或傳送)
{
    HAL_I2C_EV_IRQHandler(&I2cHandle);
}

  兩個中斷對應的中斷事件如下圖所示:

傳送完成、接收完成和錯誤回撥函式:

void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *I2cHandle)
{
       //傳送完成回撥函式 
       {
            //一些其他操作
        }
       HAL_I2C_Slave_Receive_IT(&I2cHandle,i2c_slave_recv,I2C_REC_BYTES);
        {
            //一些其他操作
        }
}

void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *I2cHandle)
{
       //接收完成回撥函式
        {
            //一些其他操作
        }
        HAL_I2C_Slave_Transmit_IT(&I2cHandle,send_buffer,send_cnt);
        {
            //一些其他操作
        }
}

void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *I2cHandle)
{
       //錯誤異常回撥函式
}

實際操作時可以在接收完成中斷中處理資料然後開啟從機傳送中斷,在傳送完成中斷中開啟從機接收中斷,可以實現收發。

目前用HAL庫傳送必須將send_cnt的位元組全部傳送完成才行,不然通訊會出問題。這個問題需要進一步解決。

相關文章