標(biāo)題:
單片機(jī)+AT24C02為啥讀寫錯(cuò)誤?
[打印本頁]
作者:
宏達(dá)工控
時(shí)間:
2023-8-1 12:59
標(biāo)題:
單片機(jī)+AT24C02為啥讀寫錯(cuò)誤?
代碼:
/****************************************************************
AT24C前四位固定為1010 A1-A2由管腳電平默認(rèn)接地,最后一位表示讀寫操作所以AT24C讀地址0xa1 寫地址0xa0
寫AT24C02的時(shí)候從器件地址為10100 0000,(0xa0),讀AT24C02的時(shí)候從器件地址為10100 0001,(0xa1)
***************************************************************/
#include<reg51.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define AT24C02_ADDRESS 0xA0 //0xA0 1010 00000寫地址
uint Count;
uint Set_Count;
// unsigned int Count;
// unsigned int Set_Count;
uint Num_L;
uint Num_H;
uint num1;
uint num2;
char yiwei_Count;//移位計(jì)數(shù)
sbit I2C_SCL= P1^6;
sbit I2C_SDA= P1^7;
sbit Start_Dianji=P3^0; //電機(jī)啟動(dòng)_dianji
sbit forward=P3^1; //正轉(zhuǎn)檢測(cè)
//sbit back=P3^1; //反轉(zhuǎn)檢測(cè)
sbit run=P3^7; //運(yùn)行信號(hào)
sbit jia_up=P1^0;// 增加鍵
sbit jian_down=P1^1;//減少鍵
sbit yiwei_up=P1^2; //移位鍵
sbit qingling=P1^3; //清零鍵
uchar code ledcode[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //共陰數(shù)碼管編碼0-9
uchar data Ledbuff[8]={1};//顯示緩沖區(qū)
#define I2CDelay_us(){_nop_();_nop_();_nop_();_nop_();}//voidI2CDelay_us
/***********************
AT24C初始化
*************************/
void I2C_init()
{
I2C_SCL=1;
// I2CDelay_us(4);
I2C_SDA=1;//首先確保SCL SDA都是高電平
// I2CDelay_us(4);
}
/***********************
產(chǎn)生總線起始信號(hào)
*************************/
void I2C_Start(void )
{
I2C_SDA=1;//首先確保SCL SDA都是高電平
// I2CDelay_us(5);
I2C_SCL=1; //確保SCL高電平
// I2CDelay_us(5);
I2C_SDA=0;//先在SCL為高時(shí)拉低SDA,即為起始信號(hào)
// I2CDelay_us(5);
I2C_SCL=0; //在拉低 SCL,鉗住I2C總線準(zhǔn)備發(fā)送或接收數(shù)據(jù)
}
/***********************
產(chǎn)生總線停止信號(hào):先拉低SDA在拉低SCL
*************************/
void I2C_Stop(void )
{
I2C_SDA=0;//首先確保SCL SDA都是低電平
I2C_SCL=1; //先拉高 SCL
I2C_SDA=1;//在拉高 SDA
/*
I2C_SCL=0;
I2C_SDA=0;
// I2CDelay_us(4);
I2C_SCL=1;
I2C_SDA=1;
// I2CDelay_us(4);
*/
}
/*******************************************************************************
*@brief I2C發(fā)送一個(gè)字節(jié)數(shù)據(jù)
*@param Byte要發(fā)送的字節(jié)
*@retval 無
起始信號(hào)后必須送一個(gè)從機(jī)地址(7)位,1-7位為要接收器件的地址,第八位讀寫位0發(fā)送1接收,第9位ACK應(yīng)答位,
緊接著為第一個(gè)數(shù)據(jù)字節(jié),然后一位應(yīng)答位ACK后面繼續(xù)第二個(gè)數(shù)據(jù)字節(jié)
**********************************************************************************/
void I2C_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++)
{
I2C_SDA=Byte&(0x80>>i);
I2C_SCL=1; //先拉高 SCL
I2C_SCL=0; //SCL
}
}
/***********************************************************************************************
*@brief I2C讀取 接收一個(gè)字節(jié)
*@param 無
*@retval 讀取 接收到的一個(gè)字節(jié)數(shù)據(jù)
********************************************************************************************/
unsigned char I2C_ReceiveByte(void)
{
unsigned char i,Byte=0x00;//
I2C_SDA=1; //
for(i=0;i<8;i++)
{
I2C_SCL=1; //先拉高 SCL
if(I2C_SDA){Byte |= (0x80>>i); }
I2C_SCL=0; //SCL
}
return Byte;
}
/*********************
*@brief I2C發(fā)送應(yīng)答Ack
*@param AckBit應(yīng)答位 0為應(yīng)答(成功) 1為非應(yīng)答(失敗)
*@retval 無
************************/
void I2C_SendAck(unsigned char AckBit)
{
I2C_SDA=AckBit;
I2C_SCL=1; //先拉高 SCL
I2C_SCL=0; //SCL
}
/*********************
*@brief I2C接收應(yīng)答位
*@param 無
*@retval AckBit應(yīng)答位 0為應(yīng)答(成功) 1為非應(yīng)答(失�。�
************************/
unsigned char I2C_ReceiveAck(void)
{
unsigned char AckBit;
I2C_SDA=1;
I2C_SCL=1; //先拉高 SCL
AckBit=I2C_SDA;
I2C_SCL=0; //SCL
return AckBit; //返回值
}
/**********向AT24C寫數(shù)據(jù)***********
*@brief AT24C寫入一個(gè)字節(jié)
*@param WordAddress要寫入字節(jié)的地址
*@param Data要寫入的數(shù)據(jù)
*@retval無
寫多字節(jié)時(shí),寫入一個(gè)字節(jié)。在寫一個(gè)字節(jié)前,必須延時(shí)5ms
************************/
void AT24C_WriteByte(unsigned char WordAddress,Data)
{
I2C_Start();//啟動(dòng)總線
I2C_SendByte(AT24C02_ADDRESS);//發(fā)送寫操作地址+寫數(shù)據(jù)(0xa0)
I2C_ReceiveAck(); //等待應(yīng)答
I2C_SendByte(WordAddress);//要寫入的地址
I2C_ReceiveAck(); //等待應(yīng)答完成
I2C_SendByte(Data); //要寫入的數(shù)據(jù),第一字節(jié) ,第二字節(jié)注意:每個(gè)字節(jié)都回應(yīng)一個(gè)應(yīng)答位0,如果沒有回應(yīng)說明寫入不成功
I2C_ReceiveAck(); //等待完成 注意:每個(gè)字節(jié)都回應(yīng)一個(gè)應(yīng)答位0,如果沒有回應(yīng)說明寫入不成功
I2C_Stop(); //發(fā)送結(jié)束信號(hào):停止總線
}
/************從AT24C中讀出數(shù)據(jù)*********
*@brief AT24C讀取一個(gè)字節(jié)
*@param WordAddress要讀出字節(jié)的地址
*@param 無
*@retval要讀出的數(shù)據(jù)
************************/
unsigned char AT24C_ReadByte(unsigned char WordAddress) //void
{
unsigned char Data;
I2C_Start(); //發(fā)送起始信號(hào):啟動(dòng)總線
I2C_SendByte(AT24C02_ADDRESS); //接上首字節(jié),發(fā)送器件寫操作地址+寫數(shù)據(jù)(0xa0)這里寫操作時(shí)維綸把所要讀的數(shù)據(jù)地址AT24C02_ADDRESS通知讀取哪個(gè)地址信息
I2C_ReceiveAck(); //等待完成應(yīng)答
I2C_SendByte(WordAddress);//發(fā)送要讀取內(nèi)存的地址(WORD ADDRESS)
I2C_ReceiveAck(); //等待應(yīng)答完成
I2C_Start();//在次啟動(dòng)總線
I2C_SendByte(AT24C02_ADDRESS| 0x01); //對(duì)E2PROM進(jìn)行讀操作(0XA1)E2PROM會(huì)自動(dòng)向主機(jī)發(fā)回?cái)?shù)據(jù),讀取一個(gè)字節(jié)后回應(yīng)一個(gè)應(yīng)答位,后會(huì)繼續(xù)傳送下一個(gè)地址的數(shù)據(jù)0xa1
I2C_ReceiveAck(); //等待完成
Data= I2C_ReceiveByte(); //要讀出的數(shù)據(jù)到Data
I2C_SendAck(1); //等待完成::如果不想讀了,就發(fā)送一個(gè)非應(yīng)答位NAK(1),發(fā)送結(jié)束,停止總線
I2C_Stop(); //停止總線
return Data ;//返回值
}
/***********************************/
void delayms(uint ms)
{
uchar k;
while(ms--)
{
for(k = 0; k < 120; k++);
}
}
void display() //顯示程序display(uchar a,b,c,d,e) char i;
{
static unsigned char i = 0;
switch(i)//使用多分支選擇語句 i=count display 0x代表16進(jìn)制
{
case(0):Ledbuff[7]=Set_Count/1000;break; //取設(shè)定千位字符送緩存
case(1):Ledbuff[6]=Set_Count/100%10;break; //取設(shè)定百位字符送緩沖
case(2):Ledbuff[5]=Set_Count/10%10;break; //取設(shè)定十位字符送緩沖
case(3):Ledbuff[4]=Set_Count%10;break; //取設(shè)定個(gè)位字符送緩存
case(4):Ledbuff[3]=Count/1000;break; //取計(jì)數(shù)千位字符送緩存
case(5):Ledbuff[2]=Count/100%10;break;
case(6):Ledbuff[1]=Count/10%10;break;
case(7):Ledbuff[0]=Count%10;break;
}
P0=0x00; //消陰:段碼全部低電平關(guān)閉
P2=~(0x01<<i); //P2位選,左移i位取反
P0=ledcode[Ledbuff[i]]; //P0字符刷新顯示
delayms(1); //顯示2MS
i=++i%8; //自加1
}
/*
void Adjust(void) //按鍵設(shè)定匝數(shù),用P2.4個(gè)位-P2.7(千位)前四位數(shù)碼管顯示
{
if(yiwei_up==0) //移位按鍵按下
{
while(!yiwei_up); //等待移位按鍵松開
if(yiwei_Count<3) //移位
{
yiwei_Count +=1;
}
else //如果>3
{
yiwei_Count=0; //設(shè)定位在個(gè)位
}
}
if(Set_Count>=0 && Set_Count<9999)//最大9999yiwei_Count=0; //設(shè)定加 jia_up==0
{
if (jia_up==0) //增加按鍵按下
{
while(!jia_up);//等待加按鍵松開
{
if (yiwei_Count==0) //
{
Set_Count += 1; //設(shè)定+1
}
if (yiwei_Count==1&&Set_Count<9990)
{
Set_Count += 10; //設(shè)定+1
}
if (yiwei_Count==2&&Set_Count<9900)
{
Set_Count += 100; //設(shè)定+1
}
if (yiwei_Count==3 && Set_Count<9000)
{
Set_Count += 1000; //設(shè)定+1
}
}
}
if (jian_down==0) //減少按鍵按下
{
while(!jian_down);//等待按鍵松開
{
if (yiwei_Count==0&&Set_Count>1) // 移位在個(gè)位
{
Set_Count -= 1; //設(shè)定+1
}
if (yiwei_Count==1&&Set_Count>9)
{
Set_Count -= 10; //設(shè)定+1
}
if (yiwei_Count==2 && Set_Count>99)
{
Set_Count -= 100; //設(shè)定+1
}
if (yiwei_Count==3 && Set_Count>999)
{
Set_Count -= 1000; //設(shè)定+1
}
}
//寫入數(shù)據(jù)
/* AT24C_WriteByte(0,Set_Count%256);
delayms(5) ; //顯示2MS
AT24C_WriteByte(1,Set_Count/256);
delayms(5); //顯示2MS
}
*/
/**********************************************************
主函數(shù)
**********************************************************/
void main()
{
I2C_init();
// init(); //初始化24C02
// num=5678; //num為小于等于65535的整數(shù)。 */
Set_Count=1234;
Num_H =Set_Count/256; //1234/256就簡(jiǎn)單了,高位:取的是整數(shù)倍,不被整除的部分自然就被剔除了1234/256=4
Num_L =Set_Count%256; //%256是取余,低位:也就是你把前面的數(shù)值除以256取余,商跟除數(shù)則是256的整數(shù)倍部分1234%256=210 ;4*256=1024 %256=1234-1024=210
AT24C_WriteByte(0,Num_L);
delayms(10); //顯示2MS
AT24C_WriteByte(1,Num_H );
delayms(10); //顯示2MS
num1=AT24C_ReadByte(0); //用地址0單元存儲(chǔ)num十六進(jìn)制表示時(shí)的低兩位
num2=AT24C_ReadByte(1); //用地址0單元存儲(chǔ)num十六進(jìn)制表示時(shí)的高兩位
Count=num2*256+num1;
//寫入24C02
// AT24C_WriteByte(0,Set_Count%256); //低8位寫入0x00
/*
AT24C_WriteByte(0,120); //低8位寫入0x00
delayms(5); //顯示2MS
// AT24C_WriteByte(1,Set_Count/256); //高8位寫入0x01
AT24C_WriteByte(1,0); //高8位寫入0x01
delayms(5); //顯示2MS
//讀取數(shù)據(jù) /*
Num_L = AT24C_ReadByte(0);
Num_H |=AT24C_ReadByte(1)<<8;
Count= Num_H+Num_L;
*/
while(1)
{
/* Adjust();
if (jia_up==0) //增加按鍵按下
{
while(!jia_up);//等待加按鍵松開
{
Set_Count += 1; //設(shè)定+1
}
}
if (jian_down==0) //減少按鍵按下
{
while(!jian_down);//等待按鍵松開
{
Set_Count -= 1; //設(shè)定+1
}
}
if(yiwei_up==0) //保存按鍵按下,向AT24C寫入數(shù)據(jù)
{
while(!yiwei_up); //等待移位按鍵松開
{
AT24C_WriteByte(0,Set_Count%256);
delayms(6) ; //顯示2MS
AT24C_WriteByte(1,Set_Count/256);
delayms(6); //顯示2MS
}
}
if( qingling==0) //讀取按鍵按下
{
while(! qingling); //等待移位按鍵松開
{
Count=AT24C_ReadByte(0);
Count |=AT24C_ReadByte(1)<<8;
// Count = Num_H+Num_L;
}
} */
display();
}
}
gongyang.rar
(2023-8-1 12:59 上傳)
19.96 KB, 下載次數(shù): 2
仿真文件
作者:
lkc8210
時(shí)間:
2023-8-1 14:37
作者:
joyb
時(shí)間:
2023-8-31 09:52
AT24C02程序沒問題
作者:
北方之鄙人
時(shí)間:
2023-9-3 15:22
你自己看看是不是符號(hào)IIC協(xié)議規(guī)范,用示波器看看電平的高低情況,有無過充超標(biāo),看看開始結(jié)束時(shí)序,讀寫時(shí)序?qū)Σ粚?duì)
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1