① 30秒倒计时器课程设计
【摘 要】篮球比赛30秒钟规则规定:进攻球队在场上控球时必须在30秒钟内投篮出手(NBA比赛为24秒,全美大学体育联合会比赛中为35秒),因此在比赛时裁判既要看比赛又要看秒表计时,而本文介绍的30秒倒计时器可以解决此问题。
【关键词】AT89C51单片机、30秒倒计时器、LED
30秒倒计时器的设计和制作有很多方法,本文介绍的30秒倒计时器以AT89C51单片机作为控制单元,采用两个数码管显示时间,用三个按键分别控制计时器的计时开始、复位和暂停。倒计时器初始状态显示“30”,当裁判员按下计时键,30秒倒计时开始,当计时器时间减到0时,计时器发出声光报警,提示裁判计时时间已到。
一、电路设计
30秒倒计时器的电路主要由电源电路、单片机最小系统、按键输入、显示驱动电路、报警电路组成,30秒倒计时器控制电路如图1所示。
图1 30秒倒计时器电路原理图
1、按键输入
“30秒倒计时器”采用了三个按键来完成计数器的启动计数、复位、暂停/继续计数等功能。
(1)K1键:启动按钮(P3.2)。
按下K1键,计数器倒计时开始,数码管显示数字从30开始每秒递减计数,当递减到到零时,报警电路发出声、光报警信号。当计数器处于暂停状态时按下K1键将回到计时状态。
(2)K2键:复位按钮(P3.3)。
按下K2键,不管计数器工作于什么状态,计数器立即复位到预置值 “30” ,在报警状态时按下K2键还可取消报警。
(3)K3键:暂停/计时切换按钮(P3.4)。
当计数器处于计时状态时按下该键计数器暂停计时,数码管显示数字保持不变;当计数器处于暂停状态按下该键计数器将回到计时状态;初始状态时该键无效。
2、显示驱动电路
“30秒倒计时器”用两个共阳数码管来显示时间,数码管显示方式为动态显示。显示驱动电路中,数码管的段码引脚通过470欧的电阻接到单片机的P1口,两个片选引脚各通过一个9012连接到正5V电源,由P3.0和P3.1控制。
4、报警电路
计时时间减到0,显示数码管显示“00”时,发光二极管D1由P3.5控制发出光报警,同时蜂鸣器由P3.7控制发出声报警。
二、软件编程思路
1、全局变量
“30秒倒计时器”动作流程主要受三个全局变量控制。首先是bit变量“act”,当“act”为“1”时倒计时开始,为“0”时倒计时停止,“act”初值为“0”,可以由按钮操作将其置“1”或清“0”。第二个全局变量是char变量“time”,存放倒计时的时间,当倒计时时间为0时,发出声光报警。变量“time”的初值为30,定时中断服务程序在“act”为1时,每1s对其进行减1操作,减到0时保持为0,按下“复位键”可将“time”复位为30。第三个全局变量是int变量“t”,记录响应定时中断0的次数。根据初始化定义,定时器0以方式1工作,每1ms发出一次中断请求。控制程序只开放了定时器0中断,因此不会有比定时器0中断更高级的中断被允许,所以每次请求都会立刻被响应。响应后在中断服务程序中将全局变量“t”加1记录响应中断次数,每响应1000次即为1秒钟。变量“t”初值为0,在中断服务程序中加1,当“t”为2000时由中断服务程序清0。在按键驱动程序中,按下启动键、复位键、暂停/启动键时将“t”清0,目的是从0ms开始计时。
2、控制流程
主程序主要用来检测全局变量“time”当“time”为0时发出“声光报警”。按键驱动、显示驱动和“time”操作都在定时器0中断服务程序中进行。其控制流程如图2所示。
图2 控制流程图
三、软件程序设计
1、数码管驱动程序
到计时器的两个数码管以动态显示的方式显示计时时间“time”(全局变量),LED1显示“time”的十位,LED2显示“time”的个位。
(1)定义段码数据口和片选信号
根据实际电路,在C51中定义段码的数据口为P1,两个片选信号为P3.0和P3.1。定义如下:
#define an P1
sbit wei1=P3^0;
sbit wei2=P3^1;
(2)定义字形码
LED显示数字0~9以及全灭的字形码表格放在数组zixing[]中。字形码是固定的表格,定义时加上关键字“code” 表示该表格存放在程序存储器中。
unsigned char code zixing[]=
{
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff
};
(3)定义数码管LED1和LED2的显示变量
为了增加驱动程序的可移植性,笔者为数码管LED1和LED2定义了显示变量。显示变量就是本驱动程序的对外接口,外部程序只要改变显示变量的值就可改变数码管显示的数值。定义方式如下:
unsigned char led_str[2]={10,10};
led_str[0]直接对应数码管LED1, led_str[1]直接对应数码管LED2。本项目中由专门的子程序将全局变量time计算拆分成led_str[0]和led_str[1]。
void js()
{
led_str[1]=time/10%10;
led_str[0]=time%10;
}
(4)数码管驱动程序
数码管驱动程序“void chushi(char i)”在定时中断服务程序中被调用执行。根据初始化程序的定义,定时中断服务程序每1ms被执行一次。定时中断服务程序中运用全局变量“t”记录进入该服务程序的次数,“t”计满2000由定时中断服务程序清零。
数码管驱动程序的参数“char i”是用来确定当前点亮的是LED1还是LED2,当参数为“0”时点亮LED1,参数为“1”时点亮LED2。如果我们希望偶数次进入定时中断服务程序时点亮LED1,奇数次进入定时中断服务程序时点亮LED2,我们可以用程序调用语句“chushi(t%2);”轻松实现。
进入数码管驱动程序后首先调用子函数js(),计算当前的led_str[0]和led_str[1]。接下来将两个数码管全部熄灭以防止余晖的出现。最后点亮需要点亮的数码管并送出字型码。驱动程序代码如下:
void chushi(char i)
{
js(); //计算显示变量
an=0xff; //去余晖
wei1=i; wei2=!i; //确定片选
an=zixing[led_str[i]]; //送字型码
}
2、按键驱动程序
按键驱动程序分为按键识别和按键功能执行两部分。按键功能执行可在按键按下时或按键抬起后执行,文中将其设计在按键抬起后执行。
(1)定义按键I/O地址
根据实际电路,三个按键(启动键、复位键、暂停/启动键)分别接在P3口的P3.2,P3.3和P3.4三个引脚上。为了取键值方便还将P3口定义为“iokey”,程序中可作定义如下:
#define iokey P3
sbit key1=P3^2;
sbit key2=P3^3;
sbit key3=P3^4;
(2)按键驱动流程
按键识别的通用流程为:I/O口写“1”→判断有无键按下→延时去抖→确定键值→等待按键抬起→执行按键功能。按键驱动程序中定义了两个静态变量“ts” 和“kv”,分别用来延时去抖和存放键值。
(3)延时去抖
静态变量“ts”用来延时去抖。按键驱动程序在定时中断服务程序中每1ms被执行一遍,每检测到有键按下“ts”加1,检测到无键按下“ts”清0。按键连续按下20ms,则连续20次执行按键驱动程序时都检测到有键按下,此时静态变量“ts”累加到20,可确认按键按下有效。
为防止按键一直按着不放而使“ts”累加到溢出,确认有键按下后可使“ts”的值保持为20,或大于20的某一个值如21。
(4)取键值
确认有键按下后即可通过读取按键的I/O口状态来得到键值。为读取P3.2、P3.3和P3.4引脚状态,屏蔽P3口其他引脚的影响,可将读取后的数值按位或上11100011B(0xE3)再送给静态变量“kv”。
静态变量“kv”存放按键的键值,无键按下或按键抬起后kv的值为0。按下启动键key1时kv=11111011B(0xFB),按下复位键key2时kv=11110111B(0xF7),按下暂停/启动键key3时kv=11101111B(0xEF)。
(5)执行按键功能
按键抬起后第一次执行按键驱动程序时,静态变量“kv”任保持着按键按下时最后得到的键值,以该键值作为参数调用按键执行程序“actkey(kv);”即可执行按键功能。调用后kv值立刻清0,确保按一次键执行一次按键功能。驱动程序代码如下:
void key()
{
static unsigned char kv=0;
static unsigned char ts=0;
key1=1;key2=1;key3=1;
if(!(key1&key2&key3))
{
ts++;
if(ts>=20)ts=20; //有键按下
if(ts==20)
kv=iokey|0xe3; //取键值
}
else
{ //无键按下或按键已抬起
actkey(kv);
ts=0;
kv=0;
}
}
函数actkey(kv)用来根据键值“kv”执行相应操作。当“kv”等于0xFB时代表启动键key1按下,函数actkey(kv)将全局变量act赋值为“1”。当“kv”等于0xF7时代表复位键key2按下,函数actkey(kv)将全局变量“time”复位为“30”。当“kv”等于0xEF时代表暂停/启动键按下,函数actkey(kv)将全局变量act取反。每按一个按钮都有将全局变量“t”清0的操作,目的是每当复位、或启动计时时,进入定时中断的次数都从0开始计算,否则会出现第1秒计时不准确的现象。程序代码如下:
void actkey(unsigned char k)
{
switch(k)
{
case 0xfb:act=1;t=0;break;
case 0xf7:time=30;t=0; break;
case 0xef:act=~act;t=0; break;
}
}
四、结束语
本文在编程过程中以面向对象的编程思路封装了两个LED数码管和三个独立按键。当其驱动程序在定时中断服务程序中被调用,编程者只要操作其接口:数组“led_str[2]”和函数“actkey(unsigned char k)”,无需直接对硬件进行编程即可改变功能,增强了软件的通用性和可移植性。
② 具有倒计数显示功能的定时开关电路设计
用数字电路实现抢答器
一、设计目标
设计一个带有用户选手按下后,其他用户选手按下无效,同时,响警报、显示是谁按下的。由主持人开关复位的抢答器。
二、 基本功能
我设计的抢答器有如下功能:有人按下时,显示是谁按下的。同时,其他人再按下时电路不做任何处理。也就是说,如果有人按下以后,别人再按的话电路既不会显示是他按下的。
三、抢答器的组成
抢答器的一般构成框图如图2-1所示。它主要由开关阵列电路、触发锁存电路、编码器、7段显示器几部分组成。下面逐一给予介绍。
(1)开关阵列电路
该电路由多路开关所组成,每一竞赛者与一组开关相对应。开关应为常开型,当按下开关时,开关闭合;当松开开关时,开关自动弹出断开。
(2)触发锁存电路
当某一开关首先按下时,触发锁存电路被触发,在输出端产生相应的开关电平信息,同时为防止其它开关随后触发而产生紊乱,最先产生的输出电平变化又反过来将触发电路锁定。若有多个开关同时按下时,则在它们之间存在着随机竞争的问题,结果可能是它们中的任一个产生有效输出。
(3)编码器
编码器的作用是将某一开关信息转化为相应的8421BCD码,以提供数字显示电路所需要的编码输入。
图3-1 抢答器的组成框图
(4)7段显示译码器
译码驱动电路将编码器输出的8421BCD码转换为数码管需要的逻辑状态,并且为保证数码管正常工作提供足够的工作电流。
(5)数码显示器
数码管通常有发光二极管(LED)数码管和液晶(LCD)数码管。本设计提供的为LED数码管。
四、抢答器的工作原理
(1)开关阵列电路
图1.2所示为8路开关阵列电路,从图上可以看出其结构非常简单。电路中,R1~R8为上拉和限流电阻。当任一开关按下时,相应的输出为低电平,否则为高电平。
图4-1 开关阵列电路
(2)触发锁存电路
图3-1所示为8路触发锁存电路。
图中,74HC373为8D锁存器,一开始,当所有开关均未按下时,锁存器输出全为高电平,经8输入与非门和非门后的反馈信号仍为高电平,该信号作为锁存器使能端控制信号,使锁存器处于等待接收触发输入状态;当任一开关按下时,输出信号中必有一路为低电平,则反馈信号变为低电平,锁存器刚刚接收到的开关被锁存,这时其它开关信息的输入将被封锁。由此可见,触发锁存电路具有时序电路的特征,是实现抢答器功能的关键。
(3)编码器
如图4-3所示,74HC147H为10-4线优先(高位优先)编码器,当任意输入为低电平时,输出为相应的输入编号的8421码(BCD码)的反码。
图4-2 8路触发锁存电路。
图4-3 10-4线优先编码器
(4)译码驱动及显示单元
编码器实现了对开关信号的编码并以BCD码的形式输出。为了将编码显示出来,需用显示译码电路将计数器的输出数码转换为数码显示器件所需要的输出逻辑和一定的电流。一般这种译码通常称为7段译码显示驱动器。常用的7段译码显示驱动器有CD4511等。
数码显示器件中的液晶数码管价格较高,驱动较复杂,并且仅能工作于有外界光线的场合,所以使用较少。大多情况下使用的是LED数码管。平时使用较多的LED数码有单字和双字之分。
LED数码管尺寸有大有小,一般小的数码管每个数字笔画为一个发光二极管,而尺寸较大的数码管一个笔画可能是多个发光二极管串接而成的,这时一般无法直接用译码驱动器直接驱动(其输出高电平一般为3V左右)。
(5)解锁电路
当触发锁存电路被触发锁存后,若要进行下一轮的重新抢答,则需将锁存器解锁。可将使能端强迫置1或置0(根据具体情况而定),使锁存顺处于等待歉收状态即可。
五、改进、简化设计
(1)功能简介
抢答器同时供8名选手或8个代表队比赛,分别用8个按钮S0 ~ S7表示。设置一个系统清除和抢答控制开关S,该开关由主持人控制。
抢答器具有锁存与显示功能。即选手按动按钮,锁存相应的编号,并在LED数码管上显示,同时扬声器发出报警声响提示。选手抢答实行优先锁存,优先抢答选手的编号一直保持到主持人将系统清除为止。
抢答器具有定时抢答功能,且一次抢答的时间由主持人设定(如30秒)。当主持人启动"开始"键后,定时器进行减计时,同时扬声器发出短暂的声响,声响持续的时间0.5秒左右。
参赛选手在设定的时间内进行抢答,抢答有效,定时器停止工作,显示器上显示选手的编号和抢答的时间,并保持到主持人将系统清除为止。
如果定时时间已到,无人抢答,本次抢答无效,系统报警并禁止抢答,定时显示器上显示00。
(2)设计原理图
如图2-1所示为总体方框图。其工作原理为:接通电源后,主持人将开关拨到"清除"状态,抢答器处于禁止状态,编号显示器灭灯,定时器显示设定时间;主持人将开关置开始"状态,宣布"开始"抢答器工作。定时器倒计时,扬声器给出声响提示。
选手在定时时间内抢答时,抢答器完成:优先判断、编号锁存、编号显示、扬声器提示。当一轮抢答之后,定时器停止、禁止二次抢答、定时器显示剩余时间。如果再次抢答必须由主持人再次操作"清除"和"开始"状态开关。
图5-1 总体设计
(3)电路设计
(1)
(2)
图5-2 完整电路
抢答器电路参考电路如图5-2所示。
该电路完成两个功能:一是分辨出选手按键的先后,并锁存优先抢答者的编号,同时译码显示电路显示编号;二是禁止其他选手按键操作无效。工作过程:开关S置于"清除"端时,RS触发器的
端均为0,4个触发器输出置0,使74LS148的 =0,使之处于工作状态。当开关S置于"开始"时,抢答器处于等待工作状态,当有选手将键按下时(如按下S5),74LS148的输出 经RS锁存后,1Q=1, =1,74LS48处于工作状态,4Q3Q2Q=101,经译码显示为"5"。
此外,1Q=1,使74LS148 =1,处于禁止状态,封锁其他按键的输入。当按键松开即按下时,74LS148的 此时由于仍为1Q=1,使 =1,所以74LS148仍处于禁止状态,确保不会出二次按键时输入信号,保证了抢答者的优先性。
如有再次抢答需由主持人将S开关重新置;清除"然后再进行下一轮抢答。74LS148为8线-3线优先编码器,表5-1为其功能表。
表5-1功能表
由节目主持人根据抢答题的难易程度,设定一次抢答的时间,通过预置时间电路对计数器进行预置,计数器的时钟脉冲由秒脉冲电路提供。
可预置时间的电路选用十进制同步加减计数器74LS192进行设计,具体电路如图4-4所示。(3)报警电路由555定时器和三极管构成的报警电路如图5-4所示。
其中555构成多谐振荡器,振荡频率fo=1.43/〔(RI+2R2)C〕,其输出信号经三极管推动扬声器。PR为控制信号,当PR为高电平时,多谐振荡器工作,反之,电路停振。
本电路给出了所有相关电路,对于发声报警电路只有左下角555电路。时序控制电路是抢答器设计的关键,它要完成以下三项功能:
1、主持人将控制开关拨到"开始"位置时,扬声器发声,抢答电路和定时电路进人正常抢答工作状态。
2、当参赛选手按动抢答键时,扬声器发声,抢答电路和定时电路停止工作。
3、当设定的抢答时间到,无人抢答时,扬声器发声,同时抢答电路和定时电路停止工作。工作原理:当555电路的到信号后,开始产生高低电压不同的方波,这些方波从555电路的输出端出来,经过510欧姆的保护电阻进入放大电路。信号经过放大后,再传给扬声器,这时信号已经不再是方波,而是一种连续变化的一种类似于简谐波的电信号。但是他的频率还是和555电路的输出端的频率一样。
图5-4 定时电路
图5-5扬声器设计
根据上面的功能要求,设计的时序控制电路如4-5图所示。
图中,门G1的作用是控制时钟信号CP的放行与禁止,门G2的作用是控制74LS148的输人使能端 。图11、4的工作原理是:主持人控制开关从"清除"位置拨到"开始"位置时,来自于图5-5中的74LS279的输出 1Q=0,经G3反相, A=1,则时钟信号CP能够加到74LS192的CPD时钟输入端,定时电路进行递减计时。
同时,在定时时间未到时,则"定时到信号"为 1,门G2的输出 =0,使 74LS148处于正常工作状态,从而实现功能①的要求。当选手在定时时间内按动抢答键时,1Q=1,经 G3反相, A=0,封锁 CP信号,定时器处于保持工作状态;同时,门G2的输出 =1,74LS148处于禁止工作状态,从而实现功能②的要求。当定时时间到时,则"定时到信号"为0, =1,74LS148处于禁止工作状态,禁止选手进行抢答。
同时, 门G1处于关门状态,封锁 CP信号,使定时电路保持00状态不变,从而实现功能③的要求。集成单稳触发器74LS121用于控制报警电路及发声的时间。
(4)需要器材:
1.数字实验箱。
2. 集成电路74LS148 1片,74LS279 1片,74LS48 3片,74LS192 2片,NE555 2片,74LS00 1片,74LS121 1片。
3. 电阻 510Ω 2只,1KΩ 9只,4.7kΩ l只,5.1kΩ l只,100kΩ l只,10kΩ 1只, 15kΩ 1只, 68kΩ l只。
4.电容 0.1uF 1只,10uf 2只,100uf 1只。
5. 三极管 3DG12 1只。
6. 其它:发光二极管2只,共阴极显示器3只。
六、其他设计思路
电路设计的思路方法多样可以满足不同需求。 而且我还考虑了很多不同的设计思路,这些不同的思路,他们所用到的器件也不同。下面的内容是我参考的其他的大致的设计方法
使用JK触发器实现用户选手的信号输入和电路的锁存,使一个用户选手输入信号后其他选手输入信号不再有效。在使用户选手输入信号的锁存电路组的输出信号,也就是JK触发器组的输出信号作为二-十进制译码器的输入信号产生十进制8421信号。
这个过程可以采用一些与非门电路完成也可以采用7442二-十进制译码器或者74148优先编码器他们都可以达到输入单信号,输出8421十进制信号的目的完成信号转换的作用。为完成下一个步骤做准备。
在完成上两个步骤以后,就可以将得到的8421十进制信号传送给显示译码器用来显示数字,这给数字应该是用户选手的序列号,来表示是谁按下的。这样,就可以实现一个新功能了。
同时,可以从很多地方取输出信号,传送给555电路用来产生一定频率的方波信号。这种频率应该是人类耳朵能够分辨的频率,超过或低于这个频率范围,普通人就听不见了,那么这种电路的设计就失去了意义。
从这个555电路传出来的方波信号,在通过保护电阻后,送到放大电路,将信号放大。这时,到达放大电路输出端的信号已经变成一种简谐波,不再是方波。在将输出端信号中的直流成分通过电容器予以去掉,就可以将信号送到蜂鸣器了。这时蜂鸣器也能发出声音了。就又实现了一个功能。
从任意一个能用的输出端例如从555电路的输入端取信号送到一个发光二极管,就可以实现如果有人按下以后,就发光的功能。也可以在送到一个放大电路上,接上一个功率较大的发光器件上,使得发光效果更明显。
另外,二-十进制转换器也可以用一些与非门来完成。如图6-1
图6-1 2-10进制转换电路
七、学年设计总结
实习给了我们一个很好的提高动手能力的机会。平常我们只是在头脑中去抽象的记忆、理解那些课本上的理论知识。有的理论知识很好懂,但是有的理论知识确是晦涩难懂的,甚至只是靠自己的死记硬背去记住。但是我们都知道,那样的记忆只是一时的,很快你就会忘记。而这次的实习却给了我们一个在实践中灵活运用知识的机会,我们通过在实践中发现问题,进而去书本中找相关的知识去解决问题,从而巩固了理论知识。那样的知识是你从根本上去认识它,理解它,所以你的记忆时间会很长。
③ 利用单片机设计实现一个60秒倒计时显示装置,并且计时到后发出报警声音。
#include<reg52.h>
sbitbz=P3^1;
unsignedchara[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xd8,0x80,0x90};
unsignedcharn,time=60;
main()
{
P1=a[0];
P2=a[6];
TMOD=0X01;
TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
EA=1;
ET0=1;
TR0=1;
while(1);
}
timer0()interrupt1
{
TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
if(time!=0)
{
n++;
if(n==100)
{
n=0;
time--;
P1=a[time%10];
P2=a[time/10];
}
}
elsebz=~bz;
}