单片机电子时钟设计报告Word文档下载推荐.docx
《单片机电子时钟设计报告Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《单片机电子时钟设计报告Word文档下载推荐.docx(28页珍藏版)》请在冰豆网上搜索。
A.电路设计
1.整体设计
此次设计主要是应用单片机来设计电子时钟,硬件部分主要分以下电路模块:
显示电路用lcd1602显示,年份,月份,星期,小时、分钟和秒(日),使电路更加简单。
单片机采用AT89S51系列,这种单片机应用简单,适合电子钟设计。
电路的总体设计框架如下:
2.分块设计
模块电路主要分为:
输入部分、输出部分、复位和晶振电路。
输入部分
输入信号主要是各种模式选择和调整信号,由按键开关提供。
以下为输入部分样例:
在本实验中主要用用P3口输入按键信号,还用到了特殊的P0口。
对于P0口,由于其存在高阻状态,为了实现开关功能,给其添加上拉电阻,具体如下图所示:
输出部分
本电路的输出信号LCD的写入命令和写入数据,闹铃脉冲信号。
闹铃由端输出,模块如下:
日期时间由LCD1602输出,模块如下:
晶振与复位电路
本实验单片机时钟用内部时钟,模块如下:
复位电路为手动复位构成,模块如下:
B.程序设计
程序总体设计
本实验用汇编程序完成.
程序总的流程图如下:
程序主要模块
中断服务程序:
/******************一秒定时中断函数*****************/
voidtimer0()interrupt1using1
{
ET0=0;
验总结及感想
一分耕耘,一分收获。
只有亲自用实践来验证这句话,在能得其要领。
经过这次单片机课程设计,我从一个单片机实践的门外汉,已经越升为略知一二的新手。
虽然还有很多有关单片机的应用有待学习,但万变不离其宗,只要深入了解单片的原理,全部知识点,各个细节,一切设计皆有可能。
在实验的开始几天,基本上没有收获,不知何从下手,不知所措。
为了看得更远,不妨站在前人的肩膀上,我在整体思路模糊的情况下,在网上大量招资粮,各种与电子时钟相关的文章,我阅读了不少。
随着涉猎的点滴积累,我对电子时钟的设计方案已经慢慢酝酿而成。
有了方向和不少知识储备后,在接下来的几天,几乎每天都有突破,虽然有时只是一句程序的修改或诞生,但那种收获的感觉很暖人心。
实验中遇到了不少问题,接下来总结一下,共同探讨。
1,P0口开关问题。
P0口比较特殊,它存在高阻态,要使其输入不是高电平就是低电平,就要接上拉电阻,给其高电平输入。
以上就是实验中遇到的主要问题,基本上都找到了相应的解决之道。
整个实验的过程就是一个解决问题的过程,每天都解决一些问题,我的实验也就解决了,当然结果不重要,功利化的追求结果,会使人浮躁,还是享受那份疑难迎刃而解的快感吧!
全部完整代码:
此代码未经本人优化,可以根据自己的需求优化代码。
盗版不究,可直接引用。
/****************************************************************/
基于STC89S52单片机以及液晶1602显示的万年历项目
/***************************************************************/
#include<
>
#defineucharunsignedchar
#defineuintunsignedint
/***************液晶1602相关参数***************/
#definedata_portP0//液晶屏指令、数据通信接口
sbitrs=P1^0;
//液晶屏寄存器选择接口(rs=0时选择指令寄存器,rs=1时选择数据寄存器)
sbitrw=P1^1;
//液晶屏读写选择接口(rw=0时选择写入,rw=1时选择读出)
sbiten=P1^2;
//液晶屏使能接口(en=0时通信接口中断,en=1时通信接口接通)
ucharcodeline1_str[]={"
----Welcome!
----"
};
//液晶屏第一行要显示的字符串
ucharcodeline2_str[]={"
madeby:
MCU"
//液晶屏第二行要显示的字符串
/***************按键设置的相关参数************/
sbittimer=P1^5;
//蜂鸣器
sbitsound=P3^4;
//进入闹铃设置状态键
ucharsflag=0,ssflag=0;
//闹铃设置标志位;
闹铃工作标志位
sbitset_key=P3^7;
//进入设置
sbitup_key=P3^6;
//加号键
sbitcancle_key=P3^5;
//完成设置键
ucharset=0;
//是否进行了设置
ucharflag=0;
//设置选择标志
ucharyear=0x00;
//"
年"
寄存器
ucharmonth=0x01;
//"
月"
ucharday=0x01;
//"
日"
ucharweek=0x06;
星期"
寄存器
ucharhour;
//"
时"
ucharminite;
分"
ucharsecond;
秒"
ucharjiamiao=0;
//加秒参数
ucharfen1,fen2;
//(数据交换)分定时寄存器
ucharshi1,shi2;
//(数据交换)时定时寄存器
ucharcodenum_tab[]={"
09"
//液晶屏要显示的数字表
uchardis_val[7]={0x00,0x01,0x01,0x06,0x00,0x00,0x00};
//依次存储:
年,月,日,星期,时,分,秒
/******************子函数部分*****************/
voidlcd_int();
//初始化1602液晶
voidwelcome();
//欢迎界面
voidin_command(ucharcom);
//向液晶屏输入命令
voidin_data(uchardat);
//向液晶屏输入数据
voiddelay(uintms);
//延时函数
voidkey();
//按键设置函数
ucharcalculate_week();
//星期计算函数
voidweek_disp(ucharx);
//LCD1602显示星期值子函数声明
voidlcd_disp_string(ucharstr[]);
//液晶屏显示一串字符子函数声明
voidbrush_lcd();
//刷新液晶屏显示内容子函数声明
voidrun();
//万年历正常运行函数
/**********************************************/
voidmain()
TMOD=0x01;
//00000001使用定时器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;
}
/********延时子函数************/
voiddelay(uintms)
uchari;
while(ms--)
for(i=0;
i<
244;
i++);
}
/************LCD初始化*****************/
voidlcd_int()
delay(30);
//延时15MS,等待LCD初始化
in_command(0x01);
//清显示屏
in_command(0x38);
//8位通信,2行显示,5*7点阵
in_command(0x0c);
//开显示,关光标,关闪烁
in_command(0x06);
//字符不动,光标右移动,地址加一
/**********液晶屏显示一串字符**********/
voidlcd_disp_string(ucharstr[])
uchari=0;
while(str[i]!
='
\0'
)
in_data(str[i]);
//显示数据(字符)
i++;
/***************欢迎界面函数***************/
voidwelcome()
in_command(0x80);
//设定第一行字符串起始显示位置
while(line1_str[i]!
{
delay(100);
in_data(line1_str[i]);
//显示数据(字符)
i=0;
in_command(0xc0);
//设定第二行字符串起始显示位置
while(line2_str[i]!
in_data(line2_str[i]);
/********向液晶屏输入命令子函数************/
voidin_command(ucharcom)
delay
(2);
en=0;
//关闭通信,为设置参数做准备
rs=0;
//选择指令寄存器
rw=0;
//写入液晶
_nop_();
data_port=com;
en=1;
//开始通信
/********向液晶屏输入数据子函数************/
voidin_data(uchardat)
rs=1;
//选择数据寄存器
data_port=dat;
/***********计算星期值子函数**************/
ucharcalculate_week()
uintdays_number;
//存储天数值
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;
month;
i++)
switch(i)
case1:
case3:
case5:
case7:
case8:
case10:
case12:
days_number+=31;
//大月31天
break;
case4:
case6:
case9:
case11:
days_number+=30;
//小月30天
case2:
if(year%4==0)//闰年2月29天
{days_number+=29;
else//平年2月28天
{days_number+=28;
days_number+=day;
//加上本月日期
if((days_number+5)%7==0)//计算现在的星期值,并返回其值
{return(7);
{return((days_number+5)%7);
}
/*********LCD1602显示星期值子函数************/
voidweek_disp(ucharx)
switch(x)
case1:
lcd_disp_string("
MON"
);
//显示"
星期一"
break;
case2:
TUE"
星期二"
case3:
WED"
星期三"
case4:
THU"
星期四"
case5:
FRI"
星期五"
case6:
SAT"
星期六"
case7:
SUN"
星期日"
}
/*****************按键设置函数**************/
voidkey()
if(set_key==0)//检测"
设置"
键是否按下
delay(5);
//延时消抖
if(set_key==0)
ET0=0;
TR0=0;
if(flag<
6)
{flag++;
else
{flag=0;
switch(flag)
{
case0:
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)<
}
in_command(0x0c);
break;
case1:
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]&
day=((dis_val[2]>
4)*10)+(dis_val[2]&
hour=((dis_val[4]>
4)*10)+(dis_val[4]&
minite=((dis_val[5]>
4)*10)+(dis_val[5]&
second=((dis_val[6]>
4)*10)+(dis_val[6]&
case2:
in_command(0x86);
case3:
in_command(0x89);
case4:
in_command(0xc5);
case5:
in_command(0xc8);
case6:
in_command(0xcb);
}
while(set_key==0);
if(up_key==0&
flag!
=0)//检测"
设置时间"
启动时,"
上升"
if(up_key==0)
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_