基于51单片机的可预置分秒倒计时装置

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

1.设计方法
本次课程设计的题目是设计并实现可编程倒计时装置。

具体要求是按秒倒计时并键盘预置分、秒各两位数,键控启动计时,数码管显示倒计时;计时器归零时输出一音频信号。

根据实验要求选用AT89C52单片机作为最基本的部件,包括数码管部分,蜂鸣器部分,矩阵键盘部分等几大模块,以下依次进行介绍。

1.1 硬件简介
(1)AT89C52
AT89C52是一个低电压,高性能CMOS 8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元。

AT89C52为8 位通用微处理器,采用工业标准的C51内核,在内部功能及管脚排布上与通用的8xc52 相同,其主要用于会聚调整时的功能控制。

引脚图如下:
图一PDIP封装的AT89C52引脚图
该单片机的功能包括对会聚主IC 内部寄存器、数据RAM及外部接口等功能部件的初始化,会聚调整控制,会聚测试图控制,红外遥控信号IR的接收解码及与主板CPU通信等。

主要管脚有:XTAL1(19脚)和XTAL2(18脚)为振荡器输入输出端口,外接12MHz晶振。

RST(9脚)为复位输入端口,外接电阻电容组成的复位电路。

VCC(40脚)为供电端口,接+5V电源的一端,GND(20脚)为接地端,接地。

P0~P3为可编程通用I/O 脚,在本设计中,P0端口(32~39 脚)被定义为数码管数据输入端口,分别与数码管的相应功能管脚相连接。

P2端口外接一个74LS373对控制信号进行锁存,然后从P2口的低四位输出到数码管的片选
端,进行对四位数码管的选择。

P3口中的P3.0接蜂鸣器的使能端,控制蜂鸣器的选通。

(2)时钟振荡器
AT89C52中有一个用于构成内部振荡器的高增益反相放大器,引脚XTAL1和XTAL2分别是该放大器的输入端和输出端。

这个放大器与作为反馈元件的片外石英晶体或陶瓷谐振器一起构成自激振荡器。

外接石英晶体(或陶瓷谐振器)及电容C1、C2接在放大器的反馈回路中构成并联振荡电路。

对外接电容C1、C2虽然没有十分严格的要求,但电容容量的大小会轻微影响振荡频率的高低、振荡器工作的稳定性、起振的难易程序及温度稳定性,如果使用石英晶体,电容使用30pF ±10pF,而如使用陶瓷谐振器建议选择40pF±10pF。

(3)键盘按键电路
矩阵键盘:为了节省I/O口,通常将按键排列成矩阵形式,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。

本设计采用4*4矩阵电路,包括0~9十个数字,设置,启动,暂停,左移,右移和确定这十六个按键。

P1.0~P1.3为列扫描,P1.4~P1.7为行扫描。

(4)数码管
图二数码管简介图
如图所示,数码管主要有两种形式,共阴极和共阳极。

共阴极的数码管就是公共端接地,共阳极的数码管就是公共端接电源。

本次设计采用的是共阳极的设计方案。

1.2 设计思路
在本设计中:
(1)4x4矩阵键盘,有数字0-9输入,可以方便快捷的预置分秒,抛弃了‘分’‘秒’按键,采用‘左’
‘右’按键,使得预置数值时更加方便,可以随心所以左右移动,选择输入。

另增加一个暂停键,功能是使得再倒计时的过程中,随时暂停,再按启动键时,倒计时继续开始。

(2)数码管采用的是4位一体共阳数码管,有4
个位选端,来分别选择4个数码管。

(3)蜂鸣器采用的是有源蜂鸣器,无源蜂鸣器和有源蜂鸣器的区别在于,有源蜂鸣器只需加入一个高电平就可以发声,而无源蜂鸣器需要输入一定频率的脉冲才可以发声,从而选择简单高效的有源蜂鸣器。

1.3 设计框图
图三 设计框图
2 系统硬件设计图
根据思路设计出的硬件如下图所示
路连接图
3 程序
设计框

4 资源分配表
(1)P0.0-p0.7 上先接一个排阻,作为上拉电阻。

如下图所示
图五 上拉电阻
然后引脚接入共阳数码管的段选端,如下图所示:
P 0.0P 0.1P 0.2P 0.3P 0.4P 0.5P 0.6P 0.7
Q 0Q 1Q 2Q 3
共阳极数码管
图六 数码管
(2)P1.0-P1.7 接矩阵键盘,其中p1.0-p1.3为列扫描,p1.4-p.17为行扫描 如下图所示:
P 1.0
P 1.1
P 1.2
P 1.3
P1.4
P1.5
P1.6
P1.7
1
2
3
4
5
6
789左右启动
设置
确定
暂停
图七 矩阵键盘连接图
(3)P2口的p2.0-p2.3先接入一个74ls373锁存器,之所以要接这个锁存器是因为我们选用的是共阳数码管,需要大驱动,直接用单片机接的话带不起来,亮度会很低。

如下图:
图八 锁存器
之后373的Q 输出端的q0-q3再接入供养数码管的位选端,分别选中4个数码管,高电平有效,如图4.3所示。

(4)P3口的p3.0接入蜂鸣器,输入一个低电平,蜂鸣器便发声。

5 源程序
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit P3_0=P3^0;
char seg_n[4]={10,10,10,10}; //设置阿拉伯数字表示
uchar seg_code[10]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98}; //共阳码表
uchar seg[4]={0xff,0xff,0xff,0xff}; //设置值全局变量段值
uchar num[4]={0,0,0,0}; //位是否赋值标志位
uchar key_num=50;
uint rupt;
uint buz;
/***************延时函数***************/
void delay1ms(void) //误差0us
{
unsigned char a,b,c;
for(c=1;c>0;c--)
for(b=142;b>0;b--)
for(a=2;a>0;a--);
}
void delay500ms(void) //误差0us
{
unsigned char a,b,c;
for(c=23;c>0;c--)
for(b=152;b>0;b--)
for(a=70;a>0;a--);
}
void delay20ms(void) //误差0us
{
unsigned char a,b;
for(b=215;b>0;b--)
for(a=45;a>0;a--);
}
/***************中断函数***************/
void Timer1Interrupt(void) interrupt 3 //中断1MS
{
TH1 = 0x0FC;
TL1 = 0x18;
rupt++;
}
/***************动态扫描数码管**************/
void seg_scan(uchar chose) //chose 选择闪烁显示或不闪烁,1为闪烁,0为不闪
{
uint i=0 ;
uint j=0 ;
for(;j<125;j++)
{
for(i=0;i<4;i++)
{
P2=0x01;
P2=_crol_(P2,i);
P0=seg[i];
delay1ms();
P0=0xff; //段值清零,防止乱码
}
if(chose==0) j=125; //如果为0,选择为不闪模式,跳出循环
}
if(chose==1) delay500ms(); //选择为闪烁模式,执行闪烁延时500ms
}
/***************键盘扫描***************/
void keyboard_scan()
{
uchar x=50;
uchar i=0; //i为行,j为列
uchar j=0;
uchar r[4]={0xe0,0xd0,0xb0,0x70};
uchar l[4]={0x0e,0x0d,0x0b,0x07};
uchar key[4][4]={{9,8,7,14},{6,5,4,24},{3,2,1,34},{0,42,43,44}}; //按键值,代码P1=0xf0;
for(i=0;i<4;i++)
{
if(P1==r[i]) //确定在第I行
{
P1=0x0f;
for(j=0;j<4;j++)
{
if(P1==l[j]) //确定在第J列
{
P1=0xf0;
delay20ms(); //延时20MS 再测
for(i=0;i<4;i++)
{
if(P1==r[i]) //确定在第I行
{
P1=0x0f;
for(j=0;j<4;j++)
{
if(P1==l[j]) //确定在第J列
x=key[i][j];
}
}
}
}
}
}
}
key_num=x;
}
/***************"设置按键"键盘扫描***************/
void setup()
{
uchar i=0;
seg[0]=0x88;
seg[1]=0x88;
seg[2]=0x88;
seg[3]=0x88;
for(;i!=1;)
{
seg_scan(0);
keyboard_scan();
if(key_num==44) i=1;
}
}
/***************赋值函数***************/
void seg_value()
{
uchar y[4]={0,0,0,0};
char i=0;
seg[0]=0xff; //数码管清零
seg[1]=0xff;
seg[2]=0xff;
seg[3]=0xff;
for(i=0;;i++)
{
for(num[i]=0 ; num[i]!=1;)
{
key_num=50; //key_num需要赋值一个无关值,以免出现乱码
seg[i]=0x88; //赋值为A,30为学林值,88为共阳值
seg_scan(1);
keyboard_scan();
switch(key_num) //检测是否有功能键按下
{
case 24 :if(y[0]&y[1]&y[2]&y[3])
{
seg[i]=seg_code[seg_n[i]]; //清掉A
goto label_reset;
}
break; //4位都赋值完毕,且按下确定键,则进入下一阶段
case 42 :if(seg_n[i]==10) {seg[i]=0xff;} //左移键按下
else{seg[i]=seg_code[seg_n[i]];}
i--;break;
case 43 :if(seg_n[i]==10) {seg[i]=0xff;} //右移键按下
else{seg[i]=seg_code[seg_n[i]];}
i++;break;
case 44 :goto label_reset;break;
}
if(i==-1) i=3;
if(i==4) i=0;
num[i]=0; //只允许在赋值0-9的情况下跳出本循环,左移右移不跳出
if(key_num<10)
{ if((i==0)||(i==2))
{
if(key_num<6) //在第一位和第三位赋值必须小于6
{
seg_n[i]=key_num; seg[i]=seg_code[key_num]; //若无功能键按下,则赋值
num[i]=1;y[i]=1; //标志位置1,进入下一位赋值
}
else{}
}
else
{
seg_n[i]=key_num; seg[i]=seg_code[key_num]; //若无功能键按下,则赋值
num[i]=1;y[i]=1; //标志位置1,进入下一位赋值
}
}
}
}
label_reset: {}
}
/***************"启动按键"检测程序***************/
void start()
{
uchar i=0 ;
for(i=0;i!=1;)
{
seg_scan(0);
keyboard_scan();
if(key_num==34) i=1;
}
}
/***************倒计时程序***************/
void cutdown()
{
label:
for(;seg_n[0]>=0;)
{
for(;seg_n[1]>=0;)
{
for(;seg_n[2]>=0;)
{
for(;seg_n[3]>=0;)
{
for(TR1=1;TR1!=0;)
{
for(;rupt>=1000;) //中断1次1MS,1000次为1S;
{
rupt=0;
TR1=0;
seg[3]=seg_code[seg_n[3]];
seg[2]=seg_code[seg_n[2]];
seg[1]=seg_code[seg_n[1]];
seg[0]=seg_code[seg_n[0]];
seg_n[3]=(seg_n[3]-1);
}
seg_scan(0);
keyboard_scan();
if(key_num==14)
{
while(1)
{
seg_scan(0);
key_num=50;
keyboard_scan();
if(key_num==34) goto label;
}
}
}
}
seg_n[3]=9;
seg_n[2]=(seg_n[2]-1);
}
seg_n[2]=5;
seg_n[1]=(seg_n[1]-1);
}
seg_n[1]=9;
seg_n[0]=(seg_n[0]-1);
}
}
/***************蜂鸣器警报***************/
void buzzer()
{
P3_0=0;
}
/******************************主程序***************************/ void main()
{ TMOD = 0x10;
TH1 = 0x0FC; //TR1用来倒计时1S中断
TL1 = 0x18;
EA = 1;
ET1 = 1;
begin: setup(); //循环键盘扫描_'设置'按键
seg_value(); //赋值阶段
if(key_num==44) goto begin; //如果设置键按下,从头开始运行程序seg[1]=(seg[1] & 0x7f) ; //点亮第二位小数点,表明设置值完成,此后不能再设置
start(); //循环键盘扫描_'启动'按键
cutdown(); //倒计时程序
buzzer(); //蜂鸣器鸣声程序
}
6 性能分析
本次设计,主要突出的是友好的用户体验,以及稳定的系统。

特别是在赋值阶段,可以重复多次覆盖赋值。

(1)在进入赋值阶段,会有闪烁显示,这表示正在赋值,也与我们日常生活中用的电子手表同宗同源,电子手表在调整时间时,也会闪烁显示,这使得用户可以很好的接受本系统,有一个好的用户体验。

(2)在闪烁的时候,当前赋值位都会闪烁显示A,从而表明正在赋值的地方。

这让用户更加直观的了解程序的运行,非常方便的知道所赋值的地方。

(3)在赋值阶段,可以不断的覆盖赋值,方便用户修改定时的时间,还可以直接点击设定,把所有的值清空,重新赋值,这都是很人性化的。

(4)在赋值完成,点击确定后,会点亮在分秒数码管中间的小数点,友好的指示出了赋值完成。

(5)在点击启动按键后,在小数点消失的时刻便是计时开始的时刻,将程序内部的运行表明的一清二楚。

(6)本设计在要求的基础上还增加了暂停按键,随时点击暂停键,便暂停倒计时,直至点击启动按键。

(7)在倒计时完成后,数码管依然会显示,并伴随蜂鸣器警报。

另外倒计时采用中断计时,可以保证倒计时1S的准确性。

图九实物图
7 心得体会
8 参考文献
[1] 余永权.AT89系列单片机应用技术.北京:北京航空航天大学出版社,2002
[2] 沈红卫.单片机应用系统设计实例与分析. 北京:北京航空航天大学出版社,2003
[3] 吴金戎.8051单片机实践与应用.北京:清华大学出版社,2002
[4] 胡汉才.单片机原理及系统设计.北京:清华大学出版社,2002
[5] 何希才.新型集成电路应用实例[M].北京:电子工业出版社,2002.。

相关文档
最新文档