51單片機普通IO口模擬IIC總線(xiàn)的程序實(shí)現
IIC是總線(xiàn)結構,1個(gè)Master,1個(gè)或多個(gè)Slave,各Slave設備以7位地址區分,地址后面再跟1位讀寫(xiě)位,表示讀(=1)或者寫(xiě)(=0),所以我們有時(shí)也可看到8位形式的設備地址,此時(shí)每個(gè)設備有讀、寫(xiě)兩個(gè)地址,高7位地址其實(shí)是相同的。
IIC數據格式如下:
無(wú)數據:SCL=1,SDA=1;
開(kāi)始位(Start):當SCL=1時(shí),SDA由1向0跳變;
停止位(Stop):當SCL=1時(shí),SDA由0向1跳變;
數據位:當SCL由0向1跳變時(shí),由發(fā)送方控制SDA,此時(shí)SDA為有效數據,不可隨意改變SDA;
當SCL保持為0時(shí),SDA上的數據可隨意改變;
地址位:定義同數據位,但只由Master發(fā)給Slave;
應答位(ACK):當發(fā)送方傳送完8位時(shí),發(fā)送方釋放SDA,由接收方控制SDA,且SDA=0;
否應答位(NACK):當發(fā)送方傳送完8位時(shí),發(fā)送方釋放SDA,由接收方控制SDA,且SDA=1。
當數據為單字節傳送時(shí),格式為:
開(kāi)始位,8位地址位(含1位讀寫(xiě)位),應答,8位數據,應答,停止位。
當數據為一串字節傳送時(shí),格式為:
開(kāi)始位,8位地址位(含1位讀寫(xiě)位),應答,8位數據,應答,8位數據,應答,……,8位數據,應答,停止位。
需要注意的是:
1、SCL一直由Master控制,SDA依照數據傳送的方向,讀數據時(shí)由Slave控制SDA,寫(xiě)數據時(shí)由Master控制SDA。當8位數據傳送完畢之后,應答位或者否應答位的SDA控制權與數據位傳送時(shí)相反。
2、開(kāi)始位“Start”和停止位“Stop”,只能由Master來(lái)發(fā)出。
3、地址的8位傳送完畢后,成功配置地址的Slave設備必須發(fā)送“ACK”。否則否則一定時(shí)間之后Master視為超時(shí),將放棄數據傳送,發(fā)送“Stop”。
4、當寫(xiě)數據的時(shí)候,Master每發(fā)送完8個(gè)數據位,Slave設備如果還有空間接受下一個(gè)字節應該回答“ACK”,Slave設備如果沒(méi)有空間接受更多的字節應該回答“NACK”,Master當收到“NACK”或者一定時(shí)間之后沒(méi)收到任何數據將視為超時(shí),此時(shí)Master放棄數據傳送,發(fā)送“Stop”。
5、當讀數據的時(shí)候,Slave設備每發(fā)送完8個(gè)數據位,如果Master希望繼續讀下一個(gè)字節,Master應該回答“ACK”以提示Slave準備下一個(gè)數據,如果Master不希望讀取更多字節,Master應該回答“NACK”以提示Slave設備準備接收Stop信號。
6、當Master速度過(guò)快Slave端來(lái)不及處理時(shí),Slave設備可以拉低SCL不放(SCL=0將發(fā)生“線(xiàn)與”)以阻止Master發(fā)送更多的數據。此時(shí)Master將視情況減慢或結束數據傳送。
下面是本人編寫(xiě)的單片機普通IO口模擬IIC總線(xiàn)的程序源代碼:
/*Fuction:GPIO模擬iic bus,實(shí)現與AT24C02的數據通信PS:該源代碼是以STC89C52為平臺編寫(xiě)的,可通過(guò)修改包含的頭文件以適用于所有51系列單片機SD:Jason*/#include#include sbit sda = P2^0;sbit scl = P2^1;unsigned char table1[11]={0,1,2,3,4,5,6,7,8,9};unsigned char table2[11];void init();void somenop();void delay(unsigned char);void start();void stop();void send_ack(unsigned char);unsigned char rec_ack();void write_byte(unsigned char);unsigned char read_byte();unsigned char write_add(unsigned char,unsigned char *,unsigned char);unsigned char read_add(unsigned char,unsigned char *,unsigned char);void main(){init();write_add(0x10,table1,10);delay(100);read_add(0x10,table2,10);while(1);}//端口初始化void init(){memset(table2,0,sizeof(table2));sda = 1;scl = 1;somenop();}//起始信號void start(){sda = 1;somenop();scl = 1;somenop();sda = 0;somenop();}//終止信號void stop(){sda = 0;somenop();scl = 1;somenop();sda = 1;somenop();}//主機發(fā)送應答信號void send_ack(unsigned char ack){scl = 0;somenop();sda = ack;somenop();scl = 1;somenop();scl = 0;somenop();sda = 1;somenop();}//主機接收應答信號unsigned char rec_ack(){scl = 1;somenop();if(sda == 1){scl = 0;delay(1);scl = 1;if(sda == 1)return 1;}elsereturn 0;}//寫(xiě)一個(gè)字節void write_byte(unsigned char dat){unsigned char i,a;a = dat;for(i=0;i<8;i++){a = a<<1;scl = 0;somenop();sda = CY;somenop();scl = 1;somenop();}scl = 0;somenop();sda = 1;somenop();}//讀一個(gè)字節unsigned char read_byte(){unsigned char i,a;scl = 0;somenop();sda = 1;somenop();for(i=0;i<8;i++){scl = 1;somenop();a = (a<<1)|sda;scl = 0;somenop();}return a;}//向add地址寫(xiě)入len長(cháng)度的dat數據unsigned char write_add(unsigned char add,unsigned char *dat,unsigned char len){unsigned char flag,i;start();write_byte(0xa0);if(rec_ack() == 0){write_byte(add);if(rec_ack() == 0){for(i=0;i 0;y--)for(z=110;z>0;z--);}
評論