目標(biāo):EEPROM-IIC總線理解(三)
代碼編寫(一):
//延時函數(shù),延時10us
void I2CDelay() //誤差 0us
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=2;a>0;a--);
}
//起始信號:SCL為高電平時SDA有個從高到底的跳變動作,之后才能進(jìn)行數(shù)據(jù)傳輸
void I2CStart() //產(chǎn)生總線起始信號
{
I2C_SDA = 1; //首先確保SDA腹忽、SCL都是高電平
I2C_SCL = 1;
I2CDelay();
I2C_SDA = 0; //先拉低SDA
I2CDelay();
I2C_SCL = 0; //再拉低SCL
}
//終止信號:SCL為高電平時SDA有個從低到高的跳變動作猖败,之后停止數(shù)據(jù)傳輸
void I2CStop() //產(chǎn)生總線停止信號
{
I2C_SCL = 0; //首先確保SDA、SCL都是低電平
I2C_SDA = 0;
I2CDelay();
I2C_SCL = 1; //先拉高SCL
I2CDelay();
I2C_SDA = 1; //再拉高SDA
I2CDelay();
}
//注意:在SCL是高電平時不要亂改變SDA的狀態(tài)防止是停止信號使運(yùn)行失敗
//數(shù)據(jù)發(fā)送(寫):只有在SCL是高電平時SDA上的數(shù)據(jù)是有效的烹俗。編寫單片機(jī)向總線發(fā)送數(shù)據(jù)時爆侣,可以在SCL是低電平時把數(shù)據(jù)傳輸?shù)絊DA中(SCL在低電平時SDA才能改變數(shù)據(jù)),
//等一個字節(jié)傳輸完后幢妄,拉高SCL電平延時一段時間后再拉低SCL電平(在延時時間內(nèi)即SCL是高電平這段時間內(nèi)SDA不能發(fā)生變化)來使SDA中的而數(shù)據(jù)發(fā)送到從機(jī)
unsigned char I2cSendByte(unsigned char dat)
{
unsigned char a=0;b=0; //最大255兔仰,一個機(jī)器周期為1us,最大延時255us蕉鸳。
for(a=0;a<8;a++){
SDA = dat>>7; //起始信號后SCL=0,所以可以直接改變SDA,因?yàn)閿?shù)據(jù)是先按高字節(jié)發(fā)送的所以向右移7位把最到位高位放到最低位的地方乎赴,此時數(shù)據(jù)雖然給力SDA但并每沒有發(fā)送到從機(jī)
dat = dat<<1; //把次高位變?yōu)樽罡呶? I2CDelay(); //上面幾行是數(shù)據(jù)變化的階段
SCL=1; //發(fā)送數(shù)據(jù)時SCL保持高電平,此時數(shù)據(jù)穩(wěn)定
I2CDelay();
SCL=0; //再拉低SCL,完成一個位周期榕吼,scl一個位周期然后數(shù)據(jù)發(fā)送出去了饿序,準(zhǔn)確的說是在SCL是高電平的這段時間里發(fā)送出去了
I2CDelay();//此上到SCL=1;是數(shù)據(jù)發(fā)送的條件
}
SDA=1;//8位數(shù)據(jù)發(fā)送完后友题,主機(jī)釋放SDA嗤堰,以檢測從機(jī)應(yīng)答
I2CDelay();
SCL=1;//拉高SCL,來讀取SDA的狀態(tài)
while(SDA) //等待應(yīng)答度宦,也就是等待從設(shè)備把SDA拉低
{
b++;
if(b>200){ //如果超過2000us沒有應(yīng)答發(fā)送失敗踢匣,或者為非應(yīng)答,表示接收結(jié)束
SCL=0;
I2CDelay();
return 0; //未響應(yīng)
}
}
SCL=0; //時鐘線拉低
I2CDelay();
return 1; //響應(yīng)了戈抄,說明b++還沒累加到200
}
FC總線每接收完一個字節(jié)(8個位)后离唬,在第9個時鐘信號時,會在SDA上回應(yīng)一個低電平的ACK應(yīng)答信號划鸽,以此表明當(dāng)前受控的器件已接收完一個字節(jié)输莺,可以開始下一個字節(jié)的傳送了。
編程時可以在傳送完一個字節(jié)后裸诽,把連接SDA的I/O口線設(shè)置回讀數(shù)據(jù)狀態(tài)嫂用,如使用51系列的單片機(jī)時就要把I/O口置高電平,然后在SCL.腳設(shè)置一個脈沖丈冬,在SCL為高電平時讀取SDA嘱函,如不為低電平就說明器件狀態(tài)不空閑或出錯。需要注意埂蕊,因?yàn)镾DA是雙向的I/O往弓,無論是接收還是器件接收,每個字節(jié)完成后蓄氧,接收方都可以發(fā)送一個ACK回應(yīng)給發(fā)送方函似。
//數(shù)據(jù)讀取:
unsigned char I2cReadByte()
{
unsigned char a=0,dat=0; //dat用于接受單片機(jī)接受到的數(shù)據(jù)
SDA=1; //起始和發(fā)送一個字節(jié)之后SCL都是0
I2CDelay();
for(a=0;a<8;a++){
SCL=1; //只有在SCL電平是高電平時SDA數(shù)據(jù)才有效喉童,所以讀的時候先把SCL拉高再去讀SDA中的數(shù)據(jù)
I2CDelay();
dat<<=1;
dat|=SDA; //dat來接受SDA中的數(shù)據(jù)
I2CDelay();
SCL=0; //拉低SCL
I2CDelay();
}
return dat; //返回接收到的數(shù)據(jù)
}