2.1.2 器件和原理
本例主要介绍AVR单片机外围电路中按键去抖电路的设计,分别介绍相应的软件和硬件解决方案。然后利用C语言编写通过按键控制发光二极管亮灭状态的程序。
1、按键的去抖动电路
(1)按键的响应过程
我们日常所说的按键,实际上是一个机械开关,本实例所用的按键外观如图2.1.1所示。理想的按键的闭合和断开时,接触点的电压应该立即变高或者变低,但
是由于机械触点的弹性以及按键按动时电压突变等原因,在触点闭合或断开的瞬间会出现电压抖动现象,如图2.1.2所示。在发生抖动的时间一般在
5-10ms。
一次按键处理过程如下:当按键按下之后,相应的按键接触点的电压以高低电平的方式输入到单片机的I/O口。按键的闭合与断开是有一定时间的,一般为
0.1-1S。而AVR单片机的机器周期一般为1us甚至更短,在0.1-1S的时间段内,程序会检测很多次按键的输入电平,这样单片机可能会认为按键被
按下了多次,从而出现误判。
图2.1.1 按键开关 图2.1.2 按键闭合断开时的电压波动示意图
(2)按键去抖动的方法和原理
为了去除按键的抖动,保证单片机对按键的一次输入只响应一次,可以采用硬件和软件两种方法:硬件电路去抖动是在外围电路中加入去抖动电路(如R-S触发
器);软件去抖动是在程序中加入延时程序以跳过抖动时间,等待信号稳定后再次判断按键的输入电平,如果信号电平保持不变,则可以确认一次按键按下。
●硬件去抖动电路的原理
用R-S触发器形成去抖电路是单片机外围电路设计中常用的方法,这种方法可以减少单片机软件对按键动作的延时和计算。
先来了解一下R-S触发器的基本工作原理和工作特点。R-S触发器的基本构成如图2.1.3所示,这个电路有两个与非门交叉耦合而成,/S、/R是信号输入端,低电平有效。Q和/Q既表示触发器状态,又是触发器的输出端。
图2.1.3 R-S触发器的基本原理
在启动过程中,/S端一旦下降到开门电平,Q端电平就会上升,反馈到门B的输入端,此时门B在/R的低电平作用下处于导通状态,/Q输出高电平反馈到A的
输入端,如果这时/S端电压有一个高的跳动,则A门截止,Q段输出低电平,这个低电平反馈到A的输入端,使A门导通,Q端电平为高,这样就保证了Q端电平
的稳定,从而消除按键的抖动。
典型的硬件去抖动电路如图2.1.4,74LS02按键输出端口通过/Q端接入单片机的I/O口,74LS02构成一个R-S触发器电路实现按键的消抖。
●软件消抖的原理和实现
软件消抖的基本原理是在软件中对按键进行两次检测确认,记载第一次检测到按键按下后,间隔10ms左右再次检测按键是否按下,只有在两次都检测到按键按下时才最终确认有键按下,这样就避开了按键的抖动时间,从而消除了抖动的影响。
图2.1.4 74LS02实现的硬件消抖电路
在按键接口软件的设计中,除了要考虑按键消抖外,一般还要判别按键的释放,只有检测到按键释放后,才能确定为一次完整的按键动作。
通用的案件检测程序如下:
[code="c"]
Keyscan()
{
if(!key) //判断按键是否按下,key=0表示按键按下
{
delayms(20); //延时20ms。避开按键抖动时间
if(!key) //再次判断按键是否按下,
{
… //按键按下的处理程序
}
}
While(!key); //判断按键是否放开,key=1表示按键释放,退出按键处理函数
}
[/code]
2.1.3 电路
本例中的电路如图2.1.5和2.1.6所示。
1、电路原理
图2.1.5是按键检测电路,两个按键分别连接到单片机的PD6、PD7管脚,AVR单片机在程序里把PD6、PD7设置为带上拉的端口,这样按键没有按
下时,PD6、PD7处于高电平状态,当按键按下时PD6、PD7被连接到地,电平状态变为低电平,程序中检测到PD6、PD7的电平为低电平时,就可以
认为按键被按下了。
图2.1.6为LED显示电路,当按键K3被按下时,D1、D3、D5、D7点亮,D2、D4、D6、D8熄灭。当按键K4被按下时,D1、D3、D5、D7熄灭,D2、D4、D6、D8点亮。
2、元器件选择
在这里列出和本例相关的、关键部分的器件名称及其在电路中的作用。
● ATmega16:单片机,检测按键按下情况并控制发光二极管的亮灭。
● D1-D8:发光二极管,指示按键状态。
● RP1:阻值为330Ω的排阻,限流电阻。
● K3、K4:按键,当按键按下时,与按键连接的单片机端口的电平发生变化。
3、管脚连接
在这里列出和本例相关的、关键部分的单片机端口与外围电路的连接。
● PB0-PB7:连接8个发光二极管LED1-LED8,控制发光二极管的亮灭。
● PD6、PD7:连接按键K3、K4,检测两个按键的状态。
2.1.4 程序设计
1、程序功能
● 按键软件消抖
本例中采用软件消抖的方法,在程序中加入软件延时,去除按键的抖动。
● 按键检测
通过将单片机的PD6、PD7口设置为输入状态,同时使能这两个口的内部上拉电阻(因为这两个口在按键没有按下时处于悬空状态,易受外界干扰,所以必须将其内部上来电阻使能,使其平时处于高电平状态),检测按键是否按下。
通过将单片机的PB0-PB7口设置为输出状态,根据K3、K4两个按键的按下情况,控制不同的发光二极管点亮或熄灭。
● AVR单片机端口输入状态的读取
AVR单片机端口配备有3个寄存器,分别是方向控制寄存器DDRx,数据寄存器PORTx,和输入引脚寄存器PINx(x=A\B\C\D)。当I/O工作在输入方式,要读取外部引脚上的电平时,应读取PINxn的值,而不是PORTxn的值。
2、主要变量和函数说明
无
3、使用WINAVR开发环境,makefile文件同前面的例子,直接复制到本实例程序的文件夹中即可。
4、程序代码
[code="c"]
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
PORTB = 0X00; //输出低,LED全部熄灭
DDRB = 0Xff; //PB端口置为输出
PORTD = 0Xc0; //一定要使能上拉电阻,否则会有干扰
DDRD = 0X3F; //K3、K4按键(PD6、PD7)设置为输入端口
while(1)
{
if(!(PIND & (1 << PD6))) //判断按键是否按下
{
_delay_ms(20); //判断按键按下,延时一会再判断是否按下, 以消除干扰
if(!(PIND & (1 << PD6))) // 按键真正按下后,进行相应处理
{
PORTB = 0X55; // 按键按下,灯亮
while(!(PIND & (1 << PD6)));//等待按键释放
//PORTB = 0X55; // 把这句话从上面移到这里,按键释放后,灯才点亮
}
}
if(!(PIND & (1 << PD7))) //判断按键是否按下
{
_delay_ms(20); //判断按键按下,延时一会再判断是否按下, 以消除干扰
if(!(PIND & (1 << PD7))) // 按键真正按下后,进行相应处理
{
PORTB = 0Xaa; //
while(!(PIND & (1 << PD7))); //
//PORTB = 0Xaa; //
}
}
}
}