51單片機普通IO口模擬IIC總線的程序?qū)崿F(xiàn)
IIC是總線結(jié)構(gòu),1個Master,1個或多個Slave,各Slave設(shè)備以7位地址區(qū)分,地址后面再跟1位讀寫位,表示讀(=1)或者寫(=0),所以我們有時也可看到8位形式的設(shè)備地址,此時每個設(shè)備有讀、寫兩個地址,高7位地址其實是相同的。
IIC數(shù)據(jù)格式如下:
無數(shù)據(jù):SCL=1,SDA=1;
開始位(Start):當SCL=1時,SDA由1向0跳變;
停止位(Stop):當SCL=1時,SDA由0向1跳變;
數(shù)據(jù)位:當SCL由0向1跳變時,由發(fā)送方控制SDA,此時SDA為有效數(shù)據(jù),不可隨意改變SDA;
當SCL保持為0時,SDA上的數(shù)據(jù)可隨意改變;
地址位:定義同數(shù)據(jù)位,但只由Master發(fā)給Slave;
應(yīng)答位(ACK):當發(fā)送方傳送完8位時,發(fā)送方釋放SDA,由接收方控制SDA,且SDA=0;
否應(yīng)答位(NACK):當發(fā)送方傳送完8位時,發(fā)送方釋放SDA,由接收方控制SDA,且SDA=1。
當數(shù)據(jù)為單字節(jié)傳送時,格式為:
開始位,8位地址位(含1位讀寫位),應(yīng)答,8位數(shù)據(jù),應(yīng)答,停止位。
當數(shù)據(jù)為一串字節(jié)傳送時,格式為:
開始位,8位地址位(含1位讀寫位),應(yīng)答,8位數(shù)據(jù),應(yīng)答,8位數(shù)據(jù),應(yīng)答,……,8位數(shù)據(jù),應(yīng)答,停止位。
需要注意的是:
1、SCL一直由Master控制,SDA依照數(shù)據(jù)傳送的方向,讀數(shù)據(jù)時由Slave控制SDA,寫數(shù)據(jù)時由Master控制SDA。當8位數(shù)據(jù)傳送完畢之后,應(yīng)答位或者否應(yīng)答位的SDA控制權(quán)與數(shù)據(jù)位傳送時相反。
2、開始位“Start”和停止位“Stop”,只能由Master來發(fā)出。
3、地址的8位傳送完畢后,成功配置地址的Slave設(shè)備必須發(fā)送“ACK”。否則否則一定時間之后Master視為超時,將放棄數(shù)據(jù)傳送,發(fā)送“Stop”。
4、當寫數(shù)據(jù)的時候,Master每發(fā)送完8個數(shù)據(jù)位,Slave設(shè)備如果還有空間接受下一個字節(jié)應(yīng)該回答“ACK”,Slave設(shè)備如果沒有空間接受更多的字節(jié)應(yīng)該回答“NACK”,Master當收到“NACK”或者一定時間之后沒收到任何數(shù)據(jù)將視為超時,此時Master放棄數(shù)據(jù)傳送,發(fā)送“Stop”。
5、當讀數(shù)據(jù)的時候,Slave設(shè)備每發(fā)送完8個數(shù)據(jù)位,如果Master希望繼續(xù)讀下一個字節(jié),Master應(yīng)該回答“ACK”以提示Slave準備下一個數(shù)據(jù),如果Master不希望讀取更多字節(jié),Master應(yīng)該回答“NACK”以提示Slave設(shè)備準備接收Stop信號。
6、當Master速度過快Slave端來不及處理時,Slave設(shè)備可以拉低SCL不放(SCL=0將發(fā)生“線與”)以阻止Master發(fā)送更多的數(shù)據(jù)。此時Master將視情況減慢或結(jié)束數(shù)據(jù)傳送。
下面是本人編寫的單片機普通IO口模擬IIC總線的程序源代碼:
/*Fuction:GPIO模擬iic bus,實現(xiàn)與AT24C02的數(shù)據(jù)通信PS:該源代碼是以STC89C52為平臺編寫的,可通過修改包含的頭文件以適用于所有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ā)送應(yīng)答信號void send_ack(unsigned char ack){scl = 0;somenop();sda = ack;somenop();scl = 1;somenop();scl = 0;somenop();sda = 1;somenop();}//主機接收應(yīng)答信號unsigned char rec_ack(){scl = 1;somenop();if(sda == 1){scl = 0;delay(1);scl = 1;if(sda == 1)return 1;}elsereturn 0;}//寫一個字節(jié)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();}//讀一個字節(jié)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地址寫入len長度的dat數(shù)據(jù)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--);}
評論