电子时钟实验报告
全部代码在文档末尾:51单片机,LCD1602液晶显示屏平台下编程实现,可直接编译运行
目录:
一, 实验目的
20世纪末,电子技术获得了飞速的发展,在其推动下,现代电子产品几乎渗透了社会的各个领域,有力地推动了社会生产力的发展和社会信息化程度的提高,同时也使现代电子产品性能进一步提高,产品更新换代的节奏也越来越快。
现代生活的人们越来越重视起了时间观念,可以说是时间和金钱划上了等号。对于那些对时间把握非常严格和准确的人或事来说,时间的不准确会带来非常大的麻烦,所以电子钟是以其小巧,价格低廉,走时精度高,使用方便,功能多,便于集成化而受广大消费的喜爱,得到了广泛的使用。
1. 学习8051定时器时间计时处理、按键扫描及LCD液晶显示的设计方法。
2. 设计任务及要求 利用实验平台上LCD1602液晶显示屏, 设计带有闹铃功能的数字时钟
二,实验要求
A.基本要求:
1. 在LCD1602液晶显示屏上显示当前日期,时间。
2. 利用按键可对时间及闹玲进行设置,并可显示设置闹玲的时间。闹玲时间到蜂鸣器发出声响,一分钟后闹铃停止。
B.扩展部分:
1.日历功能(能对年,月,日,星期进行显示,分辨平年,闰年以及各月天数,并调整)实现年月日时分秒的调整,星期准确的随着日期改变而改变进行显示。
2.定时功能(设定一段时间长度,定时到后,闹铃提示)
C.可扩展部分:
1.闹铃重响功能(闹铃被停止后,以停止时刻开始,一段时间后闹铃重响,且重响时间的间隔可调)
2.可进行备忘录提示,按照年月日,可在设定的某年某月进行闹铃提示。
三,实验基本原理
利用单片机定时器完成计时功能,定时器0计时中断程序每隔0.05s中断一次并当作一个计数,设定定时1秒的中断计数初值为20,每中断一次中断计数初值加1,当减到20时,则表示1s到了,秒变量加1,同理再判断是否1min钟到了,再判断是否1h到了,是否一天到了,是否一个月到了,是否一年到了。
将时间在LCD液晶屏上显示,降低了程序的编写难度。LCD的固定显示特性是我们省去了数码管的动态扫描显示。
四,实验设计分析
针对要实现的功能,采用AT89S52单片机进行设计,AT89S52 单片机是一款低功耗,高性能CMOS8位单片机,片内含4KB在线可编程(ISP)的可反复擦写1000次的Flash只读程序存储器,器件采用高密度、非易失性存储技术制造,兼容标准MCS- 51指令系统及80C51引脚结构。这样,既能做到经济合理又能实现预期的功能。
在程序方面,采用分块设计的方法,这样既减小了编程难度、使程序易于理解,又能便于添加各项功能。程序可分为闹钟的声音程序、时间显示程序、日期显示程序,秒表显示程序,时间调整程序、闹钟调整程序、定时调整程序,延时程序等。运用这种方法,关键在于各模块的兼容和配合,若各模块不匹配会出现意想不到的错误。
首先,在编程之前必须了解硬件结构尤其是各引脚的用法,以及内部寄存器、存储单元的用法,否则,编程无从下手,电路也无法设计。这是前期准备工作。第二部分是硬件部分:依据想要的功能分块设计设计,比如输入需要开关电路,输出需要显示驱动电路和数码管电路等。第三部分是软件部分:先学习理解C语言的编程方法再根据设计的硬件电路进行分块的编程调试,最终完成程序设计。第四部分是软件画图部分:设计好电路后进行画图,包括电路图和仿真图的绘制。第五部分是软件仿真部分:软硬件设计好后将软件载入芯片中进行仿真,仿真无法完成时检查软件程序和硬件电路并进行修改直到仿真成功。第六部分是硬件实现部分:连接电路并导入程序检查电路,若与设计的完全一样一般能实现想要的功能。最后进行功能扩展,在已经正确的设计基础上,添加额外的功能!
五,实验要求实现
A.电路设计
1. 整体设计
此次设计主要是应用单片机来设计电子时钟,硬件部分主要分以下电路模块:显示电路用lcd1602显示,年份,月份,星期,小时、分钟和秒(日),使电路更加简单。单片机采用AT89S51系列,这种单片机应用简单,适合电子钟设计。
电路的总体设计框架如下:
2. 分块设计
模块电路主要分为:输入部分、输出部分、复位和晶振电路。
2.1 输入部分
输入信号主要是各种模式选择和调整信号,由按键开关提供。以下为输入部分样例:
在本实验中主要用用P3口输入按键信号,还用到了特殊的P0口。对于P0口,由于其存在高阻状态,为了实现开关功能,给其添加上拉电阻,具体如下图所示:
2.2 输出部分
本电路的输出信号LCD的写入命令和写入数据,闹铃脉冲信号。
闹铃由P1.5端输出,模块如下:
日期时间由LCD1602输出,模块如下:
2.3 晶振与复位电路
本实验单片机时钟用内部时钟,模块如下:
复位电路为手动复位构成,模块如下:
B.程序设计
B.1 程序总体设计
本实验用汇编程序完成.
程序总的流程图如下:
B.2 程序主要模块
中断服务程序:
/******************一秒定时中断函数*****************/
void timer0() interrupt 1 using 1
{
ET0=0; //关闭定时器T0中断允许位
TR0=0; //关闭定时器T0
jiamiao++;
TH0=(65536-50000)/256; //设定每次中断间隔50ms
TL0=(65536-50000)%256;
TR0=1; //启动定时器T0
ET0=1; //打开定时器T0中断允许位
}
本实验中,计数器T0有运用,其中T0中断为时钟定时所用,T1中断用于秒表的准确性保证。T0的定时长度为0.05s,工作于方式1,计数1次,时长1us,故计数器计数20次,进入中断,装满定时器需要0.05s的时间,从而20次中断为一秒,一秒之后,判断是否到60秒,若不到则秒加一,然后返回,若到,则秒赋值为0,分加一,依次类推。包括日期显示的功能也是如此。另外,由于要实现倒计时功能,因此在中断程序中还要加入加一的寄存器,需要时将其进行显示。
程序中日历的实现较为复杂,要考虑平年,闰年,特殊的2月,每月的天数的不尽相同。具体的逻辑判断方法为:首先,要考虑年份是不是闰年,闰年的判断方法是:将年份除以100,若能整除,则将年份除以400,若还能整除,则为闰年,若不能,则为平年;若不能被100整除,则判断是否能被4整除,若能,则为闰年,若不能则为平年。只有2月与平、闰年相关,因此在闰年和平年的子程序中,要判断是不是2月,若是则在相应的年中进行日期的增加,若不是则转入平时的月份。其中1、3、5、7、8、10、12月是每月31天,4、6、9、11月为每月30天。
显示子程序:
/********刷新液晶屏显示内容子函数*********/
void brush_lcd()
{
static uchar old_second=0x01;
if(dis_val[6]!=old_second)
{
old_second=dis_val[6]; //刷新原来的"秒"为新"秒"值
in_command(0x80); //设定第一行字符串起始显示位置
in_data('2'); //年的千位
in_data('0'); //年的百位
in_data(num_tab[dis_val[0]/16]); //显示"年"
in_data(num_tab[dis_val[0]%16]);
in_data('-'); //显示分隔符
in_data(num_tab[dis_val[1]/16]); //显示"月"
in_data(num_tab[dis_val[1]%16]);
in_data('-'); //显示分隔符
in_data(num_tab[dis_val[2]/16]); //显示"日"
in_data(num_tab[dis_val[2]%16]);
in_data(' '); //显示分隔符
in_data('['); //显示分隔符
week_disp(dis_val[3]); //LCD1602显示星期值
in_data(']'); //显示分隔符
in_command(0xc0); //设定第二行字符串起始显示位置
in_data('-'); //显示分隔符
in_data('-'); //显示分隔符
in_data('-'); //显示分隔符
in_data('-'); //显示分隔符
in_data(num_tab[dis_val[4]/16]); //显示"时"
in_data(num_tab[dis_val[4]%16]);
in_data(':'); //显示分隔符
in_data(num_tab[dis_val[5]/16]); //显示"分"
in_data(num_tab[dis_val[5]%16]);
in_data(':'); //显示分隔符
in_data(num_tab[dis_val[6]/16]); //显示"秒"
in_data(num_tab[dis_val[6]%16]);
in_data('-'); //显示分隔符
in_data('-'); //显示分隔符
in_data('-'); //显示分隔符
in_data('-'); //显示分隔符
}
}
本程序通过Keil单片机开发平台实现程序的编译,链接,生成HEX文件。程序再编译过程中可以发现错位,并及时改正,在设计时非常重要,使错误被扼杀在摇篮中。
五.实验总结及感想
一分耕耘,一分收获。只有亲自用实践来验证这句话,在能得其要领。经过这次单片机课程设计,我从一个单片机实践的门外汉,已经越升为略知一二的新手。虽然还有很多有关单片机的应用有待学习,但万变不离其宗,只要深入了解单片的原理,全部知识点,各个细节,一切设计皆有可能。
在实验的开始几天,基本上没有收获,不知何从下手,不知所措。为了看得更远,不妨站在前人的肩膀上,我在整体思路模糊的情况下,在网上大量招资粮,各种与电子时钟相关的文章,我阅读了不少。随着涉猎的点滴积累,我对电子时钟的设计方案已经慢慢酝酿而成。有了方向和不少知识储备后,在接下来的几天,几乎每天都有突破,虽然有时只是一句程序的修改或诞生,但那种收获的感觉很暖人心。
实验中遇到了不少问题,接下来总结一下,共同探讨。
1, P0口开关问题。P0口比较特殊,它存在高阻态,要使其输入不是高电平就是低电平,就要接上拉电阻,给其高电平输入。
以上就是实验中遇到的主要问题,基本上都找到了相应的解决之道。整个实验的过程就是一个解决问题的过程,每天都解决一些问题,我的实验也就解决了,当然结果不重要,功利化的追求结果,会使人浮躁,还是享受那份疑难迎刃而解的快感吧!
全部完整代码:
此代码未经本人优化,可以根据自己的需求优化代码。盗版不究,可直接引用。
/****************************************************************/
基于STC89S52单片机以及液晶1602显示的万年历项目
/***************************************************************/
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
/***************液晶1602相关参数***************/
#define data_port P0 //液晶屏指令、数据通信接口
sbit rs=P1^0; //液晶屏寄存器选择接口(rs=0时选择指令寄存器,rs=1时选择数据寄存器)
sbit rw=P1^1; //液晶屏读写选择接口(rw=0时选择写入,rw=1时选择读出)
sbit en=P1^2; //液晶屏使能接口(en=0时通信接口中断,en=1时通信接口接通)
uchar code line1_str[]={"----Welcome!----"};//液晶屏第一行要显示的字符串
uchar code line2_str[]={" made by: MCU "};//液晶屏第二行要显示的字符串
/***************按键设置的相关参数************/
sbit timer=P1^5; //蜂鸣器
sbit sound=P3^4; //进入闹铃设置状态键
uchar sflag=0,ssflag=0; //闹铃设置标志位;闹铃工作标志位
sbit set_key=P3^7; //进入设置
sbit up_key=P3^6; //加号键
sbit cancle_key=P3^5; //完成设置键
uchar set=0; //是否进行了设置
uchar flag=0; //设置选择标志
uchar year=0x00; //"年"寄存器
uchar month=0x01; //"月"寄存器
uchar day=0x01; //"日"寄存器
uchar week=0x06; //"星期"寄存器
uchar hour; //"时"寄存器
uchar minite; //"分"寄存器
uchar second; //"秒"寄存器
uchar jiamiao=0; //加秒参数
uchar fen1,fen2; //(数据交换)分定时寄存器
uchar shi1,shi2; // (数据交换)时定时寄存器
uchar code num_tab[]={"0123456789"}; //液晶屏要显示的数字表
uchar dis_val[7]={0x00,0x01,0x01,0x06,0x00,0x00,0x00};//依次存储:年,月,日,星期,时,分,秒
/******************子函数部分*****************/
void lcd_int(); //初始化1602液晶
void welcome(); //欢迎界面
void in_command(uchar com); //向液晶屏输入命令
void in_data(uchar dat); //向液晶屏输入数据
void delay(uint ms); //延时函数
void key(); //按键设置函数
uchar calculate_week(); //星期计算函数
void week_disp(uchar x); //LCD1602显示星期值子函数声明
void lcd_disp_string(uchar str[]); //液晶屏显示一串字符子函数声明
void brush_lcd(); //刷新液晶屏显示内容子函数声明
void run(); //万年历正常运行函数
/**********************************************/
void main()
{
TMOD=0x01; //0000 0001 使用定时器T0的模式1(16位模式)
TH0=(65536-50000)/256; //设定每次中断间隔50ms
TL0=(65536-50000)%256;
jiamiao=1;
EA=1; //打开总中断允许
ET0=1; //打开定时器T0中断允许位
TR0=1; //启动定时器T0
lcd_int();
welcome();
delay(1000);
while(1)
{
key();
if(jiamiao==20)
{
second++;
dis_val[6]=((second/10)<<4)|(second%10); //刷新"秒"
jiamiao=0;
run();
}
if(flag==0)
{
if(dis_val[0]==0x00 && dis_val[1]==0x01 && dis_val[2]==0x01)//2000年1月1日为星期六
{dis_val[3]=0x06;}
brush_lcd(); //刷新液晶屏显示内容
}
if(hour==shi2 && minite==fen2 &&ssflag==1)
{
timer=0;
}
else
{
timer=1;
}
}
}
/********延时子函数************/
void delay(uint ms)
{
uchar i;
while(ms--)
{
for(i=0;i<244;i++);
}
}
/************LCD初始化*****************/
void lcd_int()
{
delay(30); //延时15MS,等待LCD初始化
in_command(0x01); //清显示屏
in_command(0x38); //8位通信,2行显示,5*7点阵
in_command(0x0c); //开显示,关光标,关闪烁
in_command(0x06); //字符不动,光标右移动,地址加一
}
/**********液晶屏显示一串字符**********/
void lcd_disp_string(uchar str[])
{
uchar i=0;
while(str[i]!='\0')
{
in_data(str[i]); //显示数据(字符)
i++;
}
}
/***************欢迎界面函数***************/
void welcome()
{
uchar i;
in_command(0x80); //设定第一行字符串起始显示位置
while(line1_str[i]!='\0')
{
delay(100);
in_data(line1_str[i]); //显示数据(字符)
i++;
}
i=0;
in_command(0xc0); //设定第二行字符串起始显示位置
while(line2_str[i]!='\0')
{
delay(100);
in_data(line2_str[i]); //显示数据(字符)
i++;
}
}
/********向液晶屏输入命令子函数************/
void in_command(uchar com)
{
delay(2);
en=0;//关闭通信,为设置参数做准备
rs=0;//选择指令寄存器
rw=0;//写入液晶
_nop_();
data_port=com;
en=1;//开始通信
_nop_();
en=0;//关闭通信,为设置参数做准备
}
/********向液晶屏输入数据子函数************/
void in_data(uchar dat)
{
delay(2);
en=0;//关闭通信,为设置参数做准备
rs=1;//选择数据寄存器
rw=0;//写入液晶
_nop_();
data_port=dat;
_nop_();
en=1;//开始通信
_nop_();
en=0;//关闭通信,为设置参数做准备
}
/***********计算星期值子函数**************/
uchar calculate_week()
{
uint days_number; //存储天数值
uchar i;
if(year>=1)
{
days_number=(((year-1)/4)+1); //从00年到year-1年的闰年个数
days_number=days_number+(year*365); //从00年到year-1年的总天数
}
else
{
days_number=0;
}
for(i=1;i<month;i++)
{
switch(i)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:days_number+=31;//大月31天
break;
case 4:
case 6:
case 9:
case 11:days_number+=30;//小月30天
break;
case 2: if(year%4==0) //闰年2月29天
{days_number+=29;}
else //平年2月28天
{days_number+=28;}
break;
}
}
days_number+=day; //加上本月日期
if((days_number+5)%7==0) //计算现在的星期值,并返回其值
{return(7);}
else
{return((days_number+5)%7);}
}
/*********LCD1602显示星期值子函数************/
void week_disp(uchar x)
{
switch(x)
{
case 1: lcd_disp_string("MON"); //显示"星期一"
break;
case 2: lcd_disp_string("TUE"); //显示"星期二"
break;
case 3: lcd_disp_string("WED"); //显示"星期三"
break;
case 4: lcd_disp_string("THU"); //显示"星期四"
break;
case 5: lcd_disp_string("FRI"); //显示"星期五"
break;
case 6: lcd_disp_string("SAT"); //显示"星期六"
break;
case 7: lcd_disp_string("SUN"); //显示"星期日"
break;
}
}
/*****************按键设置函数**************/
void key()
{
if(set_key==0) //检测"设置"键是否按下
{
delay(5); //延时消抖
if(set_key==0)
{
ET0=0; //打开定时器T0中断允许位
TR0=0; //启动定时器T0
if(flag<6)
{flag++;}
else
{flag=0;}
switch(flag)
{
case 0: if(set==1) //检测时间是否更改
{
set=0; //时间更改标志复位
dis_val[0]=((year/10)<<4)|(year%10); //刷新"年"
dis_val[1]=((month/10)<<4)|(month%10); //刷新"月"
dis_val[2]=((day/10)<<4)|(day%10); //刷新"日"
dis_val[3]=week; //刷新"星期"
dis_val[4]=((hour/10)<<4)|(hour%10); //刷新"时"
dis_val[5]=((minite/10)<<4)|(minite%10); //刷新"分"
dis_val[6]=((second/10)<<4)|(second%10); //刷新"秒"
}
in_command(0x0c); //开显示,关光标,关闪烁
break;
case 1: in_command(0x83); //设定显示(光标)位置----"年"低位闪烁
in_command(0x0d); //开显示,关光标,开闪烁
year=((dis_val[0]>>4)*10)+(dis_val[0]&0x0f); //预设调节变量初始值为当前时刻
month=((dis_val[1]>>4)*10)+(dis_val[1]&0x0f);
day=((dis_val[2]>>4)*10)+(dis_val[2]&0x0f);
hour=((dis_val[4]>>4)*10)+(dis_val[4]&0x0f);
minite=((dis_val[5]>>4)*10)+(dis_val[5]&0x0f);
second=((dis_val[6]>>4)*10)+(dis_val[6]&0x0f);
break;
case 2: in_command(0x86); //设定显示(光标)位置----"月"低位闪烁
break;
case 3: in_command(0x89); //设定显示(光标)位置----"日"低位闪烁
break;
case 4: in_command(0xc5); //设定显示(光标)位置----"时"低位闪烁
break;
case 5: in_command(0xc8); //设定显示(光标)位置----"分"低位闪烁
break;
case 6: in_command(0xcb); //设定显示(光标)位置----"秒"低位闪烁
break;
}
while(set_key==0);
}
}
if(up_key==0 && flag!=0) //检测"设置时间"启动时,"上升"键是否按下
{
delay(5); //延时消抖
if(up_key==0)
{
switch(flag)
{
case 1: if(sflag==1)
{break;}
if(year<99)
{year++;}
else
{year=0;}
if(year%4!=0 && month==2)//平年的2月
{
if(day>28)
{
day=28;
in_command(0x88); //设定显示(光标)位置----"日"高位
in_data(num_tab[day/10]); //修正"日"
in_data(num_tab[day%10]);
}
}
week=calculate_week(); //计算星期值
in_command(0x8c); //设定显示(光标)位置----"星期"
week_disp(week); //LCD1602显示星期值
in_command(0x82); //设定显示(光标)位置----"年"高位
in_data(num_tab[year/10]); //显示正在调节的"年"
in_data(num_tab[year%10]);
in_command(0x83); //设定显示(光标)位置----"年"低位闪烁
break;
case 2: if(sflag==1)
{break;}
if(month<12)
{month++;}
else
{month=1;}
if(month==4 || month==6 || month==9 || month==11)
{
if(day>30)
{
day=30;
in_command(0x88);//设定显示(光标)位置----"日"高位
in_data(num_tab[day/10]); //修正"日"
in_data(num_tab[day%10]);
}
}
if(month==2)
{
if(year%4!=0) //平年
{
if(day>28)
{
day=28;
in_command(0x88); //设定显示(光标)位置----"日"高位
in_data(num_tab[day/10]); //修正"日"
in_data(num_tab[day%10]);
}
}
else //闰年
{
if(day>29)
{
day=29;
in_command(0x88); //设定显示(光标)位置----"日"高位
in_data(num_tab[day/10]); //修正"日"
in_data(num_tab[day%10]);
}
}
}
week=calculate_week();//计算星期值
in_command(0x8c); //设定显示(光标)位置----"星期"
week_disp(week); //LCD1602显示星期值
in_command(0x85); //设定显示(光标)位置----"月"高位
in_data(num_tab[month/10]); //显示正在调节的"月"
in_data(num_tab[month%10]);
in_command(0x86); //设定显示(光标)位置----"月"低位闪烁
break;
case 3: if(sflag==1)
{break;}
if(month==4 || month==6 || month==9 || month==11)
{
if(day<30)
{day++;}
else
{day=1;}
}
else if(month==2)
{
if(year%4!=0) //平年
{
if(day<28)
{day++;}
else
{day=1;}
}
else //闰年
{
if(day<29)
{day++;}
else
{day=1;}
}
}
else
{
if(day<31)
{day++;}
else
{day=1;}
}
week=calculate_week();//计算星期值
in_command(0x8c); //设定显示(光标)位置----"星期"
week_disp(week); //LCD1602显示星期值
in_command(0x88); //设定显示(光标)位置----"日"高位
in_data(num_tab[day/10]); //显示正在调节的"日"
in_data(num_tab[day%10]);
in_command(0x89); //设定显示(光标)位置----"日"低位闪烁
break;
case 4: if(hour<23)
{
if(sflag==1) //完成闹钟状态下的数值变换,并保存设置前的状态
{
shi1=hour;
hour++;
shi2=hour;
}
else
{hour++;}
}
else
{hour=0;}
in_command(0xc4); //设定显示(光标)位置----"时"高位
in_data(num_tab[hour/10]); //显示正在调节的"时"
in_data(num_tab[hour%10]);
in_command(0xc5); //设定显示(光标)位置----"时"低位闪烁
break;
case 5: if(minite<59)
{
if(sflag==1) //完成闹钟状态下的数值变换,并保存设置前的状态
{
fen1=minite;
minite++;
fen2=minite;
}
else
{minite++;}
}
else
{minite=0;}
in_command(0xc7); //设定显示(光标)位置----"分"高位
in_data(num_tab[minite/10]); //显示正在调节的"分"
in_data(num_tab[minite%10]);
in_command(0xc8); //设定显示(光标)位置----"分"低位闪烁
break;
case 6: if(second<59)
{second++;}
else
{second=0;}
in_command(0xca); //设定显示(光标)位置----"秒"高位
in_data(num_tab[second/10]); //显示正在调节的"秒"
in_data(num_tab[second%10]);
in_command(0xcb); //设定显示(光标)位置----"秒"低位闪烁
break;
}
set=1; //时间更改标志置位
while(up_key==0);
}
}
if(sound==0 && flag!=0)//启动定时状态标志
{
sflag=1;
}
if(cancle_key==0 && flag!=0) //检测"设置时间"启动时,"完成"键是否按下
{
delay(5); //延时消抖
if(cancle_key==0)
{
set=0; //时间更改标志复位
flag=0; //设置按键状态值复位
in_command(0x0c); //开显示,关光标,关闪烁
while(cancle_key==0);
if(sflag==1) //判断是否进行过闹钟定时设置
{
minite=fen1;
hour=shi1;
ssflag=1; //启动闹钟工作标志
sflag=0; //关闭闹钟定时状态标志
}
ET0=1; //打开定时器T0中断允许位
TR0=1; //启动定时器T0
}
}
}
/********刷新液晶屏显示内容子函数*********/
void brush_lcd()
{
static uchar old_second=0x01;
if(dis_val[6]!=old_second)
{
old_second=dis_val[6]; //刷新原来的"秒"为新"秒"值
in_command(0x80); //设定第一行字符串起始显示位置
in_data('2'); //年的千位
in_data('0'); //年的百位
in_data(num_tab[dis_val[0]/16]); //显示"年"
in_data(num_tab[dis_val[0]%16]);
in_data('-'); //显示分隔符
in_data(num_tab[dis_val[1]/16]); //显示"月"
in_data(num_tab[dis_val[1]%16]);
in_data('-'); //显示分隔符
in_data(num_tab[dis_val[2]/16]); //显示"日"
in_data(num_tab[dis_val[2]%16]);
in_data(' '); //显示分隔符
in_data('['); //显示分隔符
week_disp(dis_val[3]); //LCD1602显示星期值
in_data(']'); //显示分隔符
in_command(0xc0); //设定第二行字符串起始显示位置
in_data('-'); //显示分隔符
in_data('-'); //显示分隔符
in_data('-'); //显示分隔符
in_data('-'); //显示分隔符
in_data(num_tab[dis_val[4]/16]); //显示"时"
in_data(num_tab[dis_val[4]%16]);
in_data(':'); //显示分隔符
in_data(num_tab[dis_val[5]/16]); //显示"分"
in_data(num_tab[dis_val[5]%16]);
in_data(':'); //显示分隔符
in_data(num_tab[dis_val[6]/16]); //显示"秒"
in_data(num_tab[dis_val[6]%16]);
in_data('-'); //显示分隔符
in_data('-'); //显示分隔符
in_data('-'); //显示分隔符
in_data('-'); //显示分隔符
}
}
/******************一秒定时中断函数*****************/
void timer0() interrupt 1 using 1
{
ET0=0; //关闭定时器T0中断允许位
TR0=0; //关闭定时器T0
jiamiao++;
TH0=(65536-50000)/256; //设定每次中断间隔50ms
TL0=(65536-50000)%256;
TR0=1; //启动定时器T0
ET0=1; //打开定时器T0中断允许位
}
/********************万年历正常运行函数********************/
void run()
{
if(second>=59)
{
minite++;
second=0x00;
}
if(minite>=59)
{
hour++;
minite=0x00;
}
if(hour>=23)
{
day++;
hour=0x00;
}
if(month==4 || month==6 || month==9 || month==11)
{
if(day>=30)
{day=0x01;month++;}
}
if(month==2)
{
if(year%4!=0) //平年
{
if(day>=28)
{day=0x01;month++;}
}
else //闰年
{
if(day>=29)
{
day=0x01;
month++;
}
}
}
else
{
if(day>=31)
{day=1;month++;}
}
if(month>=12)
{month=0x01;year++;}
dis_val[0]=((year/10)<<4)|(year%10); //刷新"年"
dis_val[1]=((month/10)<<4)|(month%10); //刷新"月"
dis_val[2]=((day/10)<<4)|(day%10); //刷新"日"
dis_val[3]=week; //刷新"星期"
dis_val[4]=((hour/10)<<4)|(hour%10); //刷新"时"
dis_val[5]=((minite/10)<<4)|(minite%10); //刷新"分"
dis_val[6]=((second/10)<<4)|(second%10); //刷新"秒"
}
基于单片机电子时钟的设计绪论单片机自20世纪70年代问世以来以其极高的性能价格比受到人们的重视和关注应用很广发展很快单片机体积小重…
科技创新实践[数字时钟设计][用AT89S52单片机设计电子时钟的实验报告]目录单片机的个性化电子钟设计报告1一、设计背景1二、作…
单片机电子时钟的设计目录1引言12设计任务与要求221设计题目222设计要求23系统的功能分析与设计方案331系统的主要功能332…
电子时钟实验报告全部代码在文档末尾51单片机LCD1602液晶显示屏平台下编程实现可直接编译运行目录一实验目的1二实验要求2三实验…
第一部分设计任务和要求11单片机课程设计内容利用STC89C51单片机和LCD1602电子显示屏实现电子时钟可由按键进行调时和12…
JINGCHUUNIVERSITYOFTECHNOLOGY单片机原理及应用课程设计报告题目电子时钟专业电气工程及其自动化班级20x…
单片机原理与应用课程设计与实现实训报告专业自动化年级班级姓名实训时间实训地点指导教师一实训题目基于51单片机电子时钟设计设计要求1…
第一部分设计任务和要求11单片机课程设计内容利用STC89C51单片机和LCD1602电子显示屏实现电子时钟可由按键进行调时和12…
基于单片机电子时钟的设计绪论单片机自20世纪70年代问世以来以其极高的性能价格比受到人们的重视和关注应用很广发展很快单片机体积小重…
单片机课程设计电子钟一实现功能1能够实现准确计时以数字形式显示时分秒的时间2小时以24小时计时形式分秒计时为60进位能够调节时钟时…
一6该课程设计是利用MCS51单片机内部的定时计数器中断系统以及行列键盘和LED显示器等部件设计一个单片机电子时钟设计的电子时钟通…