标题: 51单片机+AT24C02+按键+Proteus仿真时钟源程序 [打印本页]
作者: hufei 时间: 2013-6-17 03:17
标题: 51单片机+AT24C02+按键+Proteus仿真时钟源程序
时间很准确,跑了2个小时才慢1S,这可是用Proteus仿真软件仿真哦!而且里面有详细的说明,具体到每一步。还有AT24C02的中文资料,希望对新手有用。不过在调试程序的过程中发现了一点小问题,一直没有找到解决的办法,就是在调节时间时光标移动有时出现问题,但是又并不影响调节,具体在程序中有说明,希望有高手能够指点一下!在此先感谢!
单片机定时器时钟.zip
(63.28 KB, 下载次数: 548)
作者: admin 时间: 2013-6-17 03:50
下面是主程序:
/**************************************
名称:89c52+at24c02+键盘时钟程序
工具:protues仿真软件
作者:kwx618
时间:2011-09-10
**************************************/
#include <reg52.h>
#include <intrins.h>
#include"at24c02.h"
#define uchar unsigned char
#define uint unsigned int
sbit LCD_RS=P0^0;
sbit LCD_RW=P0^1;
sbit LCD_EN=P0^2;
sbit S1=P1^2;
sbit S2=P1^3;
sbit S3=P1^4;
sbit S4=P1^5;
char year,mounth,day,hour,minute,second;
uchar num,count;
bit write=0; //写2402标志
uchar code nyr_table[]=" 20 - - ";
uchar code sfm_table[]=" : : ";
/************延时1ms函数***************/
void delay1ms(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=112;y>0;y--);
}
/**************LCD1602程序***********/
void LCD_BUSY()
{
P2=0x00;
LCD_RS=0;
LCD_RW=1;
LCD_EN=1;
while(P2&0x80);
LCD_EN=0;
}
void writeLCD_command(uchar cmd)
{
LCD_BUSY();
LCD_RS=0;
LCD_RW=0;
P2=cmd;
_nop_();
LCD_EN=1;
_nop_();
LCD_EN=0;
}
void writeLCD_data(uchar date)
{
LCD_BUSY();
LCD_RS=1;
LCD_RW=0;
P2=date;
_nop_();
LCD_EN=1;
_nop_();
LCD_EN=0;
}
void write_nyrsfm(char add,char date)
{
char shiwei,gewei;
shiwei=date/10;
gewei=date%10;
writeLCD_command(0x80|add);
delay1ms(1);
writeLCD_data(0x30+shiwei);
delay1ms(1);
writeLCD_data(0x30+gewei);
delay1ms(1);
}
void LCD_init()
{
uchar num1,num2;
year=0;mounth=1;day=1;
hour=23;minute=59;second=59;
LCD_BUSY();
writeLCD_command(0x38);//设置16*2显示,5*7点阵,8位数据接口
delay1ms(5); //此处必须加延时,否则LCD不显示
writeLCD_command(0x0c);//开显示,光标不显示
delay1ms(5); //此处必须加延时,否则光标不会移动
writeLCD_command(0x06);//读或写字符后,光标自动加1,整屏不移动
delay1ms(5);
writeLCD_command(0x02);//数据指针清0
delay1ms(5);
writeLCD_command(0x80|0x02);
for(num1=0;num1<11;num1++)
{
writeLCD_data(nyr_table[num1]);
}
writeLCD_command(0x80|0x43);
for(num2=0;num2<9;num2++)
{
writeLCD_data(sfm_table[num2]);
}
write_nyrsfm(0x80|0x05,year);
_nop_();
write_nyrsfm(0x80|0x08,mounth);
_nop_();
write_nyrsfm(0x80|0x0b,day);
_nop_();
write_nyrsfm(0x80|0x44,hour);
_nop_();
write_nyrsfm(0x80|0x47,minute);
_nop_();
write_nyrsfm(0x80|0x4a,second);
_nop_();
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;
ET0=1;
TR0=1;
}
/**************************************************
名称:按键程序
S1: 设置键
S2:时间加
S3:时间减
**************************************************/
void keyscan()
{
if(S1==0)
{
delay1ms(10);
if(S1==0)
num++;
while(!S1);
switch(num)
{
case 1: TR0=0;
writeLCD_command(0x80|0x4b);
delay1ms(1);
writeLCD_command(0x0f);
delay1ms(1);
break;
case 2: TR0=0;
writeLCD_command(0x80|0x48);
writeLCD_command(0x0f);
break;
case 3: TR0=0;
writeLCD_command(0x80|0x45);
writeLCD_command(0x0f);
break;
case 4: TR0=0;
writeLCD_command(0x80|0x0c);
writeLCD_command(0x0f);
break;
case 5: TR0=0;
writeLCD_command(0x80|0x09);
writeLCD_command(0x0f);
break;
case 6: TR0=0;
writeLCD_command(0x80|0x06);
writeLCD_command(0x0f);
break;
case 7: num=0;
writeLCD_command(0x0c);
TR0=1;
break;
default:break;
}
}
}
void up_downsetkey()
{
//keyscan();
if(num!=0)
{
if(S2==0)
{
delay1ms(10);
if(S2==0)
while(!S2);
switch(num)
{
case 1: second++;
if(second==60)
second=0;
write_nyrsfm(0x80|0x4a,second);
delay1ms(5);
write2402_data(1,second);
delay1ms(5);
break;
case 2: minute++;
if(minute==60)
minute=0;
write_nyrsfm(0x80|0x47,minute);
delay1ms(5);
write2402_data(2,minute);
delay1ms(5);
break;
case 3: hour++;
if(hour==24)
hour=0;
write_nyrsfm(0x80|0x44,hour);
delay1ms(5);
write2402_data(3,hour);
delay1ms(5);
break;
case 4: day++;
if(day==30)
day=0;
write_nyrsfm(0x80|0x0b,day);
delay1ms(5);
write2402_data(4,day);
delay1ms(5);
break;
case 5: mounth++;
if(mounth==12)
mounth=0;
write_nyrsfm(0x80|0x08,mounth);
delay1ms(5);
write2402_data(5,mounth);
delay1ms(5);
break;
case 6: year++;
if(year==99)
year=0;
write_nyrsfm(0x80|0x05,year);
delay1ms(5);
write2402_data(6,year);
delay1ms(5);
break;
default:break;
}
}
if(S3==0)
{
delay1ms(10);
if(S3==0)
while(!S3);
switch(num)
{
case 1: second--;
if(second==-1)
second=59;
write_nyrsfm(0x80|0x4a,second);
delay1ms(1);
write2402_data(1,second);
break;
case 2: minute--;
if(minute==-1)
minute=59;
write_nyrsfm(0x80|0x47,minute);
write2402_data(2,minute);
break;
case 3: hour--;
if(hour==-1)
hour=23;
write_nyrsfm(0x80|0x44,hour);
write2402_data(3,hour);
break;
case 4: day--;
if(day==-1)
day=30;
write_nyrsfm(0x80|0x0b,day);
write2402_data(4,day);
break;
case 5: mounth--;
if(mounth==-1)
mounth=12;
write_nyrsfm(0x80|0x08,mounth);
write2402_data(5,mounth);
break;
case 6: year--;
if(year==-1)
year=99;
write_nyrsfm(0x80|0x05,year);
write2402_data(6,year);
break;
default:break;
}
}
}
}
/*void display() //开始的时候采用这种边显示边写2402的方式,但是程序写不到2402,
{ //很郁闷。不过调整时间时光标很正常,一直想找个方法让光标正常而且能写进
if(count==20) // 2402的方法,但是没有想出来
{
second++;
count=0;
if(second==60)
{
second=0;
minute++;
if(minute==60)
{
minute=0;
hour++;
if(hour==24)
{
hour=0;
day++;
if(day==31)
{
day=0;
mounth++;
if(mounth==13)
{
mounth=0;
year++;
write_nyrsfm(0x80|0x05,year);
delay1ms(1);
write2402_data(6,year);
delay1ms(1);
}
write_nyrsfm(0x80|0x08,mounth);
delay1ms(1);
write2402_data(5,mounth);
delay1ms(1);
}
write_nyrsfm(0x80|0x0b,day);
delay1ms(1);
write2402_data(4,day);
delay1ms(1);
}
write_nyrsfm(0x80|0x44,hour);
delay1ms(1);
write2402_data(3,hour);
delay1ms(1);
}
write_nyrsfm(0x80|0x47,minute);
delay1ms(1);
write2402_data(2,minute);
delay1ms(1);
}
write_nyrsfm(0x80|0x4a,second);
delay1ms(1);
write2402_data(1,second);
delay1ms(1);
}
} */
/************显示程序****************/
void display()
{
//year=0;mounth=1;day=0; // 开始的时候不写这两句,显示的结果就是2000-0/-0/ 23-0/-0/ ,
//hour=23;minute=59;second=59; // 解决办法是先在加上这两句,然后把初始化里的那两句屏蔽掉,然后编译显示,
write_nyrsfm(0x80|0x05,year); // 在回过头来去掉初始化里的屏蔽,把这两句删掉编译就显示正常了,具体为什么会
delay1ms(1); //这样,我也不清楚,有待解决。
write_nyrsfm(0x80|0x08,mounth);
delay1ms(1);
write_nyrsfm(0x80|0x0b,day);
delay1ms(1);
write_nyrsfm(0x80|0x44,hour);
delay1ms(1);
write_nyrsfm(0x80|0x47,minute);
delay1ms(1);
write_nyrsfm(0x80|0x4a,second);
delay1ms(1);
}
void main()
{
init_2402();
delay1ms(5);
LCD_init();
delay1ms(5); //此处也必须加延时,否则不会在指定的位置显示
second =read_data(0); //读出24c02保存的值赋于sec
if(second>60) //防止首次读出错误数据
second=0;
delay1ms(5);
minute=read_data(1); //读出24c02保存的值赋于sec
if(minute>60) //防止首次读出错误数据
minute=0;
delay1ms(5);
hour=read_data(2); //读出24c02保存的值赋于sec
if(hour>24) //防止首次读出错误数据
hour=0;
delay1ms(5);
day=read_data(3); //读出24c02保存的值赋于sec
if(day>30) //防止首次读出错误数据
day=0;
delay1ms(5);
mounth=read_data(4); //读出24c02保存的值赋于sec
if(mounth>12) //防止首次读出错误数据
mounth=0;
delay1ms(5);
year=read_data(5); //读出24c02保存的值赋于sec
if(year>12) //防止首次读出错误数据
year=0;
delay1ms(5);
while(1)
{
display();
delay1ms(1);
keyscan();
delay1ms(1);
up_downsetkey();
delay1ms(1);
if(write==1)
{
write2402_data(0,second);
delay1ms(1);
write2402_data(1,minute);
delay1ms(1);
write2402_data(2,hour);
delay1ms(1);
write2402_data(3,day);
delay1ms(1);
write2402_data(4,mounth);
delay1ms(1);
write2402_data(5,year);
delay1ms(1);
write=0; //清0
}
}
}
void intputtime0() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
count++;
if(count==16)//此处应该是20,但是用protues仿真时会发现误差很大,所以我调到了16,时间刚好。
{
second++;
count=0;
if(second==60)
{
second=0;
minute++;
if(minute==60)
{
minute=0;
hour++;
if(hour==24)
{
hour=0;
day++;
if(day==31)
{
day=0;
mounth++;
if(mounth==13)
{
mounth=0;
year++;
}
}
}
}
}
write=1;
}
}
作者: 左左右右 时间: 2013-7-1 16:06
51Hei(51黑)论坛有你更精彩
作者: HUFUHA 时间: 2013-10-9 03:10
看看学习学习
作者: 13620819446 时间: 2013-10-13 23:27
不错过来看看
作者: 游侠(单片机开 时间: 2013-10-23 14:16
很好 学习 谢谢
作者: wanshaojun 时间: 2014-1-18 22:55
学习学习
作者: fbzsn 时间: 2014-8-31 23:03
好像proteus仿真通不过,检测到没有声明write2402_data子函数,程序中也没有写这个子函数。
作者: test66878114 时间: 2014-9-2 10:19
谢谢分享,赞一个
作者: 游侠(单片机开 时间: 2014-9-2 11:30
谢谢 很好
作者: heam 时间: 2014-9-15 12:33
谢谢分享
作者: xing3198 时间: 2014-9-18 16:18
很好 学习 谢谢
作者: shc95 时间: 2014-10-8 10:18
感谢楼主分享
作者: finalex 时间: 2014-10-8 10:29
有图吗
作者: shushikuan 时间: 2014-10-8 11:02
很好,学习了哈。
作者: tianxing 时间: 2014-10-14 17:51
马虎了。
作者: 绿源学习者 时间: 2015-1-30 13:49
没有仿真图唉
作者: seeking1005 时间: 2015-2-2 01:11
51Hei(51黑)论坛有你更精彩
作者: fontex 时间: 2015-2-2 13:21
又学到新东西。
作者: 啊大苏打似的 时间: 2015-7-9 09:49
不知道有没有电路原理图




作者: 11223 时间: 2015-9-14 21:12
时钟的时间如何修改?
作者: zxcvbnm1 时间: 2015-10-28 17:23
有图么
作者: wangxiaomi 时间: 2015-11-1 19:14
非常好
作者: ruzongqing 时间: 2016-1-14 14:10
我要认真的好好学习学习!
作者: linnyshow 时间: 2016-3-22 22:32
不错,有电路图就更好了。
作者: 瓦尔登 时间: 2016-3-23 19:04
好东西呀,正在学习,多谢了
作者: lqm 时间: 2016-3-27 23:19
很不错,值得大家学习
作者: 炳文 时间: 2016-12-3 09:36
到底有没有仿真
作者: hei_cmh 时间: 2016-12-11 18:06
很好 学习
作者: 784721214 时间: 2016-12-12 14:22
学习下,很不错!
作者: chjx0131 时间: 2017-1-2 14:47
学习了。
作者: darm 时间: 2017-3-16 11:26
借鉴了一下,对我学习单片机很有作用,多谢
作者: yanjingshe 时间: 2017-4-5 14:37
24c02是干什么用的
作者: yuanyuanyuaan 时间: 2017-10-31 09:06
谢谢楼主的教程,回去好好研究一下~~
作者: xd_q 时间: 2018-1-19 15:45
学习一下
作者: 70599 时间: 2018-5-21 10:37
谢谢楼主的教程,正研究2402
作者: echos2000 时间: 2019-10-29 19:37
很好,收藏了
作者: q2855159156 时间: 2020-12-18 13:52
向大佬学习学习
作者: 大山儿子20@ 时间: 2023-11-25 10:13
谢谢坛主的无私分享,都是干货的。
作者: dyx811 时间: 2023-11-25 22:35
学习了,依然在学习的路上!感谢版主和楼主的无私奉献!
作者: anjianguo 时间: 2024-11-23 23:20
(65536-50000)/256; 把50000定义为时基,再增加一层时基设置(并存储),这样时钟可以调的很准!
我正在为STC15W408外加AT24C02存储时基头疼!我用的是STC89C52外加AT24C02存储器的程序!嘿嘿!
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |