资源描述
成绩
课 程 设 计
课程名称
单片机原理和应用课程设计
课题名称
时钟跑表设计
专 业
班 级
学 号
姓 名
指导老师
林国汉、王迎旭、汪超、李晓秀等
5月22日
电气信息学院
课程设计任务书
课题名称
时钟跑表设计
姓 名
专业
班级
学号
指导老师
林国汉
课程设计时间
5月22日-6月3日
一、任务及要求
设计任务:
本课题要求以MCS-51系列单片机为关键,设计一个数字时钟。
(1) 含有时钟和跑表功效,用LED或液晶显示器进行显示;
(2) 含有时钟调整功效
(3) * 含有闹钟功效,且闹钟时间可调整。
(4) *其它功效
设计要求:
(1)确定系统设计方案;
(2)进行系统硬件设计;
(3)完成应用程序设计;
(4)应用系统硬件和软件调试。
二、进度安排
第一周:
周一:集中部署课程设计任务和相关事宜,查资料确定系统总体方案。
周二~周三:完成硬件设计和电路连接
周四~周日:完成软件设计
第二周:
周一~周三:程序调试
周四~周五:设计汇报撰写。周五进行答辩和设计结果检验。
三、参考资料
1、王迎旭等.单片机原理及及应用[M]. 2版.机械工业出版社,
2、胡汉才.单片机原理及其接口技术[M].3版.清华大学出版社,.
3、戴灿金.51单片机及其C语言程序设计开发实例[M].清华大学出版社,
目 录
第一章 总体方案设计 1
1.1 设计方案设计任务和要求 1
1.2 设计思绪及系统框架图 1
第二章 硬件电路设计 3
2.1 单片机AT89C51 3
2.2 矩阵键盘电路 4
2.3 蜂鸣器电路 4
2.4 LED数码管显示电路 5
第三章 软件设计 6
3.1 系统主程序 6
3.2 矩阵键盘功效程序 6
3.4 定时功效程序 8
第四章 调试 10
4.1 系统调试方法 10
4.2 调试结果 10
第五章 总结 11
附录 12
附录A 电路仿真原理图 12
附录B 程序清单 13
第一章 总体方案设计
1.1设计任务和要求
设计任务:
本课题要求以MCS-51系列单片机为关键,设计一个数字时钟。
(1) 含有时钟和跑表功效,用LED或液晶显示器进行显示;
(2) 含有时钟调整功效
(3) * 含有闹钟功效,且闹钟时间可调整。
(4) *其它功效
设计要求:
(1) 确定系统设计方案;
(2) 进行系统硬件设计;
(3) 完成应用程序设计;
(4) 应用系统硬件和软件调试。
1.2 设计思绪及系统框架图
我们采取是AT89C51作为时钟控制芯片。此次方案关键由时钟模块、秒表模块和闹钟模块组成,其中时钟模块包含时钟显示功效、时钟调整功效和时钟暂停功效,秒表模块包含秒表开启功效、秒表暂停功效、秒表时间存放功效和秒表回显功效,闹钟模块包含闹钟调整功效、闹钟显示功效和闹钟存放功效。时钟经过定时器T0对时、分、秒数值进行操作,而且秒计算到60时候,要自己清零并向分进1,分计算到60时候,要自己清零并向时进1,时进到24时候,要清零,这么才能进行循环计时。秒表模块需要重新显示一个秒表界面,同时也应该需要经过另外一个定时器T1对秒表进行操作,从而确保在秒表界面,时钟显示模块时间还在进行。闹钟模块则需要设计闹钟时间,当设计闹钟时间和时钟时间相等,蜂鸣器响起,从而达成闹钟功效,另外经过外接24c02存放芯片,将闹钟时间进行存放,且含有断电存放功效,当系统断电重新开启以后,可显示之前设定闹钟值。
另外还要实现对时间调整功效,AT89C51P1口外接一个矩阵键盘,当按下K3键时,进行时钟调整,当K3按下一次时,是对时间分钟进行调整,按下K5键数值加一,按下K6键数值减一。当按下K12键时,进行闹钟调整,当K3按下一次时,是对闹钟分钟进行调整,按下K5键数值加一,按下K6键数值减一。对于秒表模块,当按下K7键时,秒表开启,当按下K8键时,显示秒表目前值,但秒表继续走动。在秒表计时过程中,每按下一次K9键,则对秒表目前值进行存放,每按下K10键,则对存放值进行一一回显(矩阵键盘按键标号详见电路仿真图)。
在单片机内部构建两个模块:控制模块、定时模块,用以实现依据要求进行自动计数功效。单片机外部构建四个电路:矩阵键盘电路、数码管显示电路、蜂鸣器电路、24C02存放电路,用以实现对单片机内部计数选择控制、闹钟响铃、闹钟存放和时间输出正确显示。该电子时钟是显示分、时值,秒为数码表DP位闪烁一个计时装置此次计时周期设置为二十四小时。为了确保时间正常校对,在系统中设有校对按钮,用以实现对数码管显示正确调整,图1.1所表示为系统框架图。
图1.1 系统框架图
第二章 硬件电路设计
2.1 单片机AT89C51
AT89C51是一低电压、高性能CMOS8位微处理器,俗称单片机。AT89C51是一个带2K字节闪存可编程可擦除只读存放器单片机。单片机可擦除只读存放器能够反复擦除1000次。因为将多功效8位CPU和闪烁存放器组合在单个芯片中,ATMELAT89C51是一个高效微控制器。AT89C51单片机为很多嵌入式控制系统提供了一个灵活性高且价廉方案,图2.1所表示为AT89C51管脚图。
此次电路中用到单片机P0、P1、P2、P3口,所表示下面对这四个端口进行具体介绍。
P0口:P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流。当P0口管脚第一次写1时,被定义为高阻输入。P0能够用于外部程序数据存放器,它能够被定义为数据/地址低八位。在FIASH编程时,P0 口作为原码输入口,当FIASH进行校验时,P0输出原码,此时P0外部必需接上拉电阻。此次课设中P0口接是数码管8个管脚,P0^0~P0^7依次接数码管A~DP管脚。
P1口:P1口是一个内部提供上拉电阻8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是因为内部上拉缘故。在FLASH编程和校验时,P1口作为低八位地址接收。此次P1课设口接数码管6个位选端口。
图2.1 89C51引脚图
P2口:P2口为一个内部上拉电阻8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。并所以作为输入时,P2口管脚被外部拉低,将输出电流。这是因为内部上拉缘故。P2口当用于外部程序存放器或16位地址外部数据存放器进行存取时,P2口输出地址高八位。在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存放器进行读写时,P2口输出其特殊功效寄存器内容。P2口在FLASH编程和校验时接收高八位地址信号和控制信号。此次课设中P2口P2^4~P2^7分别接是数码管位选W1~W4。
P3口:此次课设中P3口P3^3和P3^4分别接是24C02SCL和SDA,P3^7接是蜂鸣器一端。
2.2 矩阵键盘电路
在此次设计中,矩阵键盘S1~S4列分别接P1^7~P1^4引脚,H1~H4行分别接是P1^3~P1^0引脚。先从P1口高四位输出高电平,低四位输出低电平,从P1口高四位读取键盘状态。再从P1口高四位输出低电平,低四位输出高电平,从P1口低四位读取键盘状态。将两次读取结果组合起来就能够得到目前按键特征编码。使用上述方法我们得到16个键特征编码。图2.2所表示为矩阵键盘接线图。
图2.2 矩阵键盘接线图
2.3 蜂鸣器电路
当初钟显示时间和闹钟存放时间相同时,P3^7引脚输出低电平,使蜂鸣器接通,发出滴滴响声,响声连续时间为20秒,20秒后P3^7引脚输出高电平,蜂鸣器关断,图2.3所表示为蜂鸣器接线图。
图2.3 蜂鸣器接线图
2.4 LED数码管显示电路
在此次设计中,采取4位数码管显示器。数码管假如根据段数分可为七段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管单元,也就是多了一个小数点显示;假如根据发光二极管单元连接方法又能够分为共阳极数码管和共阴极数码管。共阳极数码管是将全部发光二极管阳极接到一起后就形成公共阳极(COM)数码管,共阳极数码管在应用时要将公共极(COM)接到+5V,当某一字段发光二极管阴极为低电平时,对应字段就点亮,当某一字段阴极为高电平时,对应字段就不亮。共阴极数码管是将全部发光二极管阴极接到一起形成公共阴极(COM)数码管,共阴极数码管在应用时应将公共极(COM)接到地线GND上,当某一字段发光二极管阳极为高电平时,对应字段就点亮,当某一字段阳极为低电平时,对应字段就不亮。此次课设数码管选择共阳极八段数码管,图2.4所表示为LED数码管接线图。
图2.4 LED数码管接线图
第三章 软件设计
3.1 系统主程序
先对显示单元和定时器/计数器初始化,然后反复调用数码管显示模块和按键处理模块,检测矩阵按键值,则转入对应功效程序。主程序步骤图图3.1所表示。
图3.1 主程序步骤图
3.2 矩阵键盘功效程序
此次设计16个矩阵按键共用到了12个按键,每个按键全部有对应功效。K1键为时钟开启键,按下K1键后数码管显示时钟。此时按下K3键以后进行时钟调整,按一下进行分钟调整,按两下进行小时调整。接着按K5键数值加一,按K6键数值减一。每次调整分钟或小时以后全部要按K1键进行确定以后才能重新按K3键进行调整。按下K7键开启秒表,接着按下K8键,秒表暂停,但此时秒表还在走动,只是显示按键时秒表目前值。在秒表走动过程中,按下K9键则存放目前按下值,每按一下,存放一个值,按下K10键后则回显秒表之前存放值,每按一下,回显一个时间,循环显示。K11键为闹钟显示功效按键,K12为闹钟调整按键,按一下进行分钟调整,按两下进行小时调整。接着按K5键数值加一,按K6键数值减一。每次调整分钟或小时以后全部要按K11键进行确定以后才能重新按K12键进行调整。另外K2键为时钟暂停键,K4键为系统清零键。时钟模块、秒表模块和闹钟模块对应矩阵键盘功效程序步骤图分别图3.3、图3.4、图3.5所表示。
图3.3 时钟模块矩阵键盘功效步骤图 图3.4 秒表模块矩阵键盘功效步骤图
图3.5 闹钟模块矩阵键盘功效步骤图
3.3 定时功效程序
T0用于时钟定时,定时时间设为50ms,定时时间到则中止,在中止服务程序中用一个计数器对50ms计数,计20次则对秒单元加一。秒单元加到60则对分单元加一,同时秒单元清0;分单元加到60则对时单元加一,同时分单元清0;时单元加到24则对时单元清0,标志一天时间计满。T1用于秒表定时,定时时间设为20ms,定时时间到则中止,在中止服务程序中用一个计数器对20ms计数,计5次则对秒表100毫秒单元加一。100毫秒单元加到10则对秒单元加一,同时100毫秒单元清0;秒单元加到1000则自动清0。时钟秒显示为数码管第四位管子DP值闪烁,每次秒加一DP就会闪烁一次。定时器T0功效步骤图图3.4所表示,定时器T1功效步骤图图3.5所表示。
图3.4 定时器T0功效步骤图 图3.5 定时器T1功效步骤图
第四章 调试
4.1 系统调试方法
先在电脑上使用Proteus仿真软件进行电路仿真进行仿真,编程使用keil、调试工具并生成可实施文件加载到单片机中,在Proteus中点击运行,查看运行结果是否和预期要求相符,假如仿真成功,便能够到试验板上进行实物试验。
4.2 调试结果
图4.1 时钟显示调试图
图4.2 秒表显示调试图
图4.3 闹钟显示调试图
第五章 总结和体会
附录
附录A 电路仿真原理图
附录B 程序清单
#include"reg52.h"
#include"intrins.h"
#ifndef __I2C_H_
#define __I2C_H_
#define uint unsigned int
#define uchar unsigned char
uint xdata resultm[100];
uint xdata resultf[100];
uchar code duanxuan[]={ 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x7f,0x83,0xc6,0xa1,0x86,0x8e ,0xff};//共阳极0~f数码管编码
uchar code duanxuan1[]={ 0xc0-0x80,0xf9-0x80,0xa4-0x80,0xb0-0x80,0x99-0x80,0x92-0x80,0x82-0x80,0xf8-0x80,0x80-0x80,0x90-0x80,0x7f-0x80,0x83-0x80,0xc6-0x80,0xa1-0x80,0x86-0x80,0x8e-0x80 ,0xff-0x80};
uchar code weixuan[]={0xe0,0xd0,0xb0,0x70};
uchar flag3;
uchar temp,timer0_shi,timer0_fen,timer0_miao;
uchar timer1_fm,nao1,nao2,nao3,nao4;
uint timer1_zm;
uchar timer1_bw, timer1_sw, timer1_gw;
uchar c,z,k;
sbit beep =P3^7 ;
sbit scl=P3^4;
sbit sda=P3^5;
uint t0=0,t1=0;
//--定义使用IO口--//
sbit I2C_SCL = P3^4;
sbit I2C_SDA = P3^5;
void I2C_Delay10us();
void I2C_Start();
void I2C_Stop();
uchar I2C_SendByte(uchar dat, uchar ack);
uchar I2C_ReadByte();
void At24c02Write(unsigned char addr,unsigned char dat);
unsigned char At24c02Read(unsigned char addr);
#endif
void init(void)
{
TMOD=0x11;
TCON=0x01;
TH0=0x3c; //定时50ms
TL0=0x0b0;
TH1=0xb1;//定时20ms
TL1=0xe0;
EA=1;
EX0=1;
ET0=1;
ET1=1;
}
void delay(uint x) //12Mhz延时xms
{
uint i,j;
for(i=x;i>0;i--)
for(j=20;j>0;j--);
}
void smg_display(uchar dx,uchar wx)//数码管位选
{
P0=duanxuan[dx];
P2=weixuan[wx-1];
delay(1);
}
void smg_display1(uchar dx,uchar wx)//数码管位选
{
P0=duanxuan1[dx];
P2=weixuan[wx-1];
delay(1);
}
uchar keyscan()
{
uchar temp_keyvalue,temp1_keyvalue;
P1=0xf0;
delay(1);
temp_keyvalue=P1;
if(temp_keyvalue!=0xf0)
{ delay(2);
temp_keyvalue=P1;
if(temp_keyvalue!=0xf0)
{ temp1_keyvalue=temp_keyvalue&0xf0;
P1=0x0f;
delay(2);
temp_keyvalue=P1;
temp1_keyvalue=temp1_keyvalue|temp_keyvalue;
}
while(temp_keyvalue!=0x0f)
{
P1=0x0f;
temp_keyvalue=P1;
}
}
return temp1_keyvalue;
}
void naozhong(uchar s,uchar f)
{
if(s==timer0_shi&&f==timer0_fen)
{
if(timer0_miao<=20)
beep=0;
if(timer0_miao>20)
beep=1;
}
}
void disposal(void)
{ uchar hour,second,timer1_ffm;
uchar zt_bw,zt_sw,zt_gw,zt_fm;
uchar nao_fen,nao_shi;
uchar nao_gsw,nao_ggw,nao_dsw,nao_dgw;
uchar key_progress,timer0_gsw,timer0_ggw,flag1,flag2;
uchar timer0_dsw,timer0_dgw,s1,s2,f1,f2;
key_progress=keyscan();
switch(key_progress)
{ case 0xbe:// 时钟暂停
{
TR0=0;
timer0_gsw=timer0_shi/10;
timer0_ggw=timer0_shi%10;
timer0_dsw=timer0_fen/10;
timer0_dgw=timer0_fen%10;
smg_display(timer0_gsw,1);
smg_display1(timer0_ggw,2);
smg_display(timer0_dsw,3);
smg_display(timer0_dgw,4);
break;
}
case 0xee: //清零
{ TR0=0;
TR1=0;
timer1_zm=0;
timer1_fm=0;
timer0_shi=0;
timer0_fen=0;
timer0_dgw=timer0_fen%10;
timer0_gsw=timer0_shi/10;
timer0_ggw=timer0_shi%10;
timer0_dsw=timer0_fen/10;
timer0_dgw=timer0_fen%10;
smg_display(timer0_gsw,1);
smg_display1(timer0_ggw,2);
smg_display(timer0_dsw,3);
smg_display(timer0_dgw,4);
break;
}
case 0x7e://时钟开启
{ keyscan();
temp=P1;
nao1=At24c02Read(1);
nao1=At24c02Read(1);
nao2=At24c02Read(2);
nao2=At24c02Read(2);
while(temp ==0xf0)
{ TR0=1;
flag3=1;
timer0_gsw=timer0_shi/10;
timer0_ggw=timer0_shi%10;
timer0_dsw=timer0_fen/10;
timer0_dgw=timer0_fen%10;
smg_display(timer0_gsw,1);
delay(30);
smg_display1(timer0_ggw,2);
delay(30);
smg_display(timer0_dsw,3);
delay(30);
smg_display(timer0_dgw,4);
delay(30);
if((nao1||nao2)!=0)
naozhong(nao2,nao1);
temp=P1;
}
break;
}
case 0xde: // 时钟调整
{ keyscan();
flag3=0;
temp=P1;
flag2=0;
flag1++;
if(flag1>2)
flag1=2;
while(temp ==0xf0)
{
s1=timer0_gsw;
s2=timer0_ggw;
f1=timer0_dsw;
f2=timer0_dgw;
hour=s2+s1*10;
second=f2+f1*10;
smg_display(s1,1);
delay(50);
smg_display1(s2,2);
delay(50);
smg_display(f1,3);
delay(50);
smg_display(f2,4);
delay(50);
temp=P1;
}
break;
}
case 0x7d: //加时钟
{ flag3=0;
if(flag1==1||flag2==1)
second++;
if(flag1==2||flag2==2)
hour++;
if(hour>=24)
hour=0;
if(second>=60)
second=0;
keyscan();
temp=P1;
while(temp ==0xf0)
{ s1=hour/10;
s2=hour%10;
f1=second/10;
f2=second%10;
smg_display(s1,1);
delay(50);
smg_display(s2,2);
delay(50);
smg_display(f1,3);
delay(50);
smg_display(f2,4);
delay(50);
nao1=f2+f1*10;
nao2=s2+s1*10;
temp=P1;
if(keyscan()==0x7e)
{
timer0_fen=f2+f1*10;
timer0_shi=s2+s1*10;
flag1=0;
flag2=0;
}
if(keyscan()==0xdb)
{
nao_fen=f2+f1*10;
nao_shi=s2+s1*10;
flag1=0;
flag2=0;
}
}
break;
}
case 0xbd: //减时钟
{ flag3=0;
if(flag1==2||flag2==2)
{
if(hour<=0)
hour=24;
hour--;
}
if(flag1==1||flag2==1)
{
if(second<=0)
second=60;
second--;
}
keyscan();
temp=P1;
while(temp ==0xf0)
{ s1=hour/10;
s2=hour%10;
f1=second/10;
f2=second%10;
smg_display(s1,1);
delay(50);
smg_display(s2,2);
delay(50);
smg_display(f1,3);
delay(50);
smg_display(f2,4);
delay(50);
temp=P1;
nao1=f2+f1*10;
nao2=s2+s1*10;
if(keyscan()==0x7e)
{
timer0_fen=f2+f1*10;
timer0_shi=s2+s1*10;
flag1=0;
flag2=0;
}
if(keyscan()==0xdb)
{
nao_fen=f2+f1*10;
nao_shi=s2+s1*10;
flag1=0;
flag2=0;
}
}
break;
}
case 0xeb:// 闹钟调整
{ keyscan();
flag3=0;
temp=P1;
flag2++;
flag1=0;
if(flag2>2)
flag2=2;
while(temp ==0xf0)
{
nao_gsw=nao2/10;
nao_ggw=nao2%10;
if(flag2==1)
{nao_dsw=nao1/10;
nao_dgw=nao1%10;
}
nao3=nao_ggw+nao_gsw*10;
nao4=nao_dgw+nao_dsw*10;
smg_display(nao_gsw,1);
delay(50);
smg_display1(nao_ggw,2);
delay(50);
smg_display(nao_dsw,3);
delay(50);
smg_display(nao_dgw,4);
delay(50);
temp=P1;
}
break;
}
case 0xdb://闹钟确定
{ flag3=0;
keyscan();
temp=P1;
while(temp ==0xf0)
{
nao_gsw=nao2/10;
nao_ggw=nao2%10;
nao_dsw=nao1/10;
nao_dgw=nao1%10;
nao3=nao_ggw+nao_gsw*10;
nao4=nao_dgw+nao_dsw*10;
smg_display(nao_gsw,1);
delay(20);
smg_display1(nao_ggw,2);
delay(20);
smg_display(nao_dsw,3);
delay(20);
smg_display(nao_dgw,4);
delay(20);
temp=P1;
}
At24c02Write(1,nao1);
At24c02Write(1,nao1);
At24c02Write(2,nao2);
At24c02Write(2,nao2);
break;
}
case 0xdd://跑表开启
{ keyscan();
flag3=0;
temp=P1;
while(temp ==0xf0)
{
TR1=1;
timer1_bw=timer1_zm/100;
timer1_sw=(timer1_zm/10)%10;
timer1_gw=timer1_zm%100%10;
timer1_ffm=timer1_fm;
smg_display(timer1_bw,1);
delay(10);
smg_display(timer1_sw,2);
delay(10);
smg_display1(timer1_gw,3);
delay(10);
smg_display(timer1_fm,4);
delay(10);
temp=P1;
}
keyscan();
if(keyscan()==0xed)
{
zt_bw=timer1_bw;
zt_sw=timer1_sw;
zt_gw=timer1_gw;
zt_fm=timer1_fm;
}
break;
}
case 0xed:// 跑表暂停
{
flag3=0;
smg_display(zt_bw,1);
delay(20);
smg_display(zt_sw,2);
delay(20);
smg_display1(zt_gw,3);
delay(20);
smg_display(zt_fm,4);
delay(20);
break;
}
case 0x7b:// 跑表计次数
{ k++;
c=k;
z=k;
flag3=0;
keyscan();
temp=P1;
resultf[k-1]=timer1_fm;
resultm[k-1]=timer1_bw*100+timer1_sw*10+timer1_gw;
while(temp ==0xf0)
{
TR1=1;
timer1_bw=timer1_zm/100;
timer1_sw=(timer1_zm/10)%10;
timer1_gw=timer1_zm%100%10;
timer1_ffm=timer1_fm;
smg_display(timer1_bw,1);
delay(5);
smg_display(timer1_sw,2);
delay(5);
smg_display1(timer1_gw,3);
delay(5);
smg_display(timer1_fm,4);
delay(5);
temp=P1;
keyscan();
if(keyscan()==0xed)
{
zt_bw=timer1_bw;
zt_sw=timer1_sw;
zt_gw=timer1_gw;
zt_fm=timer1_fm;
}
}
keyscan();
if(keyscan()==0xbb)
k=0;
break;
}
case 0xbb:// 跑表回显
{ flag3=0;
k=0;
c--;
timer1_ffm=resultf[c];
timer1_bw=resultm[c]/100;
timer1_sw=(resultm[c]/10)%10;
timer1_gw=resultm[c]%100%10;
keyscan();
展开阅读全文