一.IIC傳輸數據的格式
?
1.寫操作
2.讀操作?
3.IIC信號?
二. IIC底層驅動
#define SCL_PIN GPIO_PIN_6
#define SDA_PIN GPIO_PIN_7#define SCL_PORT GPIOB
#define SDA_PORT GPIOB/********************** 函數宏定義
**********************/
#define SCL_H HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, 1)
#define SCL_L HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, 0)#define SDA_H HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, 1)
#define SDA_L HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, 0)
#define SDA_IN HAL_GPIO_ReadPin(SDA_PORT, SDA_PIN)/** 函數名:I2C_GPIO_ReInit* 功能描述:將模擬I2C的SCL和SDA引腳進行重新初始化* 輸入參數:無* 輸出參數:無* 返回值:無
*/
extern void I2C_GPIO_ReInit(void);/** 函數名:I2C_Start* 功能描述:模擬發出I2C的開始信號-->在SCL的高電平下,SDA的電平由高到低變化* 輸入參數:無* 輸出參數:無* 返回值:無
*/
extern void I2C_Start(void);/** 函數名:I2C_Stop* 功能描述:模擬發出I2C的停止信號-->在SCL的高電平下,SDA的電平由低到高變化* 輸入參數:無* 輸出參數:無* 返回值:無
*/
extern void I2C_Stop(void);/** 函數名:I2C_GetAck* 功能描述:模擬I2C獲取從設備的響應信號-->在SCL的高電平下,從設備將SDA拉低* 輸入參數:無* 輸出參數:無* 返回值:成功得到響應返回0,否則返回-1
*/
extern int I2C_GetAck(void);/** 函數名:I2C_ACK* 功能描述:模擬I2C發出一個應答信號,在第九個時鐘將SDA拉低* 輸入參數:無* 輸出參數:無* 返回值:無
*/
extern void I2C_ACK(void);/** 函數名:I2C_NACK* 功能描述:模擬I2C發出一個非應答信號,在第九個時鐘將SDA拉高* 輸入參數:無* 輸出參數:無* 返回值:無
*/
extern void I2C_NACK(void);/** 函數名:I2C_WriteByte* 功能描述:模擬I2C發出一個字節的數據* 輸入參數:data-->要發送出去的數據,范圍0~255* 輸出參數:無* 返回值:無
*/
extern void I2C_WriteByte(uint8_t data);/** 函數名:I2C_ReadByte* 返回值:返回讀取到的數據* 輸入參數:ack-->根據此參數判斷在讀到一個字節之后是否發出應答信號* 輸出參數:無
*/
extern uint8_t I2C_ReadByte(uint8_t ack);#endif /* __DRIVER_I2C_H */
void I2C_Delay(uint32_t t)
{volatile uint32_t tmp = t;while(tmp--);
}/** 函數名:I2C_GPIO_ReInit* 功能描述:將模擬I2C的SCL和SDA引腳進行重新初始化* 輸入參數:無* 輸出參數:無* 返回值:無
*/
void I2C_GPIO_ReInit(void)
{/* 1. 使用結構體定義硬件GPIO對象 */GPIO_InitTypeDef GPIO_InitStruct = {0};/* 2. 將SCL和SDA的GPIO寄存器的值恢復為復位上電值 */HAL_GPIO_DeInit(SCL_PORT, SCL_PIN);HAL_GPIO_DeInit(SDA_PORT, SDA_PIN);/* 3. 使能SCL和SDA的GPIO的時鐘,因為他們都是GPIOF組的,所以這里只使能GPIOF的時鐘 */__HAL_RCC_GPIOF_CLK_ENABLE();/* 4. 設置GPIO的模式為開漏輸出模式,響應速度設置為快速響應 */GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;/* 5. 選擇要設置的GPIO引腳 */GPIO_InitStruct.Pin = SCL_PIN;/* 6. 調用init函數初始化GPIO */HAL_GPIO_Init(SCL_PORT, &GPIO_InitStruct);GPIO_InitStruct.Pin = SDA_PIN;HAL_GPIO_Init(SDA_PORT, &GPIO_InitStruct);
}/** 函數名:I2C_Start* 功能描述:模擬發出I2C的開始信號-->在SCL的高電平下,SDA的電平由高到低變化* 輸入參數:無* 輸出參數:無* 返回值:無
*/
void I2C_Start(void)
{SCL_H;SDA_H;I2C_Delay(100);SDA_L;I2C_Delay(100);
}/** 函數名:I2C_Stop* 功能描述:模擬發出I2C的停止信號-->在SCL的高電平下,SDA的電平由低到高變化* 輸入參數:無* 輸出參數:無* 返回值:無
*/
void I2C_Stop(void)
{SDA_L;SCL_H;I2C_Delay(100);SDA_H;I2C_Delay(100);
}/** 函數名:I2C_GetAck* 功能描述:模擬I2C獲取從設備的響應信號-->在SCL的高電平下,從設備將SDA拉低* 輸入參數:無* 輸出參數:無* 返回值:成功得到響應返回0,否則返回-1
*/
int I2C_GetAck(void)
{int i = 0;SCL_L;SDA_H;I2C_Delay(100);SCL_H;while(SDA_IN != 0){i++;if(i == 100){SCL_L;return -1;}I2C_Delay(10);}SCL_L;return 0;
}/** 函數名:I2C_ACK* 功能描述:模擬I2C發出一個應答信號,在第九個時鐘將SDA拉低* 輸入參數:無* 輸出參數:無* 返回值:無
*/
void I2C_ACK(void)
{SCL_L;SDA_L;I2C_Delay(100);SCL_H;I2C_Delay(100);
}/** 函數名:I2C_NACK* 功能描述:模擬I2C發出一個非應答信號,在第九個時鐘將SDA拉高* 輸入參數:無* 輸出參數:無* 返回值:無
*/
void I2C_NACK(void)
{SCL_L;SDA_H;I2C_Delay(100);SCL_H;I2C_Delay(100);
}/** 函數名:I2C_WriteByte* 功能描述:模擬I2C發出一個字節的數據* 輸入參數:data-->要發送出去的數據,范圍0~255* 輸出參數:無* 返回值:無
*/
void I2C_WriteByte(uint8_t data)
{uint8_t i = 0;for(i=0; i<8; i++){SCL_L;I2C_Delay(100);if(data & 0x80){SDA_H;}else{SDA_L;}data <<= 1; // 發出1bit數據后,要更新數據,將data的次高位移位到最高位SCL_H;I2C_Delay(100);}I2C_GetAck();
}/** 函數名:I2C_ReadByte* 返回值:返回讀取到的數據* 輸入參數:ack-->根據此參數判斷在讀到一個字節之后是否發出應答信號* 輸出參數:無
*/
uint8_t I2C_ReadByte(uint8_t ack)
{uint8_t i = 0;uint8_t data = 0;SDA_H;for(i=0; i<8; i++){SCL_L;I2C_Delay(100);SCL_H;I2C_Delay(100);data <<= 1; // 更新數據前,要將上一次數據左移1位用來保存接下來的這一位數據if(SDA_IN == 1) { data++;}else{data = data;}}// 根據ack決定是否發出應答if(ack == 0){I2C_ACK();}else if(ack == 1){I2C_NACK();}return data;
}