|
|
如下疑問 :
關(guān)于程序中這個(gè)讀字節(jié)的子函數(shù) uchar read_byte() ,讀取EEPROM內(nèi)數(shù)據(jù)時(shí),用了 “ k=(k<<1)|sda; ”,然后循環(huán)8次,這里是如何得到一個(gè)字節(jié)數(shù)據(jù)的,沒弄明白。
我理解是k左移之后(不管k初值是什么),低位補(bǔ)0,而sda要么是0000 0000,要么是0000 0001,是固定的,所以進(jìn)行按位或之后的k要么是0000 0000,要么是0000 0001,這個(gè)也是固定的,不管循環(huán)多少次,每次得到的k都是0000 0000,或者是0000 0001,怎么就讀取到內(nèi)部的0x55這個(gè)數(shù)據(jù)了呢? 而且實(shí)際運(yùn)行用P1點(diǎn)亮LED也是正確的。
感謝指點(diǎn)!
以下是單片機(jī)代碼(注釋是自己寫的,有錯(cuò)誤的地方還請(qǐng)不吝指正):
#include <reg52.h>
#include <intrins.h>
sbit scl=P2^1;
sbit sda=P2^0;
typedef unsigned char uchar;
typedef unsigned int uint;
void delayms(uchar z)
{
int x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void delayus()
{
_nop_();_nop_();_nop_();_nop_();_nop_();
}
void start() //開始信號(hào)
{
sda=1;
scl=1;
delayus(); //根據(jù)時(shí)序圖,scl和sda都為1的時(shí)候要保持4.7us以上。
sda=0; //在scl為高電平的狀態(tài)下,sda產(chǎn)生下降沿
delayus(); //根據(jù)時(shí)序圖,數(shù)據(jù)拉低后保持4us以上。
scl=0; //根據(jù)時(shí)序圖,將scl拉低,后面開始字節(jié)傳輸。
delayus();
}
void stop() //停止信號(hào)
{
sda=0;
scl=1;
delayus(); //根據(jù)時(shí)序圖,scl和sda分別為1、0的時(shí)候要保持4us以上。
sda=1; //在scl為高電平的狀態(tài)下,sda產(chǎn)生上升沿
delayus(); //根據(jù)時(shí)序圖,數(shù)據(jù)拉高后保持4.7us以上。
sda=0; //根據(jù)時(shí)序圖,將sda拉低。
delayus();
}
void respons() //應(yīng)答信號(hào)
{
uchar i;
sda=1; //不管之前sda是什么狀態(tài),先釋放sda
delayus();
scl=1; //將scl拉高,用于sda響應(yīng)。
delayus();
while((sda==1)&&(i<250)) i++;
scl=0;
delayus();
}
void write_byte(uchar date) //寫字節(jié),可以用來寫 器件地址 或 內(nèi)存地址 或 數(shù)據(jù)。
{
uchar i,temp;
temp=date;
scl=0;
for(i=0;i<8;i++) //總共8位(器件地址是7位+1位讀寫位,內(nèi)存地址是8位),所以需要循環(huán)8次。
{
temp=temp<<1; //將器件地址進(jìn)行左移,左移之后會(huì)溢出,因?yàn)镮IC是從MSB開始寫,所以要左移。
sda=CY; //每當(dāng)有數(shù)據(jù)溢出1,CY都會(huì)置1,溢出0,會(huì)置0,賦給sda,就得到了本次移出來的地址數(shù)據(jù)
delayus();
scl=1;
delayus(); //延時(shí),給從機(jī)時(shí)間讀取sda信號(hào)。
scl=0; //傳輸完一位后就將SCL拉低,下一次循環(huán)時(shí)sda才允許發(fā)生變化。
}
scl=0;
delayus();
sda=1;
delayus();
}
uchar read_byte() //字節(jié)讀取
{
uchar j,k;
scl=0;
delayus();
sda=1;
delayus();
for(j=0;j<8;j++)
{
scl=1;
delayus();
k=(k<<1)|sda; //k的初值不管是什么,左移之后LSB都是0
scl=0;
delayus();
}
return k;
}
void init()
{
sda=1;
scl=1;
delayus();
}
void main() // 主程序思路為先往24C02中寫0x55,然后再讀出來并且賦值給P1
{
init();
start();
write_byte(0xa0); //尋址,并且下一步為寫。
respons(); //從機(jī)響應(yīng),疑問:respons函數(shù)中,沒有響應(yīng)時(shí)超時(shí)后也會(huì)繼續(xù),那主機(jī)往哪里寫?
write_byte(22); //寫存儲(chǔ)地址,指定后面要往存儲(chǔ)器的第22個(gè)地址去寫數(shù)據(jù)。24c02總共256個(gè)字節(jié)地址,所以0~255都可以。
respons();
write_byte(0x55); //往存儲(chǔ)器的第22個(gè)地址中寫入數(shù)據(jù)0x55
respons();
stop();
delayms(100); //進(jìn)入24C02的寫周期,需>10ms
/*下面一段參考24c02的隨機(jī)讀時(shí)序來寫,將上面剛剛寫進(jìn)第22個(gè)地址的數(shù)據(jù)讀出來賦值給P1*/
start();
write_byte(0xa0); //尋址,并且下一步為寫
respons(); //從機(jī)響應(yīng)
write_byte(22); //指定要訪問的地址為22
respons();
start(); //由寫變?yōu)樽x,所以要重新開始一下
write_byte(0xa1); //尋址,并且下一步為讀
respons();
P1=read_byte();
stop();
while(1); //主程序?qū)憽⒆x完之后,將讀到的數(shù)據(jù)給P1,然后讓程序停在這里。
}
|
|