标题:
利用AT24C02来保存,精华都在程序中。。。。。
[打印本页]
作者:
xiao_yp2014
时间:
2015-1-10 23:57
标题:
利用AT24C02来保存,精华都在程序中。。。。。
本帖最后由 xiao_yp2014 于 2016-1-21 14:33 编辑
功能需求:
开机后两位数码管显示0到99之间的某一个数值,用一个按键可以不断的递增,用另外一个按键可以不断的递减。断电后此数据可保存,下次通电 开机的时候还是从那个保存的数据开始显示。
程序如下:
main.c
/*EEPROM篇--利用AT24C02存储数据
功能需求:
开机后两位数码管显示0到99之间的某一个数值,用一个按键可以不断的递增,
用另外一个按键可以不断的递减。断电后此数据可保存,下次通电开机的时候
还是从那个保存的数据开始显示。
*/
#include<reg52.h> //头文件
#include"AT24C02.h" //IIC自定义头文件
#include"Key_Scan.h" //按键自定义头文件
#include"display.h" //数码管显示自定义头文件
sbit beep_dr = P3^6; //蜂鸣器
unsigned int uiVoiceCnt = 0; //蜂鸣器时间变量
unsigned char ucSetNumber = 0; //设定值变量
void Init_All(); //初始化全部程序
void Timer_T0(); //TO定时器中断
void main()
{
Init_All(); //初始化全部
while(1)
{
display(); //调用数码管显示函数
Key_Service(); //调用按键服务函数,放在主函数里
}
}
void Init_All()
{
TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f
TL0=0x2f;
EA = 1;
ET0 = 1;
TR0=1; //开中断
ucSetNumber = read_eeprom(128); //上电开机读取EEPROM数据,128是一个我任意选的一个存储地址
if(ucSetNumber > 99)
{
write_eeprom(128,0); //往一个地址存入一个字节数据,128是一个我任意选的一个存储地址
}
}
void Timer_T0() interrupt 1
{
TF0=0; //清除中断标志
TR0=0; //关中断
Key_Scan(); //按键扫描放在中断里
if(uiVoiceCnt!=0) //蜂鸣器
{
uiVoiceCnt--; //每次进入定时中断都自减1,直到等于零为止。才停止鸣叫
beep_dr = 0; //蜂鸣器是PNP三极管控制,低电平就开始鸣叫
}
else
{
beep_dr = 1; //蜂鸣器是PNP三极管控制,高电平就停止鸣叫。
}
TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f
TL0=0x2f;
TR0=1; //开中断
}
复制代码
AT24C02.c
#include<intrins.h>
#include"AT24C02.h"
sbit eeprom_scl_dr = P3^4; //时钟线
sbit eeprom_sda_dr = P3^5; //数据输出线
//AT24C02驱动程序
void start24() //开始位
{
eeprom_sda_dr=1;
eeprom_scl_dr=1;
Delay_time(15);
eeprom_sda_dr=0;
Delay_time(15);
eeprom_scl_dr=0;
}
void ack24() //确认位
{
eeprom_scl_dr=1;
Delay_time(15);
eeprom_scl_dr=0;
Delay_time(15);
}
void stop24() //停止位
{
eeprom_sda_dr=0;
eeprom_scl_dr=1;
Delay_time(15);
eeprom_sda_dr=1;
}
unsigned char read24() //读取一个字节的时序
{
unsigned char outdata,tempdata;
outdata=0;
_nop_(); //空指令,相当于一个机器周期
_nop_(); //空指令,相当于一个机器周期
for(tempdata=0;tempdata<8;tempdata++)
{
eeprom_scl_dr=0;
_nop_(); //空指令,相当于一个机器周期
_nop_() ; //空指令,相当于一个机器周期
eeprom_scl_dr=1;
_nop_() ; //空指令,相当于一个机器周期
_nop_() ; //空指令,相当于一个机器周期
outdata<<=1;
if(eeprom_sda_dr==1)
{
outdata++;
}
_nop_() ; //空指令,相当于一个机器周期
_nop_() ; //空指令,相当于一个机器周期
}
return(outdata);
}
void write24(unsigned char dd) //发送一个字节的时序
{
unsigned char tempdata;
for(tempdata=0;tempdata<8;tempdata++)
{
if(dd>=0x80)
{
eeprom_sda_dr=1;
}
else
{
eeprom_sda_dr=0;
}
dd<<=1;
_nop_() ; //空指令,相当于一个机器周期
eeprom_scl_dr=1;
_nop_() ; //空指令,相当于一个机器周期
_nop_() ; //空指令,相当于一个机器周期
_nop_() ; //空指令,相当于一个机器周期
_nop_() ; //空指令,相当于一个机器周期
eeprom_scl_dr=0;
}
}
unsigned char read_eeprom(unsigned int address) //从一个地址读取出一个字节数据
{
unsigned char dd,cAddress;
cAddress=address; //把低字节地址传递给一个字节变量。
start24(); //开始
write24(0xA0); //此字节包含读写指令和芯片地址两方面的内容。
//指令为写指令。地址为"000"的信息,此信息由A0,A1,A2的引脚决定
ack24(); //发送应答信号
write24(cAddress); //发送读取的存储地址(范围是0至255)
ack24(); //发送应答信号
start24(); //开始
write24(0xA1); //此字节包含读写指令和芯片地址两方面的内容。
//指令为读指令。地址为"000"的信息,此信息由A0,A1,A2的引脚决定
ack24(); //发送应答信号
dd=read24(); //读取一个字节
ack24(); //发送应答信号
stop24(); //停止
Delay_time(800); //此处最关键,此处的延时时间一定要,而且要足够长
return(dd);
}
void write_eeprom(unsigned int address,unsigned char dd) //往一个地址存入一个字节数据
{
unsigned char cAddress;
cAddress=address; //把低字节地址传递给一个字节变量。
start24(); //开始
write24(0xA0); //此字节包含读写指令和芯片地址两方面的内容。
//指令为写指令。地址为"000"的信息,此信息由A0,A1,A2的引脚决定
ack24(); //发送应答信号
write24(cAddress); //发送写入的存储地址(范围是0至255)
ack24(); //发送应答信号
write24(dd); //写入存储的数据
ack24(); //发送应答信号
stop24(); //停止
Delay_time(2000); //此处最关键,此处的延时时间一定要,而且要足够长
}
void Delay_time(unsigned int Delay11_MS)
{
unsigned int Delay11_us;
for(Delay11_us=0;Delay11_us<Delay11_MS;Delay11_us++)
{
_nop_();
}
}
复制代码
AT24C02.h
#ifndef __AT24C02_H__
#define __AT24C02_H__
#include<reg52.h>
unsigned char read_eeprom(unsigned int address); //从一个地址读取出一个字节数据
void start24(); //开始位
void ack24(); //确认位
void stop24(); //停止位
unsigned char read24(); //读取一个字节的时序
void write24(unsigned char dd); //发送一个字节的时序
void write_eeprom(unsigned int address,unsigned char dd); //往一个地址存入一个字节数据
void Delay_time(unsigned int Delay11_MS); //延时程序
#endif
复制代码
Key_Scan.c
#include"Key_Scan.h" //按键自定义头文件
#include"AT24C02.h" //IIC自定义头文件
#define const_KeyTimeLevel 100 //按键消抖的时间,可以修改
#define const_VoiceCntLevel 150 //蜂鸣器鸣叫的时间
sbit Key_s1 = P1^6; //数据加
sbit Key_s2 = P1^7; //数据减
unsigned int uiKeyTimeCnt1 = 0; //按键延时计数器
unsigned int uiKeyTimeCnt2 = 0; //按键延时计数器
unsigned char ucKeyLock1 = 0; //按键自锁标志位,防止按键一直触发
unsigned char ucKeyLock2 = 0; //按键自锁标志位,防止按键一直触发
unsigned char KeySec = 0; //按键编号
void Key_Scan() //按键扫描程序
{
if(Key_s1 == 1)
{
uiKeyTimeCnt1 = 0; //延时计数器清零
ucKeyLock1 = 0; //自锁标志位清零
}
else if(ucKeyLock1 == 0) //当有按键按下
{
uiKeyTimeCnt1++; //延时计数器加1
if(uiKeyTimeCnt1 >= const_KeyTimeLevel) //去抖动时间到
{
uiKeyTimeCnt1 = 0; //延时计数器清零
ucKeyLock1 = 1; //按键自锁
KeySec = 1; //触发1号键
}
}
if(Key_s2 == 1)
{
uiKeyTimeCnt2 = 0; //延时计数器清零
ucKeyLock2 = 0; //自锁标志位清零
}
else if(ucKeyLock2 == 0) //当有按键按下
{
uiKeyTimeCnt2++; //延时计数器加1
if(uiKeyTimeCnt2 >= const_KeyTimeLevel) //去抖动时间到
{
uiKeyTimeCnt2 = 0; //延时计数器清零
ucKeyLock2 = 1; //按键自锁
KeySec = 2; //触发2号键
}
}
}
void Key_Service() //按键服务函数
{
switch(KeySec)
{
case 0:break;
case 1:
ucSetNumber++; //设定值自加1
if(ucSetNumber >= 99) //当加到99,就赋值成0
{
ucSetNumber = 0; //赋值
}
write_eeprom(128,ucSetNumber); //往一个地址存入一个字节数据
uiVoiceCnt = const_VoiceCntLevel;//蜂鸣器
KeySec = 0; //清零按键标志
break; //跳出
case 2:
ucSetNumber--; //设定值自减1
if(ucSetNumber>=99) //减到大于99,赋值成99
{
ucSetNumber = 99;
}
write_eeprom(128,ucSetNumber); //往一个地址存入一个字节数据
uiVoiceCnt = const_VoiceCntLevel; //蜂鸣器
KeySec = 0; //清零按键标志位
break;
default : break;
}
}
复制代码
Key_Scan.h
#ifndef __Key_Scan_H__
#define __Key_Scan_H__
#include<reg52.h>
void Key_Scan(); //按键扫描程序
void Key_Service(); //按键服务程序
extern unsigned int uiVoiceCnt; //变量全局声名
extern unsigned char ucSetNumber; //变量全局声名
extern unsigned char ucSetNumber; //变量全局声名extern可置于变量或者函数前,以表示变量或者函数的定义在别的文件中,
//提示编译器遇到此变量和函数时在其他模块中寻找其定义
#endif
复制代码
Display.c
#include"display.h" //显示头文件
#include"delay.h" //延时头文件
unsigned char code array[]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
void display()
{
static unsigned char ucNumber_left = 0; //左边数码管显示的实际内容
static unsigned char ucNumber_right = 0; //右边数码管显示的实际内容
static unsigned char ucDisplayStep = 1; //显示步骤切换变量
if(ucSetNumber >= 10) //在显示的数值小于10时,左边数码管不显示
{
ucNumber_left = ucSetNumber/10; //得到左边显示的值
}
else
{
ucNumber_left = 10; //小于10就不显示
}
ucNumber_right = ucSetNumber%10; //右边数码管显示的值
switch(ucDisplayStep)
{
case 1: //左边数码管显示驱动
P0 = array[ucNumber_left];
P2 = 0xfe;
ucDisplayStep = 2;
delay_10ms();
P2 = 0xff;
break;
case 2:
P0 = array[ucNumber_right]; //右边数码管显示驱动
P2 = 0xfd;
ucDisplayStep = 1;
delay_10ms();
P2 = 0xff;
break;
}
}
复制代码
Display.h
#ifndef __display_h__
#define __display_h__
#include<reg52.h>
void display();
extern unsigned char ucIICDataTemp; //声名全局变量
extern unsigned char ucSetNumber; //声名全局变量
#endif
复制代码
delay.c
#include"delay.h"
void delay_10ms() //延时函数
{
unsigned int x,y;
for(x = 0;x<10;x++)
for(y = 0;y<10;y++);
}
复制代码
delay.h
#ifndef __delay_h__
#define __delay_h__
void delay_10ms(); //函数声名
#endif
复制代码
打包程序下载——>
EEPROM篇—用AT24C02数据保存数据.zip
(108.42 KB, 下载次数: 264)
2015-1-10 23:55 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
liuyy
时间:
2015-1-11 02:59
谢谢版主提供 这么好的学习资料。先下了看看
作者:
liuyy
时间:
2015-1-11 03:01
楼主程序文件很多,但是注释详细非常好。有电路图吗?
作者:
xiao_yp2014
时间:
2015-1-11 19:55
liuyy 发表于 2015-1-11 02:59
谢谢版主提供 这么好的学习资料。先下了看看
资料还有,我会慢慢的奉献的。。。。。
作者:
xiao_yp2014
时间:
2015-1-11 19:58
liuyy 发表于 2015-1-11 03:01
楼主程序文件很多,但是注释详细非常好。有电路图吗?
文件分得很细,是为了以后方便移植,我是用的开发板,原理图就不上了,很简单的。可以根据程序来画原理图。。。
作者:
wendy666
时间:
2015-2-11 15:02
顶一下!好东西!谢谢楼主,正找这个呢!
作者:
hxk9608
时间:
2016-7-25 09:20
赞一个,很好的资料!
作者:
xyz9836
时间:
2016-8-17 23:13
多谢无私分享
作者:
xd_q
时间:
2018-1-22 13:45
谢谢版主提供 这么好的学习资料
作者:
bingguang
时间:
2019-12-6 17:11
看一看
作者:
mmjjrr
时间:
2020-4-26 22:50
写得太棒了!
作者:
lhtlhtl
时间:
2023-11-14 08:57
这么详细,讲究
作者:
lllzzzlll
时间:
2023-12-18 22:03
很不错,很详细,值得研究
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1