蓝桥杯51单片机
AT24C02的学习与应用
·
#AT24C02存储器#
①介绍
功能:存储数据
大小:2K Bit,256个字节

②原理图(数据手册)通信协议IIC
总结步骤(写操作)
- 开始
- 发送器件地址(写)0xa0
- 等待应答
- 发送字节地址
- 等待应答
- 发送数据
- 等待应答
- 停止


总结步骤(读操作)
- 开始
- 发送器件地址(写)
- 等待应答
- 发送字节地址
- 等待应答
- 开始
- 发送器件地址(读)0xa1
- 等待应答
- 读数据
- 不应答
- 停止
注意:页写一次最多写8个,多余的会从头开始覆盖
- 内存可以当作小房间(存放二进制数据),02存储器看成多栋楼,每栋楼都有八层,每层八个房间
- 连续读写:一栋一栋的把数据输入(效率高)
- 索引地址最好是每栋楼的第一层,地址是8的整数倍
使用指针:一个数组八个数据,数组名为数组的首地址,数组之间传递使用指针


③代码编写
1.IIC.c代码编写
/* # I2C代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <reg52.h>
#include <intrins.h>//此库函数确保AT24C02的正常使用
#define DELAY_TIME 5
sbit sda =P2^1;
sbit scl=P2^0;//看原理图将引脚标注
//
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);
}
void AT24C02_Write( unsigned char addr , unsigned char dat )
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
unsigned char AT24C02_Read( unsigned char addr)
{
unsigned char power_count_temp;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
power_count_temp = I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return power_count_temp;
}
//页写函数,与写函数类似,多一个循环
void AT24C02_Write_Page(unsigned char *buf,unsigned char addr,unsigned char num)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
while(num--)//数据有几个,就执行几次
{
I2CSendByte(*buf++);//先*buf,再buf++
I2CWaitAck();
}
I2CStop();
}
//页读函数,与随机读函数类似,注意,随机读有一个返回值,而页读直接存放到数组中,不需要返回值
void AT24C02_Read_Page(unsigned char *buf,unsigned char addr,unsigned char num)
{
//unsigned char i;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
/*for(i=0;i<8;i++)
{
buf[i]=I2CReceiveByte();
if(num)
{
I2CSendAck(0);//应答
}
else
{
I2CSendAck(1);//非应答
}
*/
while(num--)
{
*buf++ = I2CReceiveByte();
if(num)
{
I2CSendAck(0);//应答
}
else
{
I2CSendAck(1);//非应答
}
}
I2CStop();
}
2.IIC.h头文件编写
#ifndef __IIC_H__
#define __IIC_H__
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(unsigned char ackbit);
unsigned char AT24C02_Read( unsigned char addr);
void AT24C02_Write( unsigned char addr , unsigned char dat );
void AT24C02_Write_Page(unsigned char *buf,unsigned char addr,unsigned char num);
void AT24C02_Read_Page(unsigned char *buf,unsigned char addr,unsigned char num);
//不知道在主函数使用哪一个函数的话,就将c文件内所有函数复制在内
#endif
④注意事项
存数字永久,除非覆盖数字
读取开机次数
write函数后一定要延时,确保数据输入成功(collect_dly<10ms)
第一次有write函数,输入1234,read读出1234
第二次将write函数注释,输入2345,read读出还是1234
注意:write→delay10ms→read(数据为输入数据)
注意:直接read(无论输入何值。都是前一次有write的情况下输入的值,02芯片有保存数据的功能)
读函数:只需要读取数据所对应的字节地址即可,后面的数据是收取地址读取内容,只需要一个变量接受即可所以只有addr
写函数:需要发送字节地址和发送数据,所以有dat和addr
⑤代码案例
1.读取数字
#include <reg52.h>
#include <intrins.h>
#include <iic.h>
#define uint unsigned int
#define uchar unsigned char
//初定义
sbit LSA=P2^5;
sbit LSB=P2^6;
sbit LSC=P2^7;
sbit S7=P3^0;
code uchar smg_number[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0x7f};
////uint temp;//读取数据的值
//规定一下初值
uint temp=1234;
uint count ;
//hc573定义
void hc573(uint channel)
{
switch(channel)
{
case 4:LSA=0;LSB=0;LSC=1;break;
case 5:LSA=1;LSB=0;LSC=1;break;
case 6:LSA=0;LSB=1;LSC=1;break;
case 7:LSA=1;LSB=1;LSC=1;break;
}
}
//延时函数
void delay_ms(uint xms) //@12.000MHz
{
for( ;xms>0;xms--)
{
unsigned char data i, j;
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
//初始化
void init_sys()
{
hc573(4);
P0=0xff;
hc573(5);
P0=0x00;
}
//数码管设置,消隐与独立显示
void smg(uint pos,uint num)
{
hc573(7);
P0=0xff;
hc573(6);
P0=0x01<<(pos-1);
hc573(7);
P0=smg_number[num];
delay_ms(1);
}
//数码管显示
void display()
{
smg(5,temp/1000);
smg(6,temp/100%10);
smg(7,temp%100/10);
smg(8,temp%10);
}
//主函数
void main()
{
init_sys();
AT24C02_Write(0x00,temp%256);//低八位提取
delay_ms(10);
AT24C02_Write(0x01,temp/256);//高八位提取
delay_ms(10);
temp=AT24C02_Read(0x00)+AT24C02_Read(0x01)*256;//还原成16位
while(1)
{
display();
}
}
2.读取开机次数
#include <reg52.h>
#include <intrins.h>
#include <iic.h>
#define uint unsigned int
#define uchar unsigned char
初定义
sbit LSA=P2^5;
sbit LSB=P2^6;
sbit LSC=P2^7;
sbit S7=P3^0;
code uchar smg_number[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0x7f};
//uint temp;//读取数据的值
规定一下初值
uint temp=1234;
uint count ;
hc573定义
void hc573(uint channel)
{
switch(channel)
{
case 4:LSA=0;LSB=0;LSC=1;break;
case 5:LSA=1;LSB=0;LSC=1;break;
case 6:LSA=0;LSB=1;LSC=1;break;
case 7:LSA=1;LSB=1;LSC=1;break;
}
}
延时函数
void delay_ms(uint xms) //@12.000MHz
{
for( ;xms>0;xms--)
{
unsigned char data i, j;
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
初始化
void init_sys()
{
hc573(4);
P0=0xff;
hc573(5);
P0=0x00;
AT24C02_Write(0x01,0);//内存初始化为0,存放开机次数
delay_ms(10);//写函数后面必须延时十毫秒
}
数码管设置,消隐与独立显示
void smg(uint pos,uint num)
{
hc573(7);
P0=0xff;
hc573(6);
P0=0x01<<(pos-1);
hc573(7);
P0=smg_number[num];
delay_ms(1);
}
数码管显示
void display()
{
smg(5,temp/1000);
smg(6,temp/100%10);
smg(7,temp%100/10);
smg(8,temp%10);
}
/////////////////////
void key()
{
if(S7==0)
{
delay_ms(10);
if(S7==0)
{
while(S7==0)
{
display();
}
temp++;
AT24C02_Write(0x01,temp);//输入新的数值
}
}
}
void main()
{
init_sys();
temp=AT24C02_Read(0x01);//temp为开机次数
temp++;
AT24C02_Write(0x01,temp);//数字写进去,一定要延时10ms,时间等待才可应答
delay_ms(10);
temp=AT24C02_Read(0x01);//检验
while(1)
{
display();
key();
}
}
3.页存储数据
#include <reg52.h>
#include <intrins.h>
#include <iic.h>
#define uint unsigned int
#define uchar unsigned char
初定义
sbit LSA=P2^5;
sbit LSB=P2^6;
sbit LSC=P2^7;
sbit S7=P3^0;
code uchar smg_number[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0x7f};
//uint temp;//读取数据的值
规定一下初值
uint temp=1234;
uint count ;
hc573定义
void hc573(uint channel)
{
switch(channel)
{
case 4:LSA=0;LSB=0;LSC=1;break;
case 5:LSA=1;LSB=0;LSC=1;break;
case 6:LSA=0;LSB=1;LSC=1;break;
case 7:LSA=1;LSB=1;LSC=1;break;
}
}
延时函数
void delay_ms(uint xms) //@12.000MHz
{
for( ;xms>0;xms--)
{
unsigned char data i, j;
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
初始化
void init_sys()
{
hc573(4);
P0=0xff;
hc573(5);
P0=0x00;
数码管设置,消隐与独立显示
void smg(uint pos,uint num)
{
hc573(7);
P0=0xff;
hc573(6);
P0=0x01<<(pos-1);
hc573(7);
P0=smg_number[num];
delay_ms(1);
}
//////////////////
uchar BUFF[8]={1,2,3,4,5,6,7,8};
void display()
{
smg(1,BUFF[0]);
smg(2,BUFF[1]);
smg(3,BUFF[2]);
smg(4,BUFF[3]);
smg(5,BUFF[4]);
smg(6,BUFF[5]);
smg(7,BUFF[6]);
smg(8,BUFF[7]);
}
void main()
{
init_sys();
AT24C02_Write_Page(BUFF,0x00,8);
delay_ms(10);
AT24C02_Read_Page(BUFF,0x00,8);
while(1)
{
display();
}
}
4.存储数字(永不变,除非覆盖数字)
#include <STC15F2K60S2.H>
#include "intrins.h"
#include "iic2.h"
#define uint unsigned int
#define uchar unsigned char
uchar temp;
code unsigned char segment[] =
{
0xc0,
0xf9,
0xa4,
0xb0,
0x99,
0x92,
0x82,
0xf8,
0x80,
0x90,
0xff };
void hc573(uchar channel)
{
switch(channel)
{
case 4:P2=P2&0x1f |0x80;break;
case 5:P2=P2&0x1f |0xa0;break;
case 6:P2=P2&0x1f |0xc0;break;
case 7:P2=P2&0x1f |0xe0;break;
}
P2=P2&0x1f;
}
void delay_ms(uchar xms) //@12.000MHz
{
for( ; xms>0;xms--)
{
unsigned char data i, j;
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
void init_sys()
{
P0=0xff;
hc573(4);
P0=0x00;
hc573(5);
write(0x01,235);//写函数
delay_ms(10);
}
void smg(uchar pos,uchar dot ,uchar num)
{
P0=0xff;
hc573(7);
P0=0x01<<(pos-1);
hc573(6);
if(dot)
{
P0=segment[num]&0x7f;
}
else
{
P0=segment[num];
}
hc573(7);
delay_ms(1);
}
void display()
{
smg(1,0,10);
smg(2,0,10);
smg(3,0,10);
smg(4,0,10);
smg(5,0,10);
smg(6,0,temp/100);
smg(7,0,temp%100/10);
smg(8,0,temp%10);
}
void main()
{
init_sys();
while(1)
{
temp=read(0x01);//读取之前初始化的235
display();
}
}
#STC15F2K60S2是ISP编译的专属头文件,里面的引脚定义很全,相较于reg52.h更便捷哦^_^#
#使用AT24C02得添加intrins.h头文件,要不然IIC文件缺失条件#
更多推荐






所有评论(0)