一、 綜述
I2C(IIC,Inter-Integrated Circuit),兩線式串行總線,由PHILIPS公司開發用於連接微控制器及其外圍設備。
它是由數據線SDA和時鍾SCL構成的串行總線,可發送和接收數據。在CPU和被控IC之間、IC與IC之間進行雙向傳送,高速IIC總線一般可達400kbps以上。但在STM8中,400kHZ已經是最快速度了。
在往后的模塊調試中也經常涉及,是一個很常見並且很好用的協議。
二、STM8S103中手冊對I2C簡介
看完中文資料手冊,個人覺得比較淺顯,具體使用在后面我會貼出來。
三、 I2C詳細解析
I2C總共由五個核心函數,分別為:
①起始信號
②停止信號
③應答信號
④發送數據
⑤接收數據
通過這五個核心基本函數就能於大多數的傳感進行通信了。
以下對各個部分進行詳細介紹,附上部分主要代碼,各位可以參考一下。
3.1 起始信號
當SCL為高電平期間,SDA由高電平到低電平的跳變過程;起始信號是一種電平跳變時序信號,而不是一個電平信號,如上圖虛線框所。
void Start_Signal_IIC_(void){ //起始信號: GPIO_WriteHigh(GPIOD, GPIO_PIN_2);//數據線 IIC_Delay_4us(); GPIO_WriteHigh(GPIOD, GPIO_PIN_3);//時鍾線 IIC_Delay_4us(); GPIO_WriteLow(GPIOD, GPIO_PIN_2); //數據線 IIC_Delay_4us(); GPIO_WriteLow(GPIOD, GPIO_PIN_3); //時鍾線 IIC_Delay_4us(); }
3.2 停止信號
當SCL為高電平期間,SDA由低電平到高電平的跳變過程;停止信號也是一種電平跳變時序信號,而不是一個電平信號,如上圖虛線框所。
void End_Data_IIC_() { GPIO_WriteLow(GPIOD, GPIO_PIN_2); //數據線拉低 IIC_Delay_4us(); GPIO_WriteHigh(GPIOD, GPIO_PIN_3);//時鍾線拉高 IIC_Delay_4us(); GPIO_WriteHigh(GPIOD, GPIO_PIN_2);//數據線拉高
}
3.3 應答信號
應答信號有兩種:分別是主動應答信號和主動不應答信號
①Ack(主動拉低SDA形成應答信號)
I2C總線的數據都是以字節(8位)的方式傳送的,發送器件每發送一個字節之后,在時鍾的第9個脈沖期間釋放數據總線,由接收器發送一個 ACK(把數據總線的電平拉低)來表示數據成功接收。
//主動應答信號
void vIIC_Ack() { GPIO_WriteLow(GPIOD, GPIO_PIN_2); IIC_Delay_4us(); GPIO_WriteHigh(GPIOD, GPIO_PIN_3); IIC_Delay_4us(); GPIO_WriteLow(GPIOD, GPIO_PIN_3); IIC_Delay_4us(); }
②NAck(主動不拉低SDA不形成應答信號)
在時鍾的第9個脈沖期間發送器釋放數據總線,接收器不拉低數據總線表示一個NACK,NACK有兩種用途:
a. 一般表示接收器未成功接收數據字節;
b. 當接收器是主控器時,它收到最后一個字節后,應發送一個NACK信號,以通知被控發送器結束數據發送,並釋放總線,以便主控接收器發送一個停止信號STOP。
//主動不應答 void vIIC_NAck() { GPIO_WriteHigh(GPIOD, GPIO_PIN_2); IIC_Delay_4us(); GPIO_WriteHigh(GPIOD, GPIO_PIN_3); IIC_Delay_4us(); GPIO_WriteLow(GPIOD, GPIO_PIN_3); IIC_Delay_4us(); }
③ReadAck(等待應答信號)
該信號在主機發送完數據后等待從機應答時候使用。
u8 bIIC_ReadACK() { GPIO_Init(GPIOD, GPIO_PIN_2, GPIO_MODE_IN_PU_IT);//將SDA改為輸入模式。 GPIO_WriteHigh(GPIOD, GPIO_PIN_3); //拉高時鍾線。 IIC_Delay_4us(); if(IIC_SDA_R != 0) { //低 有應答 GPIO_WriteLow(GPIOD, GPIO_PIN_3); IIC_Delay_4us(); GPIO_Init(GPIOD, GPIO_PIN_2, GPIO_MODE_OUT_PP_HIGH_FAST);//SDA return 1; } else //高 無應答 { GPIO_WriteLow(GPIOD, GPIO_PIN_3); IIC_Delay_4us(); GPIO_Init(GPIOD, GPIO_PIN_2, GPIO_MODE_OUT_PP_HIGH_FAST);//SDA return 0; } }
3.4 發送數據
在發送起始信號后開始通信,主機發送一個8位數據。然后,主機釋放SDA線並等待從從機發出得確認信號(ACK)。
void Send_Data_IIC_(uint8_t Data){ int i;
//拉低數據線和時鍾線 GPIO_WriteLow(GPIOD, GPIO_PIN_3); GPIO_WriteLow(GPIOD, GPIO_PIN_2); for(i=0;i<8;i++) { if(Data&0x80) GPIO_WriteHigh(GPIOD, GPIO_PIN_2); else GPIO_WriteLow(GPIOD, GPIO_PIN_2); Data= Data<<1; IIC_Delay_2us(); GPIO_WriteHigh(GPIOD, GPIO_PIN_3); IIC_Delay_4us(); GPIO_WriteLow(GPIOD, GPIO_PIN_3); IIC_Delay_2us(); } }
3.5 接收數據
在發送起始信號后開始通信,主機發送一個8位數據。然后,從機收到數據返回一個確認信號(ACK)給主機,這時候主機才開始接收數據,待主機接收數據完成后,發送一個NACK信號給從機,以通知接收端結束數據接收。
//接收函數 uint8_t uIIC_RecvByte() { uint8_t i,uReceiveByte = 0; GPIO_Init(GPIOD, GPIO_PIN_2, GPIO_MODE_IN_PU_IT); for(i=0;i<8;i++) { uReceiveByte <<= 1; IIC_Delay_4us(); GPIO_WriteHigh(GPIOD, GPIO_PIN_3);//高時鍾線時讀取數據電平 IIC_Delay_4us(); if(IIC_SDA_R !=0 ) { uReceiveByte|=0x01; } IIC_Delay_4us(); GPIO_WriteLow(GPIOD, GPIO_PIN_3); IIC_Delay_4us(); } GPIO_Init(GPIOD, GPIO_PIN_2, GPIO_MODE_OUT_PP_HIGH_FAST); return uReceiveByte; }
3.6 I2C通信總過程
以下圖完美地詮釋了iic從接收到發送全過程中,SDA和SCL線的變化線。綜合上面的解釋和過程代碼,這張圖可以幫助記憶和理解。
四、例程
4.1 編譯環境:
這里用的是IAR進行編譯,較為好用,后期使用STM32的開發板可以推薦使用CUBE直接生成初始化函數,與Keil5相互搭配使用,很是方便。
4.2 主芯片:
我的主芯片是STM8S系列中的103,其中STM8S的003、005、和103、105,配置一樣(外設和CPU頻率,FLASH),在代碼相同的情況下均可進行燒寫。
4.3 代碼&解析
iic代碼可以驅動幾乎市面上的所有時鍾模塊,所以這里的代碼可以與時鍾模塊的代碼相互調用。每個函數我都有加以解釋,可以詳細了解一下。
看了上面的代碼也可以知道,這個協議是由數據線和時鍾線,數據發送接收要求拉高數據線或拉低時鍾線。所以這里推薦直接使用庫函數的拉高低,如果要方便的話,再加個宏定義可以更加直觀方便。
五、結尾
以上是iic的核心函數,對於每個函數我已經寫的很清楚,下一篇博客我會將基於iic的時鍾模塊的傳感通信博客貼出來,各位可以繼續閱讀下一篇博客做一下參考。