引言
最近在學習幾種串行通信協議,感覺收獲很多,這篇文章是學習IIC總線協議的第一篇文章,以后還會再寫一篇關於PCF8591 IIC通信的ADDA轉換芯片的文章.
關於IIC總線
IIC 即Inter-Integrated Circuit(集成電路總線),這種總線類型是由飛利浦半導體公司在八十年代初設計出來的一種簡單、雙向、二線制、同步串行總線,主要是用來連接整體電路(ICS) ,IIC是一種多向控制總線,也就是說多個芯片可以連接到同一總線結構下,同時每個芯片都可以作為實時數據傳輸的控制源。主要包括啟始、停止、讀、寫、應答信號。這種方式簡化了信號傳輸總線接口。
IIC總線上可以掛多個器件,而每個器件都有唯一的地址,這樣可以標識通信目標。數據的通信的方式采用主從方式,主機負責主動聯系從機,而從機則被動回應數據。
關於AT24C02
AT24C02是一個2K位串行CMOS E2PROM, 內部含有256個8位字節,CATALYST公司的先進CMOS技術實質上減少了器件的功耗。AT24C02有一個8字節頁寫緩沖器。該器件通過IIC總線接口進行操作,有一個專門的寫保護功能。在單片機上的應用廣泛, 可以實現掉電數據不丟失功能。
IIC總線數據有效性的規定
SCL=1期間,SDA必須保持穩定,SCL=0時,SDA才允許改變。
IIC 總線的幾種信號
1.起始和終止信號:
從時序圖可以看出,起始信號為,SCL=1,SDA下降沿;終止信號為SCL=1,SDA為上升沿,保持的時間是有限制的:
具體的程序實現如下:
起始信號:SDA=1保持時間大於4。7us,隨后SDA=0保持時間大於4us
/*SDA下降沿*/ void start() { SDA = 1; //順序不能反了,先是SDA=1; SCL = 1; delay(); SDA = 0; delay(); }
終止信號:SDA=0保持時間大於4us,隨后SDA=1保持時間大於4。7us
/*SDA上升沿*/ void end() { SDA = 0; //順序不能反了,先是SDA=0; SCL = 1; delay(); SDA = 1; delay(); }
2.應答信號:
傳送的每一個字節必須保證是8位長度。數據傳送時,先傳送最高位(MSB),每一個被傳送的字節后面都必須跟隨一位應答信號(即一幀共有9位)。
如:主機往總線上發送一個字節的數據后,釋放總線,從機會把總線拉低(即應答信號),以表示這一字節發送成功
同理主機從總線上讀取完一個字節的數據后,主機會把總線拉低,"告訴"從機這一字節的數據接收成功
程序實現
應答信號:
void ack() { uchar i = 0; SCL = 1; delay(); while(SDA == 1 && i < 250)i++; SCL = 0; //SCL=0,SDA可以改變 delay(); }
3.AT24C02的器件地址:
根據數據手冊和原理圖可以看出器件地址為:0x90/0x91其中最后一位是讀寫方向位,若下一個字節為向總線上發送數據,則為0x90,若下一個字節是從總線上讀取數據,則為0x91。
4.往總線上寫一字節的數據
程序實現:先寫最高位,通過左移運算符,將一字節的數據一位一位的傳送到總線上,其中CY存儲的是左移后的進位
void write_byte(uchar dat) { uchar i; for(i = 0; i < 8; i++) { dat = dat << 1; //如1011 0011 左移一位為0110 0110 SCL = 0; //SDL=0,才能往SDA送數據,或從SDA讀數據 delay(); SDA = CY; //上面左移后進位為1 delay(); SCL = 1; delay(); } SCL = 0; // delay(); SDA = 1; //釋放SDA delay(); }
5.從總線上讀取一個字節的數據
程序實現:帶返回值,先讀高位,然后通過移位運算符,一位一位讀入
uchar read_byte() { uchar dat = 0, tmp, i; SCL = 0; delay(); for(i = 0; i < 8; i++) { SCL = 1; //讓SDA保持穩定,准備讀取 delay(); tmp = SDA; //讀取此時SDA的狀態 dat = dat << 1; dat = dat | tmp; delay(); SCL = 0; //釋放SDA總線,為下一次讀取做准備 delay(); } return dat; }
AT24C02讀寫操作
1.通過以上幾種信號的組合,可以向AT24C02指定單元地址寫一字節的數據,可以看出,讀寫順序為:起始,寫器件地址,應答,寫單元地址,應答,寫數據,應答,終止。
程序實現:此函數無返回值,有兩個形參, 內存單元地址,范圍0-255;要寫的數據,如0xfe;
void write_AT24C02(uchar unit_addr, uchar dat) { start(); write_byte(AT24C02_ADDR + 0); //下一個字節為寫,所以是+0 ack(); write_byte(unit_addr); ack(); write_byte(dat); ack(); end(); }
2.從AT24C02任意單元地址讀取數據,可以看出讀寫順序為:起始,寫器件地址+0(下一個字節為寫),應答,寫單元地址,應答,起始,寫器件地址+1(下一個字節為讀取),讀取數據,終止。
具體程序實現:此函數有返回值,一個形參;單元地址,范圍:0-255;
uchar read_AT24C02(uchar unit_addr) { uchar dat; /*先寫數據*/ start(); write_byte(AT24C02_ADDR + 0); //下一個字節為寫 ack(); write_byte(unit_addr); ack(); start(); write_byte(AT24C02_ADDR + 1); //下一個字節為讀 ack(); dat = read_byte(); end(); return dat; }
延時函數:
void delay() //短暫5us延時 { ;; }
IIC初始化:
void I2C_init() //初始化 { SDA = 1; delay(); SCL = 1; delay(); }
具體應用
有了以上幾個函數,我們就可以寫主函數了, 功能是向內存單元211,寫入數據0xae,然后在從內存單元211中讀取出來,送給P1口led顯示.注意:寫完后要延時一會才能讀取,否則不能成功讀取.
void main() { write_AT24C02(211, 0xae); delay_10ms(); //寫完后,必須延時一定的時間才可以讀取,否則不行 P1 = read_AT24C02(211); while(1); }
總結
通過IIC 總線通信協議的學習,可以看出,IIC總線用IO口模擬操作起來還是很簡單的,使用起來還是比較方便的,而且還可以多個IIC器件掛接在一條總線上,只需要SDA和SCL兩根線即可,當然也有缺點,由於是只有一根數據線,所以不能全雙工傳輸,傳輸速度也有一定的限制.
我是初學者,以上內容如有錯誤,歡迎指正.
參考資料:
AT24C02_百度百科
iic_百度百科
歡迎大家關注我的個人博客 http://www.wangchaochao.top/
微信掃碼關注我的公眾號
不定期更新個人學習筆記和技術總結,歡迎大家互相學習交流!