单片机倒计时器.docx
《单片机倒计时器.docx》由会员分享,可在线阅读,更多相关《单片机倒计时器.docx(18页珍藏版)》请在冰豆网上搜索。
单片机倒计时器
课程设计报告
课程名称:
单片机原理及应用课程设计
设计题目:
智能倒计时器
系别:
通信与控制工程系
专业:
电子信息工程
班级:
电信二班
学生姓名:
学号:
起止日期:
指导教师:
教研室主任:
指导教师评语:
指导教师签名:
年月日
成绩评定
项目
权重
成绩
1、设计过程中出勤、学习态度等方面
0.2
2、课程设计质量与答辩
0.5
3、设计报告书写及图纸规范程度
0.3
总成绩
教研室审核意见:
教研室主任签字:
年月日
教学系审核意见:
主任签字:
年月日
摘要
在生活和生产的各领域中,随着计算机在社会领域的渗透,单片机的应用正在不断的走向深入,同时带动传统控制检测日新月异更新。
在实时控制和自动控制的单片机应用系统中,单片机往往是作为一个核心部件来使用,仅单片机方面知识是不够的,还应根据具体硬件结构,以及针对具体应用对象特点的软件结合,以作完善。
本系统由单片机系统、矩阵式键盘和LED数码管显示系统组成。
装置利用STC89C52单片机与LED数码管显示。
通过按键控制设定倒计时时间,再通过中断控制系统开始倒计时。
为了简化电路,降低成本,采用以软件为主的的接口方法。
该系统实用、功能灵活多样,可以对计时时间进行实时控制,可以广泛的应用于各种场所的控制设备。
关键字:
STC89C52;8255A芯片;数码管;键盘;定时器
智能倒计时器
设计要求
选择5位数码管做显示,实现5种倒计时模式,通过控制按键进行选择
1、99999s-0s
2、9999s-0s
3、999s-0s
4、99s-0s
5、9s-0s
6、开始值由人工输入-0s
1方案论证
1.1方案一:
采用FPGA/PLD芯片为核心的设计
采用FPGA/PLD进行设计可能在系统功能上还可以作更多的提高,但是这个对设计成本的增加也是必然的,而且FPGA/PLD这些芯片的价格比较高,操作起来难,对于做这些功能的产品来讲有点大材小用,所以也暂时不考虑。
2.3方案二:
采用STC89C52芯片为核心的设计
采用单片机STC89C52进行控制的电路比较简单,要达到以上的功能的没有多大的问题,而且单片机取材方便,价格也比较实惠,对程序的编写和调试也比较的简单,所以各方面来讲都比较适合。
根据以上两种方案的比较,确立为方案二的STC89C52作为系统的核心元件
2硬件设计
2.3STC89C52的芯片概述
典型单片机有MCS-51、MSP430、EM78、PIC、Motorola、AVR等。
MCS-51为主流产品,MSP430为低功耗产品,功能较强,EM78为低功耗产品,价格较低。
PIC为低电压、低功耗、大电流LCD驱动、低价格OTP产品。
PIC的引脚通过限流电阻接至220V交流电源,可直接与继电器想连,无须光电耦合隔离。
Motorola特点是噪声低,抗干扰能力强,比较适合于工控领域及恶劣的环境。
我们这里选51系列的89c52单片机,单片机与8255芯片相连,扩展了I/O口,使其有足够的I/O与键盘与数码管连接。
STC89C52是一个低功耗,高性能CMOS8位单片机,片内含8kBytes的可反复擦写1000次的Flash只读程序存储器。
其工作电压在4.5-5V,一般我们选用+5V电压。
外形及引脚排列如图1所示
(1)电源及时钟引脚(4个)
Vcc:
电源接入引脚
Vss:
接地引脚
XTAL1:
晶振震荡器接入的一个引脚(采用外部振荡器时,此引脚接地);
XTAL2:
晶体振荡器的另一个引脚(采用外部振荡器时,此引脚作为外部振荡器信号的输入端)。
图1:
STC89C52的核心电路框图
(2)控制线引脚(4个)
RST/Vpd:
复位信号输入引脚/备用电源输入引脚;
ALE:
地址锁存允许信号输出引脚/编程脉冲输入引脚:
EA:
内外存储器选择引脚/片外EPROM编程电压输入引脚;
PSEN:
外部程序存储器选通信号输出引脚。
(3)并行I/O引脚
P0.0-P0.7:
一般I/O口引脚或数据/低位地址总线复用引脚;
P1.0-P1.7:
一般I/O口引脚;
P2.0-P2.7:
一般I/O口引脚或高位地址总线引脚;
P3.0-P3.7:
一般I/O口引脚或第二功能引脚
2.2LED数码管显示器概述
数码管按段数分为七段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管单元(多一个小数点显示);按能显示多少个“8”可分为1位、2位、4位等等数码管;按发光二极管单元连接方式分为共阳极数码管和共阴极数码管。
共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数码管。
共阳数码管在应用时应将公共极COM接到+5V,当某一字段发光二极管的阴极为低电平时,相应字段就点亮。
当某一字段的阴极为高电平时,相应字段就不亮。
共阴数码管是指将所有发光二极管的阴极接到一起形成公共阴极(COM)的数码管。
共阴数码管在应用时应将公共极COM接到地线GND上,当某一字段发光二极管的阳极为高电平时,相应字段就点亮。
当某一字段的阳极为低电平时,相应字段就不亮。
LED数码管有两种连接方法如下:
共阳极接法。
把发光二极管的阳极连在一起构成公共阳极,使用时公共阳极接+5V,每个发光二极管的阴极通过电阻与输入端相连。
我们这里采用共阳极接法,当为低电平的时刻,那一段就亮。
我们先把要显示的数编成码,然后位选要显示的数码管,最后吧把要显示的数的码送给段选。
共阴极接法。
把发光二极管的阴极连在一起构成公共阴极,使用时公共阴极接地。
每个发光二极管的阳极通过电阻与输入端相连。
图2共阳共阴数码管
LED数码显示器的显示段码。
为了显示字符,要为LED显示器段码(或称字形代码),组成一个8字形字符的7段,再加上1个小数点位,共计8段,因此提供给LED显示器的显示段码为1个字节。
各段码位的对应关系如下表所示.十六进制数及空白字符与P的显示段码
显示字符
0
1
2
3
4
5
6
7
8
9
七段代码
3FH
06H
5BH
4FH
66H
6DH
7DH
07H
7FH
6FH
数码管要正常显示,就要用驱动电路来驱动数码管的各个段码,从而显示出我们要的数字,因此根据数码管的驱动方式的不同,可以分为静态式和动态式两类。
①静态显示驱动:
静态驱动也称直流驱动。
静态驱动是指每个数码管的每一个段码都由一个单片机的I/O端口进行驱动,或者使用如BCD码二-十进制译码器译码进行驱动。
静态驱动的优点是编程简单,显示亮度高,缺点是占用I/O端口多,如驱动5个数码管静态显示则需要5×8=40根I/O端口来驱动,实际应用时必须增加译码驱动器进行驱动,增加了硬件电路的复杂性。
②动态显示驱动:
数码管动态显示接口是单片机中应用最为广泛的一种显示方式之一,动态驱动是将所有数码管的8个显示笔划"a,b,c,d,e,f,g,dp"的同名端连在一起,另外为每个数码管的公共极COM增加位选通控制电路,位选通由各自独立的I/O线控制,当单片机输出字形码时,所有数码管都接收到相同的字形码,但究竟是那个数码管会显示出字形,取决于单片机对位选通COM端电路的控制,所以我们只要将需要显示的数码管的选通控制打开,该位就显示出字形,没有选通的数码管就不会亮。
我们这里选用动态显示。
图3数码管连接图
2.3.8255的引脚信号
1与外部设备端相连的引脚
(1)PA7-PA0:
A端口的输入/输出引脚。
(2)PB7-PB0:
B端口的输入/输出引脚。
(3)PC7-PC0:
C端口的输入/输出引脚。
②与CPU相连的引脚
(1)RESET:
复位信号,低电平有效。
当RESET信号来到时,所有内部寄存器都被清0,同时3个端口被自动设为输入端口。
(2)D7-D0:
8255A的数据线,和系统数据总线相连。
这里与单片机P0相连。
(3)CS:
芯片选择信号。
只有当CS有效时,读出信号RD和写入信号WR才对8255A有效。
(4)RD:
读出信号。
CPU通过IN指令使RD有效,将数据或状态信息从8255A中读到CPU。
(5)WR:
写入信号。
CPU通过OUT指令使WR有效,将数据或状态信息从CPU中写道8255A.
(6)A1,A0:
端口选择信号。
8255A内部有3个数据端口和1个控制端口,共4个端口。
规定A1,A0为00、01、10和11时,分别选中端口A、端口B、端口C和控制端口。
图48255A引脚图
2.4.8255的控制字
①方式选择控制字
(1)方式选择控制字把A、B、C三个端口分为A、B两组来设定工作方式。
A组包括端口A和端口C的上半部,B组包括端口B和端口C的下半部。
(2)端口A可工作于3种方式中的任何一种:
端口B只能工作于方式0和方式1;而端口C除用作输入、输出口(方式0)外,通常用来配合端口A和端口B提供联络控制信号和状态信号。
(3)归在同一组的两个端口可分别作为输入端口或输出端口,不要求同为输入或输出。
②端口C按位置位/复位控制字
(1)端口C按位置位/复位控制字尽管是对端口C进行操作的,但此控制字必须写入控制口,而不写入端口C。
(2)一个控制字只能完成端口C中某一位置的置1或置0,要对多位置1或置0,必须使用多个控制字。
2.5.键盘控制
第一种:
采用扫描键盘,可以用普通按键构成4×4矩阵键盘,直接接到AT89C51单片机的P1口,高四位作为行,低四位作为列,通过软件完成键盘的扫描和定位。
这种方式相对下面的独立式键盘节省了很多的I/O口。
第二种:
键盘控制采用独立式按键,每个按键的一端均接地,另一端直接和P1口相连,在按键和P1口之间通过10K电阻与+5V电源相连。
键盘通过检测输入线的电平状态就可以很容易地判断哪个键被按下了,这种方法操作速度高而且软件结构很简单,比较适合按键较少或操作速度较高的场合,这种独立式接口的应用很普遍。
显示部分:
我们这里采用第一种,通过扫描确定所按下的键值。
图5键盘图
2.6其他元器件介绍及参数选择
本设计中还用到其他一些元器件,例如:
晶振,电容,电阻排,电解电容,键盘,开关等等。
晶振采用频率为12MHZ,连接的两个电容为30pF;电阻排为470*8,能够实现8个470欧电阻的等效替换;电解电容为10u;开关功能是在仿真过程中,按下键盘便能实现。
3软件设计
3.1程序框图
图6程序流程图
初始化:
设置8255芯片的初始值:
a8255_PA=0xff;a8255_CON=0x81;设置定时器的初值和工作方式:
TMOD=0x01;TH0=0x3c;TL0=0xb0;IT1=1;TR0=1开中断:
EA=1;ET0=1;EX0=1。
键盘设置初值:
key=0时,a=99999;key=1时,a=9999;key=2时,a=999;key=3时,a=99;key=4时,a=9;
减1:
当定时器记1秒时,a就减1。
3.2定时/计数器初值计算
1.定时器/计数器的定时器/计数器范围
(1)工作方式0:
13位定时器/计数器方式
最大计数值=8192
(2)工作方式1:
16位定时器/计数器方式
最大计数值=65536
(3)工作方式2和工作方式3:
8位的定时器/计数器方式
因此,
最大计数值=256
2.计数器初值的计算
方法:
用最大计数量减去需要的计数次数。
即:
TC=MC其中:
TC——计数器需要预置的初值;M——计数器的模值(最大计数值);C——计数器计满回0所需的计数值,即设计任务要求的计数值。
定时时间的计算公式为:
T=(MTC)×T0(或TC=MT/T0)
(1)本电路应用16位计数器的计时
(2)1秒等于1000000微秒,而每一计时脉冲是1微秒,因此需输入1000000个计时脉冲,方可达到1秒的时间。
本设计中,设定中断每次溢出时间50ms。
(3)由上式得知,循环20次即可达到1秒定时,即:
TC=65536-0.05s/0.000001=3CB0H
THO=3CH
TL0=B0H
3.3数码管显示
数码管采用动态扫描显示:
先位选一个数码管,段选要显示的数,延迟一段时间,再位选另一位数码管,段选要显示的数,就这样类推,依次显示,利用认得视觉暂停,看起来就像是一起显示的一样。
voiddisplay(uinta)
{
uintwan,qian,bai,shi,ge;
wan=a/10000;
qian=a%10000/1000;
bai=a%1000/100;
shi=a%100/10;
ge=a%10;
a8255_PA=0xfd;
a8255_PB=table[wan];
delay
(1);
a8255_PA=0xfb;
a8255_PB=table[qian];
delay
(1);
a8255_PA=0xf7;
a8255_PB=table[bai];
delay
(1);
a8255_PA=0xef;
a8255_PB=table[shi];
delay
(1);
a8255_PA=0xdf;
a8255_PB=table[ge];
delay
(1);
}
4软件调试
4.1系统调试工具keilc51
KeilC51仿真器是一款利用KEILC51的IDE集成开发环境作为仿真环境的廉价仿真器,是利用SST公司具有IAP功能的单片机SST89C58制作而成,主要是利用了SST89C58的IAP功能,所谓IAP功能是Inapplicationprogram的英文缩写,是在应用编程的意思,通俗一点讲就是:
它可以通过串口将用户的程序下载到单片机中,可以通过串口对单片机进行编程。
它之所以具有这种功能,实际上它有两块程序flash区,其中一块flash中运行的程序可以更改另外的一块程序flash区中的程序,正是利用这一特性才用它作成了仿真器,我们把仿真器的监控程序事先烧入SST89C58,监控程序通过SST89C58的串口和PC通讯,当使用KEILC51的IDE环境仿真时,用户的程序通过串口被监控程序写入flash程序区中,当用户设置断点等操作仿真程序时,flash程序中的用户程序也在相应的更改,从而实现了仿真功能。
调试的主要方法:
1.启动Keilc51
2.新建一个工程。
Project菜单——〉Newproject,选择好我们要保存的文件夹后,键入Frist保存。
接着弹出CPU类型选择框,我们选择最常用的AT89C51,按确定。
3.在工程中加入文件。
新建一个文件,文件菜单File——〉New,我们再选择:
文件菜单File——〉SaveAs?
(另存为)弹出对话框后,我们文件名框中键入First.c(注意文件后缀名是.c)保存。
C文件建好啦。
现在我们把文件加入到工程中去。
点击Target1前面的+号,右键单击SourceGroup1——〉选择AddFilestoGroup,SourceGroup1,选择添加Add。
编译运行,检查程序是否有错误。
4.用STC软件进行下载连接到单片机,然后观察是否按设计要求实现。
5总结
在这次单片机课程设计中,我觉得最大的收获就是提高了自己的动手及思考解决问题的能力,平常以为很明白的程序,在仿真过程中却发现并不是想象的那么简单,设计的过程中失败了很多次,但通过自己的不懈努力最终获得设计的成功!
本次设计虽然是8255A非常简单的应用,但让我掌握了学习可编程接口芯片和可编程接口芯片的方法,为以后的学习实践打下了基础。
在设计过程当中也发现了自己经验的不足,尤其是在编程序方面还需要大量的练习,为以后的学习打下基础。
万事开头难,在这次课程设计后我对自己的动手能力更加有信心。
由于时间和个人能力的不足,我没能做出多位数码管计时的设计,但是在以后的时间里我继续学习以补充自己知识的短板来完善自身。
参考文献
[1]朱定华,戴汝平.单片微机原理与应用.(M)北京:
清华大学出版社,2003
[2]楼然苗,李光飞.单片机课程设计指导.(B).北京航空航天大学出版社,2007
[3]李凤霞,刘桂山,薛庆.C语言程序设计(第二版).北京理工大学出版社,2008
[4]张鑫,华臻,陈书谦.单片机原理及应用(A).北京电子工业出版社,2005
[5]谭浩强著C程序设计(第二版)清华大学出版社1999
附录一:
总体设计图
附录二:
总程序
#include
#include
#definea8255_PAXBYTE[0xd900]/*PA口地址*/
#definea8255_PBXBYTE[0xdb00]/*PB口地址*/
#definea8255_PCXBYTE[0xD5FF]/*PC口地址*/
#definea8255_CONXBYTE[0xde00]/*控制字地址*/
#defineucharunsignedchar
#defineuintunsignedlongint
uinta,n,i,j,x=1,b=1,tt=0;
uinttable[]={0x80,0x9B,0x42,0x0A,0x19,0x0C,0x04,0x9A,0x00,0x08};
voiddelay1(void)
{
unsignedchari;
for(i=250;i>0;i--);
}
ucharinkey()
{
uchari,j=0x10,k;
ucharkeytab[20]={0x18,/*0*/
0x28,/*1*/
0x48,/*2*/
0x88,/*3*/
0x14,/*4*/
0x24,/*5*/
0x44,/*6*/
0x84,/*7*/
0x12,/*8*/
0x22,/*9*/
0x42,/*10*/
0x82,/*11*/
0x11,/*12*/
0x21,/*13*/
0x41,/*14*/
0x81/*15*/
};
a8255_CON=0x81;
a8255_PC=0x00;
for(i=0;i<4;i++)
{
a8255_PC=j;
a8255_PA=0xff;
a8255_PB=0xff;
k=a8255_PC;
k=k&0x0f;
if(k!
=0)
{delay1();
k=a8255_PC;
k=k&0x0f;
if(k!
=0)
break;
}
j=j<<1;
delay1();
}
k=k+j;
for(i=0;i<16;i++)
{
if(keytab[i]==k)break;
}
returni;
}
voiddelay(uintz)
{
uintx,y;
for(x=z;x>0;x--)
for(y=11;y>0;y--);
}
voiddisplay(uinta)
{
uintwan,qian,bai,shi,ge;
wan=a/10000;
qian=a%10000/1000;
bai=a%1000/100;
shi=a%100/10;
ge=a%10;
a8255_PA=0xfd;
a8255_PB=table[wan];
delay
(1);
a8255_PA=0xfb;
a8255_PB=table[qian];
delay
(1);
a8255_PA=0xf7;
a8255_PB=table[bai];
delay
(1);
a8255_PA=0xef;
a8255_PB=table[shi];
delay
(1);
a8255_PA=0xdf;
a8255_PB=table[ge];
delay
(1);
}
voiddisplay1()
{
a8255_PA=0xdf;
a8255_PB=0x80;
delay
(1);
a8255_PA=0xef;
a8255_PB=0x7f;
delay
(1);
}
voidinit()
{a8255_PA=0xff;
a8255_CON=0x81;
tt=0;
TMOD=0x01;
TH0=0x3c;
TL0=0xb0;
EA=1;
ET0=1;
TR0=1;
EX0=1;
IT1=1;
}
voidmain()
{
ucharn=0,k=0xdf;
init();
a=0;
while
(1)
{
n=inkey();
switch(n)
{
case0:
a=99999;
break;
case1:
a=9999;
break;
case2:
a=999;
break;
case3:
a=99;
break;
case4:
a=9;
break;
}
if(n==5)
{
do
{
display1();
n=inkey();
if((n!
=5)&&(n!
=16))
{
x=0;
}
}while(x);
x=1;
}
display(a);
}
}
voidtimer0()interrupt1
{
TH0=0x3c;
TL0=0xb0;
tt++;
if(tt==20)
{
tt=0;
if(a)
{
a--;
}
}
}