1、IIC定義
IIC 即Inter-Integrated Circuit(集成電路總線),這種總線型別是由飛利浦半導體公司(后被NXP收購)在八十年代初設計出來的一種簡單、雙向、二線制、同步串行總線,主要是用來連接整體電路(ICS) ,IIC是一種多向控制總線,也就是說多個芯片可以連接到同一總線結構下,同時每個芯片都可以作為實時資料傳輸的控制源,多主多從的通訊協議,
下文將結合NXP官方的IIC手冊講解IIC協議,下載鏈接見文末,
I2C串行總線一般有兩根信號線,一根是雙向的資料線SDA,另一根是時鐘線SCL,所有接到I2C總線設備上的串行資料SDA都接到總線的SDA上,各設備的時鐘線SCL接到總線的SCL上,速率最高400Kbit/s,
在1998年的修訂中增加了高速模式,速率高達3.4Mbit/s,(這里不講,只說快速模式),
2、IIC協議規范
2.1 SDA和SCL信號
連接到總線的器件輸出級必須是漏極開路或集電極開路才能執行線與的功能,當總線空
閑時這兩條線路都是高電平,SDA 和SCL 都是雙向線路都通過一個電流源或上拉電阻連接到正的電源電壓,一般情況下我們都采用上拉電阻的方式
2.2 資料有效性
在SCL高電平的時候采樣,也就是有效,低電平的時候切換資料
2.3 開始和結束信號
起始條件:SCL線是高電平時,SDA線從高電平向低電平切換,
停止條件:SCL線是高電平時,SDA線從低電平向高電平切換,
影片展示啟動信號
代碼實作
void I2C_Start(void) { //IO輸出 SDA_OUT(); SCL_OUT(); I2C_DELAY(); //IO置高 SDA_SET(); SCL_SET(); //延時 I2C_DELAY(); //為低 SDA_CLR(); I2C_DELAY(); I2C_DELAY(); SCL_CLR(); }
結束信號時類似的方式(不是動圖)
代碼實作
void I2C_Stop(void) { //IO輸出 SDA_OUT(); SCL_OUT(); //IO置0 SDA_CLR(); SCL_CLR(); I2C_DELAY(); SCL_SET(); //延時 I2C_DELAY(); I2C_DELAY(); I2C_DELAY(); //SDA置1 SDA_SET(); I2C_DELAY(); I2C_DELAY(); }
2.4 位元組格式
SDA資料線上的每個位元組必須是8位,每次傳輸的位元組數量沒有限制,每個位元組后必須跟一個回應位(ACK),首先傳輸的資料是最高位(MSB),SDA上的資料必須在SCL高電平周期時保持穩定,資料的高低電平翻轉變化發生在SCL低電平時期,
每一個位元組后面跟著一個ACK,有ACK就可以繼續寫或讀,NACK,就停止
ACK:主機釋放總線,傳輸完位元組最后1位后的SCL的高電處,從機拉低電平,
NACK:主機釋放總線,傳輸完位元組最后1位后的SCL的高電處,從機無回應,總線為高電平,
影片描述寫入的程序
代碼實作
uint8_t I2C_Send_byte(uint8_t data) { uint8_t k; //發送8bit資料 for(k=0;k<8;k++){ I2C_DELAY(); if(data&0x80){ SDA_SET(); } else{ SDA_CLR(); } data=data<<1; I2C_DELAY(); SCL_SET(); I2C_DELAY(); I2C_DELAY(); SCL_CLR(); } //延時讀取ACK回應 I2C_DELAY(); SDA_SET(); //置為輸入線 SDA_IN(); I2C_DELAY(); SCL_SET(); I2C_DELAY(); //這里出現了問題,延時變的無限大 //讀資料 k=SDA_READ(); if(k){ NACK回應 return 0; } I2C_DELAY(); SCL_CLR(); I2C_DELAY(); SDA_OUT(); if(k){ NACK回應 return 0; } return 1; } uint8_t I2C_Receive_byte(uint8_t flg) { uint8_t k,data; //接收8bit資料 //置為輸入線 SDA_IN(); data=0; for(k=0;k<8;k++){ I2C_DELAY(); SCL_SET(); I2C_DELAY(); //讀資料 data=https://www.cnblogs.com/Fireflycjd/archive/2021/01/30/data |SDA_READ(); data=data<<1; I2C_DELAY(); SCL_CLR(); I2C_DELAY(); } data=data>>1; //往回移動1次 //回傳ACK回應 //置為輸出線 SDA_OUT(); if(flg){ SDA_SET(); //輸出1-NACK }else{ SDA_CLR();//輸出0-ACK } I2C_DELAY(); SCL_SET(); I2C_DELAY(); I2C_DELAY(); SCL_CLR(); I2C_DELAY(); SDA_OUT(); //回傳讀取的資料 return (uint8_t)data; }
2.5 從機地址和讀寫位
開始信號—>地址—>讀寫位—>ACK—>資料—>ACK.............—>停止位
這里只說7位地址,前7位為地址,最后一位為讀寫位,1表示讀操作,0表示寫操作
主機發給從機資料,也就是寫,沒有資料轉向時
主機立即讀從機資料,從第一個位元組
(Combined)綜合資料格式
3、計算IIC的頻率
通信頻率由主機掌控,也就是代碼中的延時函式決定的
從上面,我們得知最高速為400Kbit/s,我們設計300Kbit/s,
速率300Kbit/s,對應周期1/300ms=10/3us≈3us,4分頻就是3/4us,
我們使用的延時是,1/120MHZ*3*30 =3/4us
也就是頻率是300Kbit/s
和SPI類似,時鐘下降沿時,資料轉換,時鐘上升沿時,采樣資料,也就是時鐘高電平資料有效,
/*120Mhz時鐘時,當ulCount為1時,函式耗時3個時鐘,延時=3*1/120us=1/40us*/ /* SystemCoreClock=120000000 us級延時,延時n微秒 SysCtlDelay(n*(SystemCoreClock/3000000)); ms級延時,延時n毫秒 SysCtlDelay(n*(SystemCoreClock/3000)); m級延時,延時n秒 SysCtlDelay(n*(SystemCoreClock/3)); */ #if defined (__CC_ARM) /*!< ARM Compiler */ __asm void SysCtlDelay(unsigned long ulCount) { subs r0, #1; bne SysCtlDelay; bx lr; } #elif defined ( __ICCARM__ ) /*!< IAR Compiler */ void SysCtlDelay(unsigned long ulCount) { __asm(" subs r0, #1\n" " bne.n SysCtlDelay\n" " bx lr"); } #elif defined (__GNUC__) /*!< GNU Compiler */ void __attribute__((naked)) SysCtlDelay(unsigned long ulCount) { __asm(" subs r0, #1\n" " bne SysCtlDelay\n" " bx lr"); } #elif defined (__TASKING__) /*!< TASKING Compiler */ /*無*/ #endif /* __CC_ARM */ /* * @brief SysCtlDelay * @param ulCount 延時值,必須大于0 * @retval None */ void SysCtlDelay_IIC(unsigned long ulCount) { SysCtlDelay(ulCount); } /定義時鐘頻率,300KHz #define I2C_DELAY() SysCtlDelay_IIC(30)
4、PCF8536
4.1 Acknowledge
這個地方能看到關于2.4節關于ACK和NACk的說明,
4.2 Addressing
這里直接給出讀地址和寫地址,也就是最后一位的區別
4.3 讀寫時序
其實就是按照IIC協議的
讀指定器件的指定暫存器
主機設定完暫存器地址之后,再去讀寫
注意:讀取多個位元組,最后一個位元組的回包應該是NACK
主機立即從機第一個位元組讀取
注意:讀取多個位元組,最后一個位元組的回包應該是NACK
開源地址:
https://github.com/strongercjd/STM32F207VCT6
點擊查看本文所在的專輯,STM32F207教程
資料下載:
https://pan.baidu.com/s/1lRMxv2EnHRUtugIZloMrxg 提取碼:npz0
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/254655.html
標籤:其他
上一篇:QT串口助手(四):資料發送
