求大神指點:我想向EEPROM內寫入一個數,然后再把他讀出來驗證寫入成功,以此來學習IIC通訊協議的用法。但是讀出來的結果是255,不管怎么調試都沒用。哪位高手有邏輯分析儀能幫我看看是哪里出錯了嗎?
單片機源程序如下:
#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) //定義 延時函數
{
uint x,y;
for(x=0;x<100;x++)
for(y=0;y<z;y++);
}
void delay5us() //定義 延時函數
{
_nop_();
}
void I2Cstart() //定義 起始信號函數
{
SDA=1;
SCL=1;
delay5us();
SDA=0;
delay5us();
}
void I2Cstop() //定義 停止信號函數
{
SCL=0;
SDA=0;
SCL=1;
delay5us();
SDA=1;
delay5us();
}
bit ReadAck() //定義 主機讀從機應答信號函數
{
SCL=0;
SCL=1;
delay5us();
if(SDA)
{ //非應答
SCL=0; //拉低SCL(據波形圖)
return(1);
}
else
{
SCL=0;
return(0);
}
}
void SendAck(bit i) //定義 主機發送應答
{
SCL=0;
if(i)
SDA=1;
else
SDA=0;
SCL=1; //SCL拉高,讀取數據
delay5us(); //延時保持數據穩定
SCL=0; //SCL拉低占用總線繼續通信
SDA=1; //釋放sda ,否則主機會一直占用sda
}
void I2cSendByte(uchar DAT) //定義 寫入數據操作邏輯函數
{
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; //拉低時鐘總線,繼續通信
SDA=1; //釋放數據總線,允許其他設備傳遞數據
}
void At24c02write(uchar ADDR,DAT) //定義 寫入函數
{
I2Cstart(); //起始信號
I2cSendByte(At24c02ADDR+I2cWrite); //發送從機地址+寫信號
if(ReadAck())
AcKFlag=1; //主機讀應答信號:結果為無應答
else
AcKFlag=0; //主機讀應答信號:結果為有應答
I2cSendByte(ADDR); //調用寫入數據操作邏輯函數:發送想要寫入的內存地址
if(ReadAck())
AcKFlag=1;
else
AcKFlag=0;
I2cSendByte(DAT); //調用寫入數據操作邏輯函數:發送要寫入的數據
if(ReadAck())
AcKFlag=1;
else
AcKFlag=0;
I2Cstop(); //停止信號
}
uchar I2cReadByte() //讀取從機內存數據邏輯子函數
{
uchar i,DAT;
for(i=0;i<8;i++)
{
DAT<<=1;
SCL=0; //讀數據時SDA由從機控制,主機只要控制scl時序,接收sda上的數據即可
SCL=1;
if(SDA)
DAT|=0x01;
delay5us();
}
return(DAT);
}
uchar At24c02Read(uchar ADDR) //定義 讀出函數
{
uchar DAT;
I2Cstart(); //起始信號
I2cSendByte(At24c02ADDR+I2cWrite); //發送從機(EEPROM)地址+寫信號(此處發寫信號是為了發送想要讀取的內存單元的地址)
if(ReadAck())
AcKFlag=1; //主機讀應答信號:結果為無應答
else
AcKFlag=0; //主機讀應答信號:結果為有應答
I2cSendByte(ADDR); //發送想要讀的內存地址
ReadAck(); //主機讀應答信號(不管是否應答)
I2Cstart(); //重復起始信號
I2cSendByte(At24c02ADDR+I2cRead); //發送從機地址+讀信號
if(ReadAck()) //判斷應答信號
AcKFlag=1;
else
AcKFlag=0;
DAT=I2cReadByte(); //調用 讀取從機內存數據邏輯子函數 讀一個字節
SendAck(1); //主機發送應答信號:非應答(非應答函數內包括,占用總線繼續通信與釋放數據總線允許其他設備調用的信號,故調用的子函數內部不必寫
I2Cstop(); //發送停止信號
return(DAT); //返回函數值
}
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(); //延時一會,待從機將先前接收的數據處理完畢,否則可能會讀取失敗
display(At24c02Read(0x02));
while(1);
}
|