简易数字钟附详细代码.docx
《简易数字钟附详细代码.docx》由会员分享,可在线阅读,更多相关《简易数字钟附详细代码.docx(16页珍藏版)》请在冰豆网上搜索。
简易数字钟附详细代码
简易数字钟
一、实验内容
本实验的主要内容是根据提供的元器件,设计一个简易数字钟。
1、要求准确显示“时”、“分”、“秒”,24小时制;
2、具有校时功能,用户可以修改“时”、“分”,且互不影响;
3、时间显示可以实现12/24小时制切换;
设计应包括方案选择、硬件系统设计、软件系统设计等。
硬件设计包括单片
机最小系统设计、单元电路设计;软件设计包括模块化层次结构图、程序流程图
等。
通过调试与仿真,进一步完善设计,使之达到实验要求,使其更接近于实际
产品。
最后要求撰写设计实验报告,把设计内容,调试过程及性能指标的测试进
行全面总结,把实践内容上升到理论高度。
1数字钟硬件部分示意图
该简易数字钟硬件部分主要由晶振、手动复位、单片机AT89C51、数码管显示、时间调整按键模块组成。
框图如下:
图3.1数字钟硬件系统示意图
2数字钟软件部分组成框图
2.1程序总流程图
2.2时钟显示程序流程
图3.324小时时钟
3各部分模块介绍
3.1单片机AT89C51芯片分析
AT89C51单片机引脚图如下:
图4.1AT89C51引脚图
3.2晶振电路模块
在AT89C51芯片内部有一个高增益反相放大器,其输入端为芯片引脚XTAL1,输出端为引脚XTAL2。
而在芯片内部,XTAL1和XTAL2之间跨接晶体振荡器和微调电容,从而构成一个稳定的自激振荡器。
时钟电路产生的振荡脉冲经过触发器进行二分频之后,才成为单片机的时钟脉冲信号。
图4.2晶振电路
3.3复位电路模块
单片机复位的条件是:
必须使RST/VPD或RST引脚加上两个机器周期(即24个振荡周期)的高电平。
例如,若时钟频率为12MHz,每个机器周期为1us,则只需要2us以上时间的高电平,在RST引脚出现高电平后的第二个机器周期执行复位。
本次设计采用手动按钮复位。
手动按钮复位需要人为在复位输入端RST上加入高电平。
一般采用的办法是在RST端和正电源Vcc之间接一个按钮。
当人为按下按钮时,则Vcc的+5V电平就会直接加到RST端。
手动按钮复位的电路如所示。
由于人的动作再快也会使按钮保持接通达数十毫秒,所以,完全能够满足复位的时间要求。
图4.3复位电路
3.4显示模块
现在的字符型液晶模块已经是单片机应用设计中最常用的信息显示器件了。
1602型LCD显示模块具有体积小,功耗低,显示内容丰富等特点。
1602型LCD可以显示2行16个字符,有8位数据总线D0~D7和RS,R/W,EN三个控制端口,工作电压为5V,并且具有字符对比
度调节和背光功能。
图4.4显示模块
3.5按键模块
本次设计要求了该简易数字钟必须具备时、分、秒的调整功能。
故必须接入4个简单的按键,功能如图所示:
4、总仿真电路图
5、程序代码
1、main.c
#include
#include
sbits1=P1^5;//定义按键--功能键
sbits2=P1^6;//定义按键--增大键
sbits3=P1^7;//定义按键--减小键
sbits4=P1^0;//定义按键--12/24时制转换
unsignedcharcount,s1num;
unsignedcharmiao,fen,shi;
unsignedchara[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23};
unsignedcharb[]={0,1,2,3,4,5,6,7,8,9,10,11,12,1,2,3,4,5,6,7,8,9,10,11};
unsignedcharcodetable[]="2011-11-24Thurs";
voidwrite_sfm(unsignedcharadd,unsignedchardate);
voidkeyscan();
voidmain()
{
unsignedcharnum;
LCD1602();
Init_Lcd();
shi=16;//初始化小时变量值
fen=48;//初始化分钟变量值
miao=50;//初始化秒变量值
count=0;
s1num=0;
for(num=0;num<16;num++)//显示年月日星期
{
Write_Lcd(table[num],1);
Delay_us(5000);
}
Write_Lcd(0x80+0x40+6,0);//写出时间显示的两个冒号
Write_Lcd(':
',1);
Delay_us(5000);
Write_Lcd(0x80+0x40+9,0);
Write_Lcd(':
',1);
Delay_us(5000);
write_sfm(10,miao);//分别送去液晶显示
write_sfm(7,fen);
write_sfm(4,shi);
TMOD=0x01;//设置定时器0为工作模式1
TH0=(65536-50000)/256;//定时器装初值
TL0=(65536-50000)%256;
EA=1;//开总中断
ET0=1;//开定时器0中断
TR0=1;//启动开定时器0
while
(1)
{
keyscan();//不停地检测按键是否被按下
}
}
voidwrite_sfm(unsignedcharadd,unsignedchardate)//写时分秒函数
{
unsignedcharshi,ge;
shi=date/10;
ge=date%10;
Write_Lcd(0x80+0x40+add,0);//设置显示的位置
Write_Lcd(0x30+shi,1);//送去液晶显示十位
Write_Lcd(0x30+ge,1);//送去液晶显示个位
}
voidkeyscan()
{
if(s1==0)
{
Delay_us(5000);
if(s1==0)
{
s1num++;
while(!
s1);
if(s1num==1)//第一次被按下时
{
TR0=0;
Write_Lcd(0x80+0x40+10,0);
Write_Lcd(0x0f,0);//光标开始闪烁
}
if(s1num==2)
{
Write_Lcd(0x80+0x40+7,0);//第二次被按下时光标闪烁定位到分钟位置
}
if(s1num==3)
{
Write_Lcd(0x80+0x40+4,0);//第三次被按下时光标闪烁定位到小时位置
}
if(s1num==4)//第四次被按下
{
s1num=0;//记录按键数清零
Write_Lcd(0x0c,0);//取消光标闪烁
TR0=1;//启动定时器,使时钟开始走
}
}
}
if(s1num!
=0)//只有按键被按下后,增大或减小键才有效
{
if(s2==0)
{
Delay_us(5000);
if(s2==0)//增加键确认被按下
{
while(!
s2);
if(s1num==1)//若功能键第一次按下
{
miao++;//则调整秒加1
if(miao==60)//若满60后将清零
miao=0;
write_sfm(10,miao);//每调节一次送液晶显示一下
Write_Lcd(0x80+0x40+10,0);//显示位置重新回到调节处
}
if(s1num==2)//若功能键第二次按下
{
fen++;//则调整分钟加1
if(fen==60)//若满60后将清零
fen=0;
write_sfm(7,fen);//每调节一次送液晶显示一下
Write_Lcd(0x80+0x40+7,0);//显示位置重新回到调节处
}
if(s1num==3)//若功能键第三次按下
{
shi++;//则调整小时加1
if(shi==24)//若满24后将清零
shi=0;
write_sfm(4,shi);//每调节一次送液晶显示一下
Write_Lcd(0x80+0x40+4,0);//显示位置重新回到调节处
}
}
}
if(s3==0)
{
Delay_us(5000);
if(s3==0)//减小键确认被按下
{
while(!
s3);//按键释放
if(s1num==1)//若功能键第一次按下
{
miao--;//则调整秒减1
if(miao==-1)//若减到负数则将其重新设置为59
miao=59;
write_sfm(10,miao);//每调节一次送液晶显示一下
Write_Lcd(0x80+0x40+10,0);//显示位置重新回到调节处
}
if(s1num==2)//若功能键第二次按下
{
fen--;//则调整分钟减1
if(fen==-1)//若减到负数则将其重新设置为59
fen=59;
write_sfm(7,fen);//每调节一次送液晶显示一下
Write_Lcd(0x80+0x40+7,0);//显示位置重新回到调节处
}
if(s1num==3)//若功能键第三次按下
{
shi--;//则调整小时减1
if(shi==-1)//若减到负数则将其重新设置为23
shi=23;
write_sfm(4,shi);//每调节一次送液晶显示一下
Write_Lcd(0x80+0x40+4,0);//显示位置重新回到调节处
}
}
}
}
}
voidtimer0()interrupt1//定时器0中断服务程序
{
TH0=(65536-50000)/256;//再次装定时器初值
TL0=(65536-50000)%256;
count++;//20次50毫秒为1秒
if(count==20)
{
count=0;
miao++;
if(miao==60)//秒加到60则进位分钟
{
miao=0;//同时秒数清零
fen++;
if(fen==60)//分钟加到60则进位小时
{
fen=0;//同时分钟数清零
shi++;
if(shi==24)//小时加到24则小时清零
{
shi=0;
}
write_sfm(4,a[shi]);
}
write_sfm(7,fen);//分钟若变化则重新写入
}
if(s4==0)//12/24时制切换
{
Delay_us(5000);
if(s4==0)
write_sfm(4,b[shi]);//小时若变化则重新写入(12小时制)
}
else
write_sfm(4,a[shi]);//小时若变化则重新写入(24小时制)
write_sfm(10,miao);//秒若变化则重新写入
}
}
2、Lcd.c
sbitRS=P1^4;
sbitRW=P1^3;
sbitEN=P1^2;
voidLCD1602(void);
voidRead_Busy(void);
voidWrite_Lcd(unsignedcharValue,biti);
voidInit_Lcd(void);
voidDelay_us(unsignedinti);
//---------------------------------------
//名称:
1602初始化函数
//-----------------------------------------
voidInit_Lcd(void)
{
Delay_us(15000);
Write_Lcd(0x38,0);
Delay_us(5000);
Write_Lcd(0x38,0);
Delay_us(5000);
Write_Lcd(0x38,0);
Write_Lcd(0x08,0);
Write_Lcd(0x01,0);
Write_Lcd(0x06,0);
Write_Lcd(0x0c,0);
}
//---------------------------------------
//名称:
1602显示初始化函数
//-----------------------------------------
voidLCD1602(void)
{
EN=0;
RS=1;
RW=1;
P2=0xFF;
}
//---------------------------------------
//名称:
1602忙检测函数
//-----------------------------------------
voidRead_Busy(void)
{
unsignedchari=255;
P2=0xFF;
RS=0;
RW=1;
EN=1;
while((i--)&&(P2&0x80));
EN=0;
}
//---------------------------------------
//名称:
写指令、写数据函数
//-----------------------------------------
voidWrite_Lcd(unsignedcharValue,biti)//i=0写指令.i=1写数据;
{
Read_Busy();
P2=Value;
RS=i;
RW=0;
EN=1;
EN=0;
}
//---------------------------------------
//名称:
延时函数
//-----------------------------------------
voidDelay_us(unsignedintk)///延时k微妙(us)
{
while(--k);
}