单片机 定时器 课程设计.docx
《单片机 定时器 课程设计.docx》由会员分享,可在线阅读,更多相关《单片机 定时器 课程设计.docx(16页珍藏版)》请在冰点文库上搜索。
单片机定时器课程设计
单片机课程设计
说明书
题目名称:
定时器时钟数码管显示
姓名:
班级:
学号:
日期:
2012年6月29日
单片机时钟
1.摘要:
时钟是人类生活中必不可少的的工具,本设计从日常生活中的事物入手,通过对时钟计时器的设计,让我们认识到单片机已经深入到我们生活的每个领域,该设计不仅可以锻炼我们的动手能力,而且可以加深我们对单片机的认识和激发我们队位置科学领域的探索。
利用单片机实现教学数字时钟计时的主要功能,采用独立式按键进行时间调整,其中AT89C52是核心元件同是采用数码管LED动态显示“时”,“分”,“秒”的现代计时装置。
与传统机械表相比,它具有走时精确,显示直观等特点。
它的计时周期为24小时,显满刻度为“23时59分59秒”。
该系统同时具有硬件设计简单,工作稳定性高,价格低廉等优点。
1.1.关键词
AT89C52、LED显示
1.2.功能要求
1)七位数码管显示时、分、秒,以24小时运算
2)可实现时分调整
1.3.主要硬件元器件的介绍
1.3.151单片机芯片
根据初步这几方案的分析,设计这样一个简单的应用系统,可以选择带有EPROM的单片机,应用程序直接存储在片内,不用在外部扩展程序存储器,电路可以简化。
该系统的设计我们采用8051芯片。
下图所示为双列直插式封装的8051AH芯片的管脚图,功能如下:
8051AH芯片的管脚图
1.电源管脚
Vcc(40脚):
接+5V;Vss(20)脚:
接地。
2.时钟信号管脚
X1(19脚),X2(18脚):
外部时钟信号的两个管脚。
3.控制线
1)RESET(9脚):
用作复位输入端。
2)EA’/VP(31脚):
EA’为访问内部或外部程序存储器的选择信号。
对片内EPROM编程时,此管脚(作VP)接入21V编程电压。
3)ALE/P’(30脚):
当访问外部存储器时,ALE信号的负跳变将P0口上的低8位地址送入锁存器。
当对内EPROM编程时,该管脚(P’)用于输入编程脉冲。
4)PSEN’(29脚):
外部程序存储器读选通控制信号。
4.输入/输出口线
1)P0口(32-39脚):
8路漏极开路型双向并行I/O口。
在访问外部存储器时,P0口作为低8位地址/数据总线复用口,通过分时操作,先传送低8位地址,利用ALE信号的下降沿将地址锁存,然后作为8位数据总线使用,用来传送8位数据。
在对片内EPROM编程时,P0口接受指令代码;而在内部程序校验时,则输出指令代码,并要求外接上拉电阻。
外部不拓展位单片应用,则作双向I/O口用,P0口能以吸收电流的方式驱动8个LSTTL负载。
2)P1口(1-8脚):
具有内部上拉电阻的8位准双向I/O口。
在对片内EPROM编程及校验时,它接收低8位地址。
P1口能驱动4个LETTL负载。
3)P2口(21-28脚):
具有内部上拉电阻的8位准双向I/O口。
在外接存储器时,P2口作为高8位地址总线。
在对片内EPROM编程及校验时,它接受高8位地址。
P2口驱动4个LETTL负载。
4)P3口(10-17脚):
8位带有内部上拉电阻的准双向I/O口。
每一位有具有如下的特殊功能(或称第二功能):
P3.0(RXD):
串行输入端
P3.1(TXD):
串行输入端
P3.2(INT0’):
外部中断0输入端,低电平有效。
P3.3(INT1’):
外部中断1输入端,低电平有效。
P3.4(T0):
定时/计数器0外部事件计数输入端。
P3.5(T1):
定时/计数器1外部事件计数输入端。
P3.6(WR’):
外部数据存储器写选通信号,低电平有效。
P3.7(RD’):
外部数据存储器读选通信号,低电平有效。
1.3.2LED数码管
数码管是单片机系统中常用的显示界面,可以显示“1、2、3、4、5、6、7、8、9、0”和十六进制中的“A、B、C、D、E、F”及小数点“.”,数码管怎样来显示1,2,3,4呢?
数码管实际上是由7个发光管组成8字形构成的,加上小数点就是8个。
分别被命名为A,B,C,D,E,F,G,H(小数点)和DP。
如果要显示一个数字2,那么A,B,G,E,D这5个段的发光管亮,C,F,H不亮,就可以了。
LED数码管内部结构
由图可知:
要使数码管发光必须满足两个条件,一、COM端为高电平。
二、在A-G端的对应部分输入低电平。
这样电流流过相应的字段,数码管就会显示相应的字符了!
由于数码管”A,B,C……DP”端都并在一起,要使每一个数码管显示各自的内容,使用动静态扫描方式都可以。
下面是共阴极数码管字型码表:
51单片机结构框图
1.4.程序设计
1.4.1.主程序
设计中计时采用定时器T0中断完成。
主程序循环调用显示子程序和查键,当端口有开关按下时,转入相应的功能程序。
流程图如图2-4-1所示。
图1-4-1主程序流程
1.4.2.显示子程序
显示子程序每次显示6个连续内存单元的十进制BCD码数据。
由于采用7段共阳LED数码管动态扫描实现数据显示,显示十进制BCD码数据对应段码存放在ROM中。
流程图如图2-4-2所示。
显示时取内存地址中数据,然后查表得对应显示段码从P0口输出,P2口将为对应的数码管供电,于是数码管就会显示该地址单元的数据。
图2-4-2显示子程序
1.4.3.定时器T0中断服务程序
定时溢出中断周期设为50MS,中断进入后先进行定时中断初值校正,当中断累加到20次时,对秒计数单元进行加1操作。
时钟最大计时值为23时59分59秒。
#7FH存放“熄灭符”数据,用于时间调整时的闪烁功能。
在计数单元中,采用十进制BCD码计数,满十进位。
流程图如图3.3所示
在程序中采用12MHZ晶振频率,精度为1MS,定时初值为50MS,用循环程序进行20次循环可到1S。
当1S到时调用加1程序并判断秒、分是否为60,当秒为60时,秒清零,分加1;当分为60时,分清零。
终端结束时,分时计时单元数据移入对应显示单元。
图3.3定时器T0中断服务程序
1.5.按键设置
采用共阳七段LED显示器,其管脚a-g,ap与单片机AT89C52的P0口相连;P0口输出段码数据;为保证其输出的电平和LED显示器所需的电平相匹配;P2.0---P2.5作为列扫描输出;P3.0,P3.1,P3.2,P3.3,接4个按钮开关,用于调时.
1.6.数码管显示结果
此图显示的是:
17点12分03秒
1.7.程序
#include//包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#defineKeyPortP3//定义按键端口
#defineDataPortP0//定义数据端口程序中遇到DataPort则用P0替换
sbitLATCH1=P2^2;//定义锁存使能端口段锁存
sbitLATCH2=P2^3;//位锁存
unsignedcharhour,minute,second;//定义时分秒
bitUpdateTimeFlag;//定义读时间标志
unsignedcharcodedofly_DuanMa[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//显示段码值0~9
unsignedcharcodedofly_WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//分别对应相应的数码管点亮,即位码
unsignedcharTempData[8];//存储显示值的全局变量
voidDelayUs2x(unsignedchart);//us级延时函数声明
voidDelayMs(unsignedchart);//ms级延时
voidDisplay(unsignedcharFirstBit,unsignedcharNum);//数码管显示函数
unsignedcharKeyScan(void);//键盘扫描
voidInit_Timer0(void);//定时器初始化
/*------------------------------------------------
主函数
------------------------------------------------*/
voidmain(void)
{
unsignedcharnum;
Init_Timer0();
while
(1)//主循环
{
num=KeyScan();
switch(num)
{
case1:
hour++;if(hour==24)hour=0;//正常时间小时加1
break;
case2:
hour--;if(hour==255)hour=23;//正常时间小时减1
break;
case3:
minute++;if(minute==60)minute=0;//分钟加1
break;
case4:
minute--;if(minute==255)minute=59;//分钟减1
break;
default:
break;
}
if(UpdateTimeFlag==1)
{
UpdateTimeFlag=0;
TempData[0]=dofly_DuanMa[hour/10];//时//数据的转换,因我们采用数码管0~9的显示,将数据分开
TempData[1]=dofly_DuanMa[hour%10];
TempData[2]=0x40;//加入"-"
TempData[3]=dofly_DuanMa[minute/10];//分
TempData[4]=dofly_DuanMa[minute%10];
TempData[5]=0x40;
TempData[6]=dofly_DuanMa[second/10];//秒
TempData[7]=dofly_DuanMa[second%10];
}
}
}
/*------------------------------------------------
uS延时函数,含有输入参数unsignedchart,无返回值
unsignedchar是定义无符号字符变量,其值的范围是
0~255这里使用晶振12M,精确延时请使用汇编,大致延时
长度如下T=tx2+5uS
------------------------------------------------*/
voidDelayUs2x(unsignedchart)
{
while(--t);
}
/*------------------------------------------------
mS延时函数,含有输入参数unsignedchart,无返回值
unsignedchar是定义无符号字符变量,其值的范围是
0~255这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
voidDelayMs(unsignedchart)
{
while(t--)
{
//大致延时1mS
DelayUs2x(245);
DelayUs2x(245);
}
}
/*------------------------------------------------
显示函数,用于动态扫描数码管
输入参数FirstBit表示需要显示的第一位,如赋值2表示从第三个数码管开始显示
如输入0表示从第一个显示。
Num表示需要显示的位数,如需要显示99两位数值则该值输入2
------------------------------------------------*/
voidDisplay(unsignedcharFirstBit,unsignedcharNum)
{
staticunsignedchari=0;
DataPort=0;//清空数据,防止有交替重影
LATCH1=1;//段锁存
LATCH1=0;
DataPort=dofly_WeiMa[i+FirstBit];//取位码
LATCH2=1;//位锁存
LATCH2=0;
DataPort=TempData[i];//取显示数据,段码
LATCH1=1;//段锁存
LATCH1=0;
i++;
if(i==Num)
i=0;
}
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
voidInit_Timer0(void)
{
TMOD|=0x01;//使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
//TH0=0x00;//给定初值
//TL0=0x00;
EA=1;//总中断打开
ET0=1;//定时器中断打开
TR0=1;//定时器开关打开
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
voidTimer0_isr(void)interrupt1
{
staticunsignedintnum,i;
TH0=(65536-2000)/256;//重新赋值2ms
TL0=(65536-2000)%256;
Display(0,8);//调用数码管扫描
i++;
if(i==10)//20ms更新一次
{
i=0;
UpdateTimeFlag=1;//更新时间志位置1
}
num++;
if(num==500)//大致1s
{
num=0;
second++;
if(second==60)//秒到60,分钟加1
{
second=0;
minute++;
if(minute==60)//分钟到60,小时加1
{
minute=0;
hour++;
if(hour==24)//小时到24,回零
hour=0;
}
}
}
}
/*------------------------------------------------
按键扫描函数,返回扫描键值
------------------------------------------------*/
unsignedcharKeyScan(void)
{
unsignedcharkeyvalue;
if(KeyPort!
=0xff)
{
DelayMs(10);
if(KeyPort!
=0xff)
{
keyvalue=KeyPort;
while(KeyPort!
=0xff);
switch(keyvalue)
{
case0xfe:
return1;break;
case0xfd:
return2;break;
case0xfb:
return3;break;
case0xf7:
return4;break;
case0xef:
return5;break;
case0xdf:
return6;break;
case0xbf:
return7;break;
case0x7f:
return8;break;
default:
return0;break;
}
}
}
return0;
}
1.8心得体会:
通过本次课程设计,我学习到了很多,也收获了很多。
总结如下:
一、我对单片机的理论知识有了进一步的掌握,对单片机的原理和实际应用有了更多的理解和掌握。
二、我对单片机的C语言编程有了更深刻的认识和更扎实的掌握,我们不断修改,不断尝试,对源代码各个模块的函数都有了一个非常深入的掌握。
三、理论与实践相结合才能更好的理解和掌握所学的知识。