一、簡介 由飛利浦主導開發的片間互聯協議。iic通信使用三線(sda scl以及gnd,不包括電源線),極大程度上減少了對ic的io口的占用。同時iic支持多主機以及多從機,方便了程式的設計。 二、協議層簡介 在iic匯流排上scl的電平決定了整條iic匯流排的有效性。 當scl出於高電平時,主機與從機 ...
一、簡介
由飛利浦主導開發的片間互聯協議。iic通信使用三線(sda scl以及gnd,不包括電源線),極大程度上減少了對ic的io口的占用。同時iic支持多主機以及多從機,方便了程式的設計。
二、協議層簡介
在iic匯流排上scl的電平決定了整條iic匯流排的有效性。
當scl出於高電平時,主機與從機可以偵測sda數據的變化,sda上的數據有效。當scl出於低電平時sda線無效,目標準備讀取下一位數據。
在iic匯流排上,一共有四種狀態:起始,0/應答,1/非應答,結束 在scl線處於高電平的狀態下,這四種狀態對應的sda的狀態分別是: 起始: sda產生下降沿 0/ack: sda處於低電平 1/nack:sda處於高電平 結束: sda產生上升沿 同時,在iic匯流排啟動後以及一輪通信結束後,需要將scl置1,便於其他設備快速發起以及響應iic請求。而在通信中,scl要在讀取前與讀取後及時置0,便於目標設備讀取下一位數據。
iic幀格式
首先是起始信號,通知各設備開始傳輸。隨後是1byte的目標設備的地址(準確的說,是7位地址加上一個讀寫控制位)。然後由目標設備給出ack。在主機收到ack後,可進行對應數據的讀取。在數據傳輸部分,根據iic協議規定,每次只允許連續傳輸1byte,也即隨後需要有一方及時給出ack,否則將超時終止傳輸(包括nack)。所有數據傳輸完畢後,主機設置結束信號。
在一次通信中,如果需要轉變讀寫狀態,需要主機重新發送起始信號、目標地址與讀寫狀態。
三、參考實現:
基於stm32f103c6t6 HAL編寫
iic.c
#include "iic.h"
//private functions
void sda(uint8_t sta) {
HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_Pin, sta ? GPIO_PIN_SET : GPIO_PIN_RESET);
for (int i = 0;i < 100;i++);//delay
}
void scl(uint8_t sta) {
HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_Pin, sta ? GPIO_PIN_SET : GPIO_PIN_RESET);
for (int i = 0;i < 100;i++);
}
void signal(uint8_t sig) {
sda(sig);
scl(0);
scl(1);
scl(0);
}
//public functions
HAL_StatusTypeDef iic_st(void) {
sda(1);//startup
scl(1);
sda(0);
scl(0);
return HAL_OK;
}
HAL_StatusTypeDef iic_ed(void) {
scl(0);//end
sda(0);
scl(1);
sda(1);
return HAL_OK;
}
HAL_StatusTypeDef iic_tx(uint8_t data) {
for (int i = 0;i < 8;i++) {
signal(data >> 7);
data <<= 1;
}
return HAL_OK;
}
HAL_StatusTypeDef iic_rx(GPIO_PinState* pdata) {
uint8_t pin_sta = 0, data = 0;
data = 0;
scl(0);
sda(1);
for (int i = 7;i >= 0;i--) {
scl(1);
pin_sta = HAL_GPIO_ReadPin(SDA_GPIO_Port, SDA_Pin);
data += pin_sta<<i;
scl(0);
}
*pdata = data;
return HAL_OK;
}
HAL_StatusTypeDef iic_wait_ack(void) {
uint8_t t = 0xff;
scl(0);
sda(1);
scl(1);
while (t--) {
if (HAL_GPIO_ReadPin(SDA_GPIO_Port, SDA_Pin) == GPIO_PIN_RESET) {
scl(0);
return HAL_OK;
}
}
iic_ed();
return HAL_TIMEOUT;
}
HAL_StatusTypeDef iic_send_ack(uint8_t ack) {
signal(ack);
return HAL_OK;
}
iic.h
#ifndef __IIC_H__
#define __IIC_H__
#include "stm32f1xx_hal.h"
#define SDA_Pin GPIO_PIN_8
#define SDA_GPIO_Port GPIOB
#define SCL_Pin GPIO_PIN_9
#define SCL_GPIO_Port GPIOB
HAL_StatusTypeDef iic_st(void);
HAL_StatusTypeDef iic_ed(void);
HAL_StatusTypeDef iic_tx(uint8_t data);
HAL_StatusTypeDef iic_rx(uint8_t* data);
HAL_StatusTypeDef iic_wait_ack(void);
HAL_StatusTypeDef iic_send_ack(uint8_t ack) ;
#endif