(5-1)、AT24C02掉电不丢失写入与读取
AT24C02就是将数据写入E2PROM,保证写入数据掉电不丢失。考频低,一般不考,顶天考几个数据E2PROM,上电立马读取。AT24C02数据读取一定放在主程序最前面,否则会出现一些问题。通信方式也是I2C,因此底层代码跟AD、DA基本一样。存在下面我们来讲一下写入与读取的时序。
写入时序:(如图 二十二)
①初始化(通信起始信号)
②发送I2C设备地址(高七位是设备地址,最后一位是读写位,写为0,读取为1,A2、A1、A0置0,开始写操作0xa0,如图 二十一)
③从机发送反馈应答(从机发送0表明接收成功)
④写入从机设备地址(一般为8的倍数,如0、8、16、24…)
⑤从机发送反馈应答
⑥逐个写入数据、从机发送反馈应答、延时200再写(while循环)
⑦停止信号
图 二十一 AT24C02设备地址
读取时序:(如图 二十三)
①初始化(通信起始信号)
②发送I2C设备地址(高七位是设备地址,最后一位是读写位,写为0,读取为1,A2、A1、A0置0,开始写操作0xa0,如图 二十一)
③从机发送反馈应答(从机发送0表明接收成功)
④写入从机设备地址(一般为8的倍数,如0、8、16、24…)
⑤从机发送反馈应答
⑥重新初始化
⑦发送开始读取信号0xa1
⑧从机发送反馈应答(从机发送0表明接收成功)
⑨开始读取数据(无需延时)、读取完成主机发送反馈1、还有数据发送0
⑩停止信号
图 二十二 AT24C02写入
图 二十三 AT24C02读取
(5-2)AT24C02写入与读取代码解读
如图 二十四,我们按照写入的时序一步步分析,*String表示指针,传入数组名,就可以需要写入的 数据全部写入,Number就是数组里面有几个数据。
首先发送开始信号,再发送从机地址并反馈(0xA0)
再选择需要写入的寄存器地址(8的倍数),从该位置开始写,写入一次后地址会自增,数据自动放在下一位地址。
此时开始写入数据,每次写入后需要延时200,循环Number次后,数组数据全部写完,停止。
图 二十四 AT24C02写入数据代码
如图 二十五,我们按照读取的时序一步步分析,*String表示指针,传入数组名,就可以将指定地址Address开始的数据全部读取,Number就是读取数据的个数。
首先发送开始信号,再发送从机地址+读写位(读为0、写为1),并反馈(0xA0)
再选择需要读取的寄存器地址(8的倍数),从该位置开始读取,与写入原理相同,读取一次后地址会自增,第二次读取时是第一次地址自加后的位置下的数据。
重新初始化,发送寄存器地址+读写位置(读为0、写为1),反馈。
此时开始读取数据,循环Number次后,数组数据全部读取完。此时注意只有当Number==0时也就是数据已经读取完了,发送反馈1,不在读取;Number!=0说明还有数据,发送反馈0,继续读取。最后停止时序。最后,请一定记得把读取的代码放在main函数最前面!
图 二十五 AT24C02读取数据代码
提供参考代码,希望对读者有帮助
#include <STC15F2K60S2.H>
#include <INTRINS.H>
sbit sda = P2^1;
sbit scl = P2^0;
/* # I2C代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#define DELAY_TIME 5
//
static void I2C_Delay(unsigned char n)
{
do
{
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
}
while(n--);
}
//
void I2CStart(void)
{
sda = 1;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 0;
}
//
void I2CStop(void)
{
sda = 0;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 1;
I2C_Delay(DELAY_TIME);
}
//
void I2CSendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++){
scl = 0;
I2C_Delay(DELAY_TIME);
if(byt & 0x80){
sda = 1;
}
else{
sda = 0;
}
I2C_Delay(DELAY_TIME);
scl = 1;
byt <<= 1;
I2C_Delay(DELAY_TIME);
}
scl = 0;
}
//
unsigned char I2CReceiveByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++){
scl = 1;
I2C_Delay(DELAY_TIME);
da <<= 1;
if(sda)
da |= 0x01;
scl = 0;
I2C_Delay(DELAY_TIME);
}
return da;
}
//
unsigned char I2CWaitAck(void)
{
unsigned char ackbit;
scl = 1;
I2C_Delay(DELAY_TIME);
ackbit = sda;
scl = 0;
I2C_Delay(DELAY_TIME);
return ackbit;
}
//
void I2CSendAck(unsigned char ackbit)
{
scl = 0;
sda = ackbit;
I2C_Delay(DELAY_TIME);
scl = 1;
I2C_Delay(DELAY_TIME);
scl = 0;
sda = 1;
I2C_Delay(DELAY_TIME);
}
/*
IIC通信过程
1、AT24C02写入
起始信号-开始写操作(0xa0)--反馈---写入从机地址--反馈---写入数据反馈--延时200--停止
2、AT24C02读取
起始信号-开始写操作(0xa0)--反馈--写入从机地址--反馈--重新开始--开始读操作(0xa1)--反馈
--开始读取并反馈(不再接收发送1)---停止
/**
* @brief AT24C02_Write往AT24C02中写入数据保证掉电不丢失
* @param *String--传入数组名
* @param Address寄存器地址(8的倍数,如0、8、16、24...)
* @param Number--需要发送的数据总共几位
*/
void AT24C02_Write(unsigned char *String,unsigned char Address,unsigned char Number)
{
I2CStart();
I2CSendByte(0xa0); //写入从机地址
I2CWaitAck();
I2CSendByte(Address); //开始写入的寄存器地址
I2CWaitAck();
while(Number--)
{
I2CSendByte(*String++); //写入数据
I2CWaitAck();
I2C_Delay(200); //延时
}
I2CStop();
I2C_Delay(255); I2C_Delay(255);I2C_Delay(255);I2C_Delay(255);//保证时序
}
//从地址Address开始读取Number个数据,并放入*String数组中(指针)
void AT24C02_Read(unsigned char *String,unsigned char Address,unsigned char Number)
{
I2CStart();
I2CSendByte(0xa0); //写入从机地址
I2CWaitAck(); //反馈
I2CSendByte(Address); //开始写入的寄存器地址
I2CWaitAck();
I2CStart(); //重新开始
I2CSendByte(0xa1); //开始读操作
I2CWaitAck();
while(Number--) //读取Number数据
{
*String++ = I2CReceiveByte();
if(Number) //如何Number!=0表示还有数据需要读取,发送反馈0,继续读取
I2CSendAck(0);
else
I2CSendAck(1); //如何Number==0表示读取完毕,不再接收,发送反馈1
}
I2CStop();
}