【51單片機(jī)系列】EEPROM-IIC模塊
本文是關(guān)于IIC(I2C)通信協(xié)議的相關(guān)內(nèi)容。
一、 I2C介紹
I2C,Inter-Integrated Circuit總線是由PHILIPS公司開發(fā)的兩線式串行總線,用于連接微控制器及其外圍設(shè)備,是微電子通信控制領(lǐng)域廣泛采用的一種總線標(biāo)準(zhǔn)。
I2C是同步通信的一種特殊形式,具有接口線少,控制方式簡單,器件封裝形式小,通信速率較高等優(yōu)點(diǎn)。
I2C總線只有兩根雙向信號線,一根是數(shù)據(jù)線SDA,一根是時鐘線SCL。
由于I2C管腳少,硬件實(shí)現(xiàn)簡單,可擴(kuò)展性強(qiáng)等特點(diǎn),因此被廣泛使用在各大集成芯片內(nèi)。
1.1、I2C總線常用術(shù)語
主機(jī):啟動數(shù)據(jù)傳送并產(chǎn)生時鐘信號的設(shè)備。
從機(jī):被主機(jī)尋址的器件。
多主機(jī):同時有多于一個主機(jī)嘗試控制總線但不破壞傳輸;
主模式:用I2CNDAT支持自動字節(jié)計(jì)數(shù)的模式;位I2CRM,I2CSTT,I2CSTP控制數(shù)據(jù)的接收和發(fā)送。
從模式:發(fā)送和接收操作都是由I2C模塊自動控制的。
仲裁:是一個在有多個主機(jī)同時嘗試控制總線但只允許其中一個控制總線并使傳輸不被破壞的過程。
同步:兩個或多個器件同步時鐘信號的過程。
發(fā)送器:發(fā)送數(shù)據(jù)到總線的器件。
接收器:從總線接收數(shù)據(jù)的器件。
1.2、I2C物理層
I2C通信設(shè)備常用的連接方式如下所示:

I2C的物理層有如下特點(diǎn):
① 它是一個支持多設(shè)備的總線。總線指多個設(shè)備共用的信號線。在一個I2C通信總線中,可以連接多個I2C通信設(shè)備,支持多個通信主機(jī)及多個通信從機(jī)。
② 一個I2C總線只使用兩條總線線路,一條雙向串行數(shù)據(jù)線SDA,一條串行時鐘線SCL。數(shù)據(jù)線即用來表示數(shù)據(jù),時鐘線用于數(shù)據(jù)收發(fā)同步。
③ 每個連接到總線的設(shè)備都有一個獨(dú)立的地址,主機(jī)可以利用這個地址進(jìn)行不同設(shè)備之間的訪問。
④ 總線通過上拉電阻連接到電源。當(dāng)I2C設(shè)備空閑時,會輸出高阻態(tài);當(dāng)所有設(shè)備都空閑時,都輸出高阻態(tài),由上拉電阻把總線拉成高電平。
⑤ 多個主機(jī)同時使用總線時,為了防止數(shù)據(jù)沖突,會利用仲裁方式?jīng)Q定哪個設(shè)備占用總線。
⑥ 具有三種傳輸模式:標(biāo)準(zhǔn)模式傳輸速率為100kbit/s、快速模式傳輸速率為400kbit/s、高速模式傳輸速率為3.4Mbit/s,但目前大多I2C設(shè)備上不支持高速模式。
⑦ 連接到相同總線的IC數(shù)量受到總線的最大電容400pF限制。
1.3、I2C協(xié)議層
I2C的協(xié)議定義了通信的起始和停止信號、數(shù)據(jù)有效性、響應(yīng)、仲裁、時鐘同步和地址廣播等環(huán)節(jié)。
(1) 數(shù)據(jù)有效性規(guī)定
I2C總線進(jìn)行數(shù)據(jù)傳送時,時鐘信號為高電平期間,數(shù)據(jù)線上的數(shù)據(jù)必須保持穩(wěn)定,只有在時鐘線上的信號為低電平期間,數(shù)據(jù)線上的高電平或低電平狀態(tài)才允許變化。每次數(shù)據(jù)傳輸都以字節(jié)為單位,每次傳輸?shù)淖止?jié)數(shù)不受限制。如下圖所示:

(2) 起始和停止信號
時鐘線SCL為高電平期間,數(shù)據(jù)線SDA由高電平向低電平變化表示起始信號。
時鐘線SCL為高電平期間,數(shù)據(jù)線SDA由低電平向高電平變化表示終止信號。
如下圖:

起始和終止信號都是由主機(jī)發(fā)出的。
在起始信號產(chǎn)生后,總線處于被占用的狀態(tài)。
在終止信號產(chǎn)生后,總線處于空閑狀態(tài)。
(3) 應(yīng)答響應(yīng)
當(dāng)發(fā)送器件傳輸完一個字節(jié)的數(shù)據(jù)后,后面必須緊跟一個校驗(yàn)位。這個校驗(yàn)位是接收端通過控制數(shù)據(jù)線SDA來實(shí)現(xiàn)的,以提醒發(fā)送端“數(shù)據(jù)已經(jīng)接收完成,數(shù)據(jù)傳送可以繼續(xù)進(jìn)行”。
這個校驗(yàn)位是數(shù)據(jù)或地址傳輸過程中的響應(yīng)。響應(yīng)包括應(yīng)答ACK和非應(yīng)答NACK兩種信號。
作為數(shù)據(jù)接收端時,當(dāng)設(shè)備接收到I2C傳輸?shù)囊粋€字節(jié)數(shù)據(jù)或地址后,若希望對方繼續(xù)發(fā)送數(shù)據(jù),則需要向?qū)Ψ桨l(fā)送應(yīng)答ACK信號,即特定的低電平脈沖,發(fā)送方接收到該信號會繼續(xù)發(fā)送下一個數(shù)據(jù)。若接收端希望結(jié)束數(shù)據(jù)傳輸,則向?qū)Ψ桨l(fā)送非應(yīng)答ACK信號,即特定的高電平脈沖,發(fā)送方接收到該信號后會產(chǎn)生一個停止信號,結(jié)束信號傳輸。
應(yīng)答響應(yīng)時序圖如下:

每一個字節(jié)必須保證是8位長度。數(shù)據(jù)傳送時,先傳送最高位MSB,每一個被傳送的字節(jié)后面都必須跟隨一位應(yīng)答位,即一幀共有9位。
由于某種原因從機(jī)不對主機(jī)尋址信號應(yīng)答時,如從機(jī)正在進(jìn)行實(shí)時性的處理工作而無法接收總線上的數(shù)據(jù)時,它必須將數(shù)據(jù)線SDA置為高電平,由主機(jī)產(chǎn)生一個終止信號來結(jié)束總線的數(shù)據(jù)傳送。
如果從機(jī)對主機(jī)進(jìn)行了應(yīng)答,但在數(shù)據(jù)傳送一段時間后無法繼續(xù)接收更多的數(shù)據(jù)時,從機(jī)可以通過對無法接收的第一個數(shù)據(jù)字節(jié)的非應(yīng)答通知主機(jī),主機(jī)則應(yīng)發(fā)出終止信號以結(jié)束數(shù)據(jù)的繼續(xù)傳送。
當(dāng)主機(jī)接收數(shù)據(jù)時,它收到最后一個數(shù)據(jù)字節(jié)后,必須向從機(jī)發(fā)出一個結(jié)束傳送的信號。這個信號是由對從機(jī)的非應(yīng)答來實(shí)現(xiàn)的。然后從機(jī)釋放SDA線以允許主機(jī)產(chǎn)生終止信號。
這些信號中,起始信號是必需的,終止信號和應(yīng)答信號都可以省略。
(4) 總線的尋址方式
I2C總線尋址按照從機(jī)地址位數(shù)可分為兩種,一種是7位,另一種是10位。
采用7位的尋址字節(jié)(尋址字節(jié)是起始信號后的第一個字節(jié))的位定義如下:

D7 - D1位組成從機(jī)的地址。D0位是數(shù)據(jù)傳送方向位,D0=0表示主機(jī)向從機(jī)寫數(shù)據(jù),D0=1表示主機(jī)由從機(jī)讀數(shù)據(jù)
10位尋址和7為尋址兼容,且可以結(jié)合使用。10位尋址不會影響已有的7位尋址,有7位和10位地址的器件可以連接到相同的I2C總線。
以7位尋址為例,當(dāng)主機(jī)發(fā)送了一個地址后,總線上的每個器件都將頭7位與它自己的地址比較,如果一樣,器件會判定它被主機(jī)尋址,其它地址不同的器件將被忽略后面的數(shù)據(jù)信號。
R/W決定從機(jī)是接收端還是發(fā)送端。
從機(jī)的地址由固定部分和可編程部分組成。在一個系統(tǒng)中可能希望接入多個相同的從機(jī),從機(jī)地址中可編程部分決定了可接入總線該類器件的最大數(shù)目。比如一個從機(jī)的7位尋址位有4位是固定位,3位是可編程位,這時僅能尋址8個同樣的器件,即可以有8個同樣的器件介入到該I2C總線系統(tǒng)中。
(5) 數(shù)據(jù)傳輸
I2C總線上傳送的數(shù)據(jù)信號是廣義的,既包括地址信號,又包括真正的數(shù)據(jù)信號。
在起始信號后必須傳送一個從機(jī)的地址(7位),第8位是數(shù)據(jù)的傳送方向(R/W),0表示主機(jī)發(fā)送(寫)數(shù)據(jù),1表示主機(jī)接收數(shù)據(jù)(讀)。
每次數(shù)據(jù)傳送由主機(jī)產(chǎn)生的終止信號結(jié)束。但是,如果主機(jī)希望繼續(xù)占用總線進(jìn)行新的數(shù)據(jù)傳送,可以不產(chǎn)生終止信號,馬上再次發(fā)出起始信號對另一從機(jī)進(jìn)行尋址。
在總線的一次數(shù)據(jù)傳送過程中,可以有以下幾種組合方式:
a. 主機(jī)向從機(jī)發(fā)送數(shù)據(jù),數(shù)據(jù)傳送方向在整個傳送過程中不變。

陰影部分表示數(shù)據(jù)由主機(jī)向從機(jī)發(fā)送,無陰影部分表示數(shù)據(jù)由從機(jī)向主機(jī)傳送。A表示應(yīng)答,非A表示非應(yīng)答(高電平),S表示起始信號,P表示終止信號。
b. 主機(jī)在第一個字節(jié)后,立即從從機(jī)讀數(shù)據(jù)。

c. 在傳送過程中,當(dāng)需要改變傳送方向時,起始信號和從機(jī)地址都要重復(fù)產(chǎn)生一次,但兩次讀/寫方向位正好相反。

以上就是I2C總線。51單片機(jī)沒有硬件IIC接口,即使有接口通常也是采用軟件模擬I2C。主要原因是硬件IIC設(shè)計(jì)的比較復(fù)雜,而且穩(wěn)定性不怎么號好,程序移植比較麻煩,用軟件模擬IIC最大的好處是移植方便。
二、 AT24C02芯片介紹
AT24C01/02/04/08/16是一個1K/2K/4K/8K/16K的串行CMOS,內(nèi)部含有128/256/512/1024/2048個8位字節(jié),AT24C02有一個8字節(jié)頁緩沖器,AT24C02/04/08/16有一個16字節(jié)頁緩沖器。
該器件通過I2C總線接口進(jìn)行操作,有一個專門的寫保護(hù)功能。
以AT24C02芯片為例,該芯片具有I2C通信接口,芯片內(nèi)保存的數(shù)據(jù)在掉電情況下都不丟失,芯片管腳及外觀如下圖:

芯片管腳說明:
| 管腳號 | 管腳名稱 | 功能說明 |
|---|---|---|
| 1/2/3 | A0/A1/A2 | 地址輸入,A2、A1和A0是器件地址輸入引腳。 24C02/32/64使用A2、A1、A0輸入引腳作為硬件地址,總線上課同時級聯(lián)8個24C02/32/63器件。 24C04使用A2和A1輸入引腳作為硬件地址,總線上可同時級聯(lián)4個24C04器件,A0位空腳,可接地。 24C08使用A2輸入引腳作為硬件地址,總線上可同時級聯(lián)2個24C08器件,A0和A1為空腳,可接地。 24C16未使用器件地址引腳,總線上最多只可連接一個16K器件,A2、A1和A0為空腳,可接地。 |
| 5 | SDA | 串行地址和數(shù)據(jù)輸入/輸出,SDA是雙向串行數(shù)據(jù)傳輸引腳,漏極開路,需外接上拉電阻到VCC,典型值10kΩ。 |
| 6 | SCL | 串行時鐘輸入,SCL同步數(shù)據(jù)傳輸,上升沿?cái)?shù)據(jù)寫入,下降沿?cái)?shù)據(jù)讀出。 |
| 7 | WP | 寫保護(hù),WP引腳提供硬件數(shù)據(jù)保護(hù)。當(dāng)WP接地時,允許數(shù)據(jù)正常讀寫操作;當(dāng)WP接VCC時,寫保護(hù),只讀。 |
| 4 | GND | 地 |
| 8 | VCC | 正電源 |
AT24C02器件地址為7位,高4位固定是1010,低3位由A0/A1/A2信號線的電平?jīng)Q定。因?yàn)閭鬏數(shù)刂坊驍?shù)據(jù)是以字節(jié)為單位傳送的,當(dāng)傳送地址時,器件地址占7位,還有最后一位(最低位R/W)用來選擇讀寫方向,它與地址無關(guān),格式如下:

如果將A0/A1/A2連接到GND,那么器件地址為1010000,。如果要對芯片進(jìn)行寫操作時,R/W=0,寫器件地址即為0xA0;如果要對芯片進(jìn)行讀操作時,R/W=1,讀器件地址為0xA1。
如果將WP連接到GND,此時芯片允許數(shù)據(jù)正常讀寫。
I2C總線時序如下圖所示:


三、 I2C使用示例
本示例實(shí)現(xiàn)的功能:系統(tǒng)運(yùn)行時,數(shù)碼管后4為顯示0,按K1將數(shù)據(jù)寫入到EEPROM內(nèi)保存,按K2讀取EEPROM內(nèi)保存的數(shù)據(jù),按K3顯示數(shù)據(jù)加1,按K4顯示數(shù)據(jù)清零,最大能寫入的數(shù)據(jù)是255。
proteus中仿真使用到的資源有:四個獨(dú)立按鍵、動態(tài)數(shù)碼管、EEPROM模塊電路。連接如下圖所示,其中EEPROM模塊A2/A1/A0連接低,表示當(dāng)前EEPROM的地址為1010000;WP接地關(guān)閉寫保護(hù),可以正常讀/寫數(shù)據(jù);SCL和SDA分別連接單片機(jī)的P2.1和P2.0口。

軟件設(shè)計(jì),首先編寫I2C通信相關(guān)代碼,如下:
i2c.h內(nèi)容如下:
#ifndef __I2C_H_
#define __I2C_H_
#include "typedef.h"
/*************************************************************************
* 函數(shù)名: I2CStart
* 函數(shù)功能: I2C起始信號,SCL高電平期間,SDA產(chǎn)生一個下降沿。
* 起始信號后SDA和SCL都為0
* 輸入: void
* 輸出: void
**************************************************************************/
void I2CStart();
/*************************************************************************
* 函數(shù)名: I2CStop
* 函數(shù)功能: I2C終止信號,SCL高電平期間,SDA產(chǎn)生一個上升沿。
* 終止信號后SCL和SDA都為1,表示總線空閑
* 輸入: void
* 輸出: void
**************************************************************************/
void I2CStop();
/*************************************************************************
* 函數(shù)名: I2CSendByte
* 函數(shù)功能: I2C發(fā)送一個字節(jié)。在SCL高電平期間,保持SDA穩(wěn)定
* 發(fā)送完一個字節(jié)后SCL=0,SDA=1
* 輸入: void
* 輸出: 0或1,0表示發(fā)送失敗,1表示發(fā)送成功
**************************************************************************/
u8 I2CSendByte(u8 dat);
/*************************************************************************
* 函數(shù)名: I2CReadByte
* 函數(shù)功能: I2C讀取一個字節(jié)。接收完一個字節(jié)后SCL=0,SDA=1
* 輸入: void
* 輸出: dat,讀取的數(shù)據(jù)
**************************************************************************/
u8 I2CReadByte();
/*************************************************************************
* 函數(shù)名: AT24C02Write
* 函數(shù)功能: 往AT24C02中的一個地址寫一個數(shù)據(jù)
* 輸入: addr:寫入的地址
* dat:寫入的數(shù)據(jù)
* 輸出: void
**************************************************************************/
void AT24C02Write(u8 addr, u8 dat);
/*************************************************************************
* 函數(shù)名: AT24C02Read
* 函數(shù)功能: 讀取AT24C02中的一個地址的一個數(shù)據(jù)
* 輸入: addr:讀取的地址
* 輸出: dat:寫入的數(shù)據(jù)
**************************************************************************/
u8 AT24C02Read(u8 addr);
#endif
i2c.c內(nèi)容如下:
#include "reg52.h"
#include "Delay.h"
#include "i2c.h"
sbit SCL = P2^1;
sbit SDA = P2^0;
/*************************************************************************
* 函數(shù)名: I2CStart
* 函數(shù)功能: I2C起始信號,SCL高電平期間,SDA產(chǎn)生一個下降沿。
* 起始信號后SDA和SCL都為0
* 輸入: void
* 輸出: void
**************************************************************************/
void I2CStart()
{
SDA=1; // SDA初始狀態(tài)為高電平
delay10us(); // 延時10us
SCL=1; // 設(shè)置SCL為高電平
delay10us(); // 延時10us,起始信號建立保持時間>4.7us
SDA=0; // SDA產(chǎn)生一個下降沿
delay10us(); // 起始信號保持時間>4us
SCL=0; // 起始信號后置SCL為0
delay10us(); // SCL低電平周期>4.7us
}
/*************************************************************************
* 函數(shù)名: I2CStop
* 函數(shù)功能: I2C終止信號,SCL高電平期間,SDA產(chǎn)生一個上升沿。
* 終止信號后SCL和SDA都為1,表示總線空閑
* 輸入: void
* 輸出: void
**************************************************************************/
void I2CStop()
{
SDA=0;
delay10us();
SCL=1;
delay10us(); // 停止信號建立時間>4us
SDA=1;
delay10us(); // 新的發(fā)送開始前總線空閑時間>4.7us
}
/*************************************************************************
* 函數(shù)名: I2CSendByte
* 函數(shù)功能: I2C發(fā)送一個字節(jié)。在SCL高電平期間,保持SDA穩(wěn)定
* 發(fā)送完一個字節(jié)后SCL=0,SDA=1
* 輸入: void
* 輸出: 0或1,0表示發(fā)送失敗,1表示發(fā)送成功
**************************************************************************/
u8 I2CSendByte(u8 dat)
{
u8 a=0, b=0; //
// 發(fā)送8位,從最高位開始
for(a=0;a<8;a++)
{
SDA=dat>>7; // 起始信號之后SCL為0,可以直接改變SDA
dat=dat<<1;
delay10us();
SCL=1; // SCL置1
delay10us(); // 數(shù)據(jù)建立時間>4.7us
SCL=0;
delay10us();
}
// 一個字節(jié)的數(shù)據(jù)發(fā)送結(jié)束
SDA=1;
delay10us();
SCL=1;
while(SDA) // 等待應(yīng)答,等待從設(shè)備把SDA拉低
{
b++;
if(b>200) // 如果超過2000us沒有應(yīng)答發(fā)送失敗,或者為非應(yīng)答表示接收結(jié)束
{
SCL=0;
delay10us();
return 0;
}
}
SCL=0;
delay10us();
return 1;
}
/*************************************************************************
* 函數(shù)名: I2CReadByte
* 函數(shù)功能: I2C讀取一個字節(jié)。接收完一個字節(jié)后SCL=0,SDA=1
* 輸入: void
* 輸出: dat,讀取的數(shù)據(jù)
**************************************************************************/
u8 I2CReadByte()
{
u8 a=0, dat=0;
SDA=1; // 起始和發(fā)送一個字節(jié)后SCL都是0
delay10us();
for(a=0;a<8;a++)
{
SCL=1;
delay10us();
dat<<=1;
dat|=SDA;
delay10us();
SCL=0;
delay10us();
}
return dat;
}
/*************************************************************************
* 函數(shù)名: AT24C02Write
* 函數(shù)功能: 往AT24C02中的一個地址寫一個數(shù)據(jù)
* 輸入: addr:寫入的地址
* dat:寫入的數(shù)據(jù)
* 輸出: void
**************************************************************************/
void AT24C02Write(u8 addr, u8 dat)
{
I2CStart(); // 起始信號
I2CSendByte(0xa0); // 發(fā)送器件地址
I2CSendByte(addr); // 發(fā)送寫入的內(nèi)存地址
I2CSendByte(dat); // 發(fā)送寫入的數(shù)據(jù)
I2CStop(); // 終止信號
}
/*************************************************************************
* 函數(shù)名: AT24C02Read
* 函數(shù)功能: 讀取AT24C02中的一個地址的一個數(shù)據(jù)
* 輸入: addr:讀取的地址
* 輸出: dat:寫入的數(shù)據(jù)
**************************************************************************/
u8 AT24C02Read(u8 addr)
{
u8 dat;
I2CStart(); // 發(fā)送起始信號
I2CSendByte(0xa0); // 發(fā)送寫器件地址
I2CSendByte(addr); // 發(fā)送寫入的內(nèi)存地址
I2CStart(); // 改變方向,發(fā)送起始信號
I2CSendByte(0xa1); // 發(fā)送讀器件地址
dat=I2CReadByte(); // 讀取數(shù)據(jù)
I2CStop(); // 終止信號
return dat;
}
主函數(shù)如下:
/*
實(shí)現(xiàn)功能:獨(dú)立按鍵控制EEPROM讀寫并將數(shù)據(jù)顯示到數(shù)碼管中
具體實(shí)現(xiàn):有四個獨(dú)立按鍵,
按K1將數(shù)據(jù)寫入到EEPROM內(nèi)保存,
按K2讀取EEPROM內(nèi)保存的數(shù)據(jù),
按K3顯示數(shù)據(jù)加1,
按K4顯示數(shù)據(jù)清零,最大能寫入的數(shù)據(jù)是255
[2023-12-22] zoya
*/
#include "reg52.h"
#include "typedef.h"
#include "Delay.h"
#include "i2c.h"
#define GPIO_DISPLAY P0
sbit LSA=P1^0;
sbit LSB=P1^1;
sbit LSC=P1^2;
sbit K1=P3^0;
sbit K2=P3^1;
sbit K3=P3^2;
sbit K4=P3^3;
// 共陰極數(shù)碼管的碼表,0-9
u8 code smg[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6F, };
static u8 addr=0x01;
u8 dat;
u8 display[4]; // 數(shù)碼管顯示字符
// 按鍵處理函數(shù)
void KeyPros()
{
// K1寫入EEPROM
if(0==K1)
{
delayms(10); // 延時消抖
if(0==K1)
{
AT24C02Write(addr,dat); // 在EEPROM的0x01地址寫入數(shù)據(jù)dat
}
while(!K1);
}
// K2讀取EEPROM
if(0==K2)
{
delayms(10);
if(0==K2)
{
dat=AT24C02Read(addr);
}
while(!K2);
}
// K3加1
if(0==K3)
{
delayms(10);
if(0==K3)
{
dat++;
if(dat>255)
dat=0;
}
while(!K3);
}
// K4清零
if(0==K4)
{
delayms(10);
if(0==K4)
{
dat=0;
}
while(!K4);
}
}
// 數(shù)碼管顯示函數(shù)
void DigDisplay()
{
LSA=0; LSB=0; LSC=0; GPIO_DISPLAY = smg[dat/1000];
delayms(1);
LSA=1; LSB=0; LSC=0; GPIO_DISPLAY = smg[dat%1000/100];
delayms(1);
LSA=0; LSB=1; LSC=0; GPIO_DISPLAY = smg[dat%1000%100/10];
delayms(1);
LSA=1; LSB=1; LSC=0; GPIO_DISPLAY = smg[dat%1000%100%10];
delayms(1);
}
void main()
{
GPIO_DISPLAY = 0x00;
while(1)
{
KeyPros();
DigDisplay();
}
}
仿真結(jié)果:

四、擴(kuò)展實(shí)驗(yàn):通過AT24C02芯片對功能程序進(jìn)行加密
擴(kuò)展實(shí)驗(yàn)實(shí)現(xiàn)的功能:通過讀取AT24C02芯片內(nèi)0x02地址的數(shù)據(jù),判斷是否執(zhí)行按鍵對應(yīng)的操作。如果數(shù)據(jù)為0不執(zhí)行,否則執(zhí)行操作。前提是AT24C02中已經(jīng)有了數(shù)據(jù)。
在上面程序的基礎(chǔ)上添加一個全局變量u8 readdat,表示從地址0x02中讀出的數(shù)據(jù)。在主函數(shù)進(jìn)入循環(huán)之前添加一行readdat = AT24C02Read(0x02);從0x02地址中讀出數(shù)據(jù)。在按鍵處理函數(shù)中添加if(0==readdat) return;,當(dāng)0x02地址讀出的數(shù)據(jù)是0時不執(zhí)行按鍵處理函數(shù)。
實(shí)現(xiàn)結(jié)果:
當(dāng)0x02地址讀出是0時

當(dāng)0x02地址讀出不是0時
