求大神指點:我想向EEPROM內(nèi)寫入一個數(shù),然后再把他讀出來驗證寫入成功,以此來學(xué)習(xí)IIC通訊協(xié)議的用法。但是讀出來的結(jié)果是255,不管怎么調(diào)試都沒用。哪位高手有邏輯分析儀能幫我看看是哪里出錯了嗎?
單片機源程序如下:
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define At24c02ADDR 0xa0 //At24c02EEPROM地址宏定義
#define I2cWrite 0
#define I2cRead 1
sbit SCL=P2^1;
sbit SDA=P2^0;
sbit dula=P2^6;
sbit wela=P2^7;
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d, //編碼表
0x7d,0x07,0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,0x00 };
bit AcKFlag;
uchar bai,shi,ge;
void delay(uint z) //定義 延時函數(shù)
{
uint x,y;
for(x=0;x<100;x++)
for(y=0;y<z;y++);
}
void delay5us() //定義 延時函數(shù)
{
_nop_();
}
void I2Cstart() //定義 起始信號函數(shù)
{
SDA=1;
SCL=1;
delay5us();
SDA=0;
delay5us();
}
void I2Cstop() //定義 停止信號函數(shù)
{
SCL=0;
SDA=0;
SCL=1;
delay5us();
SDA=1;
delay5us();
}
bit ReadAck() //定義 主機讀從機應(yīng)答信號函數(shù)
{
SCL=0;
SCL=1;
delay5us();
if(SDA)
{ //非應(yīng)答
SCL=0; //拉低SCL(據(jù)波形圖)
return(1);
}
else
{
SCL=0;
return(0);
}
}
void SendAck(bit i) //定義 主機發(fā)送應(yīng)答
{
SCL=0;
if(i)
SDA=1;
else
SDA=0;
SCL=1; //SCL拉高,讀取數(shù)據(jù)
delay5us(); //延時保持數(shù)據(jù)穩(wěn)定
SCL=0; //SCL拉低占用總線繼續(xù)通信
SDA=1; //釋放sda ,否則主機會一直占用sda
}
void I2cSendByte(uchar DAT) //定義 寫入數(shù)據(jù)操作邏輯函數(shù)
{
uchar i;
for(i=0;i<8;i++)
{
SCL=0;
delay5us();
if(DAT&0x80)
SDA=1;
else
SDA=0;
SCL=1;
delay5us();
DAT<<=1;
}
SCL=0; //拉低時鐘總線,繼續(xù)通信
SDA=1; //釋放數(shù)據(jù)總線,允許其他設(shè)備傳遞數(shù)據(jù)
}
void At24c02write(uchar ADDR,DAT) //定義 寫入函數(shù)
{
I2Cstart(); //起始信號
I2cSendByte(At24c02ADDR+I2cWrite); //發(fā)送從機地址+寫信號
if(ReadAck())
AcKFlag=1; //主機讀應(yīng)答信號:結(jié)果為無應(yīng)答
else
AcKFlag=0; //主機讀應(yīng)答信號:結(jié)果為有應(yīng)答
I2cSendByte(ADDR); //調(diào)用寫入數(shù)據(jù)操作邏輯函數(shù):發(fā)送想要寫入的內(nèi)存地址
if(ReadAck())
AcKFlag=1;
else
AcKFlag=0;
I2cSendByte(DAT); //調(diào)用寫入數(shù)據(jù)操作邏輯函數(shù):發(fā)送要寫入的數(shù)據(jù)
if(ReadAck())
AcKFlag=1;
else
AcKFlag=0;
I2Cstop(); //停止信號
}
uchar I2cReadByte() //讀取從機內(nèi)存數(shù)據(jù)邏輯子函數(shù)
{
uchar i,DAT;
for(i=0;i<8;i++)
{
DAT<<=1;
SCL=0; //讀數(shù)據(jù)時SDA由從機控制,主機只要控制scl時序,接收sda上的數(shù)據(jù)即可
SCL=1;
if(SDA)
DAT|=0x01;
delay5us();
}
return(DAT);
}
uchar At24c02Read(uchar ADDR) //定義 讀出函數(shù)
{
uchar DAT;
I2Cstart(); //起始信號
I2cSendByte(At24c02ADDR+I2cWrite); //發(fā)送從機(EEPROM)地址+寫信號(此處發(fā)寫信號是為了發(fā)送想要讀取的內(nèi)存單元的地址)
if(ReadAck())
AcKFlag=1; //主機讀應(yīng)答信號:結(jié)果為無應(yīng)答
else
AcKFlag=0; //主機讀應(yīng)答信號:結(jié)果為有應(yīng)答
I2cSendByte(ADDR); //發(fā)送想要讀的內(nèi)存地址
ReadAck(); //主機讀應(yīng)答信號(不管是否應(yīng)答)
I2Cstart(); //重復(fù)起始信號
I2cSendByte(At24c02ADDR+I2cRead); //發(fā)送從機地址+讀信號
if(ReadAck()) //判斷應(yīng)答信號
AcKFlag=1;
else
AcKFlag=0;
DAT=I2cReadByte(); //調(diào)用 讀取從機內(nèi)存數(shù)據(jù)邏輯子函數(shù) 讀一個字節(jié)
SendAck(1); //主機發(fā)送應(yīng)答信號:非應(yīng)答(非應(yīng)答函數(shù)內(nèi)包括,占用總線繼續(xù)通信與釋放數(shù)據(jù)總線允許其他設(shè)備調(diào)用的信號,故調(diào)用的子函數(shù)內(nèi)部不必寫
I2Cstop(); //發(fā)送停止信號
return(DAT); //返回函數(shù)值
}
void display(uchar num)
{
bai=num/100;
shi=num%100/10;
ge=num%10;
while(1)
{
wela=1;
P0=0xdf;
wela=0;
dula=1;
P0=table[bai];
dula=0;
P0=0xff;
delay(3);
dula=1;
P0=table[shi];
dula=0;
P0=0xff;
wela=1;
P0=0xbf;
wela=0;
delay(3);
dula=1;
P0=table[ge];
dula=0;
P0=0xff;
wela=1;
P0=0x7f;
wela=0;
delay(3);
}
}
void main()
{
At24c02write(0x02,6);
delay5us();
delay5us(); //延時一會,待從機將先前接收的數(shù)據(jù)處理完畢,否則可能會讀取失敗
display(At24c02Read(0x02));
while(1);
}
|