1. 程式人生 > >STM32微控制器硬體I2C驅動程式(軟體輪詢方式)---摘自:FeoTech

STM32微控制器硬體I2C驅動程式(軟體輪詢方式)---摘自:FeoTech

感謝原作者:FeoTech   原文網址:http://feotech.com/?p=69

本程式主要用於驅動STM32微控制器晶片的硬體I2C暫存器,實現通過使用晶片自帶的I2C暫存器進行資料的傳送與接收.

本例程中採用I2C暫存器查詢的方式來實現資料傳輸,當I2C對應暫存器指定狀態時方可執行下一步操作.

/**
  ******************************************************************************
  * @file    Hardware_I2C.c 
  * @author  Ryan Zhao
  * @version V1.0.0
  * @date    2017-04-27
  * @brief   STM32硬體I2C底層驅動.
  ******************************************************************************
  * @attention   Null
  * 
  ******************************************************************************
  */



/**
* @brief  I2C引腳與暫存器功能配置.
* @param  None.
* @retval None.
*/
void I2C_Configuration(void)
{
  /*GPIO與IIC初始化結構體*/  
  GPIO_InitTypeDef GPIO_InitStructure;  
  I2C_InitTypeDef I2C_InitStructure;  

  /*GPIO與IIC時鐘使能*/  
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );     //GPIOB時鐘使能  
  RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C1, ENABLE );      //I2C時鐘使能  

  /*初始化GPIO*/  
  GPIO_InitStructure.GPIO_Pin =  HW_I2C_SDA_PIN | HW_I2C_SCL_PIN;   //初始化 IIC GPIO 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //最高輸出速度50Hz  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;     //輸入輸出模式為複用功能開漏輸出  
  GPIO_Init( GPIOB, &GPIO_InitStructure );            //根據GPIO初始化結構體初始化GPIOB  

  /*初始化I2C*/  
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;                  //設定為I2C模式  
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;          //設定I2C的佔空比,低電平除以高電平值為2  

  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;                 //使能ACK訊號  
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;   //指定7位地址  
  I2C_InitStructure.I2C_ClockSpeed = 400000;                  //時鐘頻率,必須小於等於400KHz  

  I2C_Cmd( HW_I2C, ENABLE );                                    //使能I2C 
  I2C_Init( HW_I2C, &I2C_InitStructure );                       //根據I2C初始化結構體初始化I2C  

  /*允許一位元組一應答模式*/  
  I2C_AcknowledgeConfig( HW_I2C, ENABLE );                      //使能I2C應答狀態 
}


/**
* @brief  從I2C指定地址中讀取資料;
* @param  讀取的地址,讀取後返回的資料;
* @retval 1:讀取資料成功,0:讀取資料無效;
*/
unsigned char  I2C_ReadByte(unsigned char Read_Address,unsigned char * Read_Data)
{ 
  unsigned char wait_time_out = wait_time_value;//等待I2C器件響應的延時
  * Read_Data = 0;

  while (I2C_GetFlagStatus(HW_I2C, I2C_FLAG_BUSY))   //判斷IIC介面狀態.當IIC狀態為BUSY時,一直停在這裡迴圈  
  {
    if((wait_time_out --) == 0) //延時等待
    {
      return 0; //響應超時,返回無效標誌
    }
  }

  /*傳送START之後要等待,意味著START條件被正確釋放,此時IIC總線上沒有其它外設*/  
  I2C_GenerateSTART( HW_I2C, ENABLE );                                          //產生START條件     
  while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_MODE_SELECT))             //判斷開始訊號是否已經發送完成  
  {
    if((wait_time_out --) == 0) //延時等待
    {
      return 0; //響應超時,返回無效標誌
    }
  }

  I2C_Send7bitAddress(HW_I2C, ADXL_WRITE, I2C_Direction_Transmitter );          //傳送從機地址ADXL_WRITE以選擇從機,主機為傳送模式  
  while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))  //如果主機發射模式被選中(死迴圈等待從機發送ACK訊號)  
  {
    if((wait_time_out --) == 0) //延時等待
    {
      return 0; //響應超時,返回無效標誌
    }
  }

  I2C_SendData(HW_I2C, Read_Address );                                         //將write_address,即要讀的地址通過IIC2傳送出去 
  while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))         //如果地址已經從IIC成功發射出去(死迴圈等待ACK訊號
  {
    if((wait_time_out --) == 0) //延時等待
    {
      return 0; //響應超時,返回無效標誌
    }
  }

  I2C_GenerateSTART(HW_I2C, ENABLE );                                            //產生START條件  
  while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_MODE_SELECT))                //如果主機被選中(死迴圈等待ACK訊號)
  {
    if((wait_time_out --) == 0) //延時等待
    {
      return 0; //響應超時,返回無效標誌
    }
  }
   /***主機接收資料***/  
  I2C_Send7bitAddress(HW_I2C, ADXL_READ, I2C_Direction_Receiver );              //主機設定為接收模式  
  while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))      //如果主機接收模式被選中(死迴圈等待ACK訊號) 
  {
    if((wait_time_out --) == 0) //延時等待
    {
      return 0; //響應超時,返回無效標誌
    }
  }

  I2C_AcknowledgeConfig(HW_I2C, DISABLE );                                        //失能IIC的應答狀態 NACK  
  I2C_GenerateSTOP( HW_I2C, ENABLE );                                           //產生STOP條件  
  while (!(I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED)))           //判斷資料是否接收完成       
  {
    if((wait_time_out --) == 0) //延時等待
    {
      return 0; //響應超時,返回無效標誌
    }
  }

  I2C_AcknowledgeConfig(HW_I2C, ENABLE );                                      //再一次使能IIC的應答狀態  
  * Read_Data = I2C_ReceiveData(HW_I2C);                                        //返回IIC接收的資料 
  return 1;
}



/**
* @brief  通過I2C介面將資料寫入從機指定地址中.
* @param  要寫入的資料,接收資料的地址;
* @retval 1:資料寫入成功 0:資料寫入失敗
*/
unsigned char  I2C_Write_Byte(uint8_t Point_Buffer,uint8_t Write_Address)
{
  unsigned char wait_time_out = wait_time_value;//等待I2C器件響應的延時

  while (I2C_GetFlagStatus(HW_I2C, I2C_FLAG_BUSY))   //判斷當前I2C介面狀態是否為Busy 
  {
    if((wait_time_out --) == 0) //延時等待
    {
      return 0; //響應超時,返回無效標誌
    }
  }

  I2C_GenerateSTARTHW_I2C, ENABLE );                                          //產生Start訊號  
  while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_MODE_SELECT))               //判斷Start訊號是否已經發送
  {
    if((wait_time_out --) == 0) //延時等待
    {
        return 0;   //響應超時,返回無效標誌
    }
  }

  I2C_Send7bitAddress(HW_I2C, ADXL_WRITE, I2C_Direction_Transmitter );              //傳送從機地址以選擇從機,主機為傳送模式  
  while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))   //判斷髮送的地址是否與從機匹配,等待從機發送ACK訊號
  {
    if((wait_time_out --) == 0) //延時等待
    {
      return 0; //響應超時,返回無效標誌
    }
  } 

  I2C_SendData(HW_I2C, Write_Address );                                        //將write_address,即要寫的暫存器地址通過IIC傳送出去     
  while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))          //判斷資料是否傳送完成
  {
    if((wait_time_out --) == 0) //延時等待
    {
      return 0; //響應超時,返回無效標誌
    }
  }
   /*往暫存器傳送資料data*/  
  I2C_SendData(HW_I2C, Point_Buffer );  
  while (!I2C_CheckEvent(HW_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))            //判斷資料是否傳送完成
  {
    if((wait_time_out --) == 0) //延時等待
    {
      return 0; //響應超時,返回無效標誌
    }
  }

  I2C_GenerateSTOP( HW_I2C, ENABLE );                                           //IIC2產生STOP條件  

  return 1;//資料寫入完成 1
}
/**
  ******************************************************************************
  * @file    Hardware_I2C.h 
  * @author  Ryan Zhao
  * @version V1.0.0
  * @date    2017-04-27
  * @brief   STM32硬體I2C底層驅動.
  ******************************************************************************
  * @attention   Null
  * 
  ******************************************************************************
  */



/*********************I2C 物理層GPIO定義*******************/
#define HW_I2C                           I2C1       //第一組I2C介面
#define HW_I2C_SDA_PIN                   GPIO_Pin_7               
#define HW_I2C_SDA_GPIO_PORT             GPIOB                      
#define HW_I2C_SCL_PIN                   GPIO_Pin_6                  
#define HW_I2C_SCL_GPIO_PORT             GPIOB  
#define wait_time_value                  200         //等待I2C器件響應的延時