现在,我们开始步入按键程序设计的殿堂,在基于Arduino为核心构成的应用系统中,用户输入是必不可少的部分,输入可以由多种方式,这里我们来讲一下最高(chao)大(jian)上(dan)的按键。 原理大放送: 这是个有5个方向的操纵杆,包括上、下、左、右以及确定(就是往下按),每个按键分别与Arduino的引脚连接,原理图如下,其中AR_A1 -- AR_A5分别于Arduino的A1 -- A5相连。 简单分析一下按键检测原理,当按键没有按下的时候,单片机的引脚通过上拉电阻R接到VCC,程序在读取这个引脚的电平时值为1(高电平);当按键按下时,该引脚被短接到GND,此时程序读这个引脚的电平时值为0(低电平);因此,按键是否按下可以通过对应引脚的高低电平来反应,我们只要再程序中判断引脚的电平状态就可以识别按键是否按下,从而做出相应的处理; 一切看起来很美好,但现实并非理想状态! 我们在得出上述结论的时候其实忽略了一个重要的问题,那就是现实中按键按下时电压的变化状态不是理想的如下图: 二现实往往是残酷的,由于按键的弹片接触时,并不是一接触就紧紧的闭合,它还存在一定的抖动,尽管这个时间非常的短暂,但是对于执行速度以us为计算单位的微控制器来说就比较漫长了,实际的按键波形是下面这样的: 这样便存在这样一个问题,由于抖动的存在,程序会认为多次按下了按键,这并不是我们所需要的。解决办法就是软件延时消抖,由于抖动的时间大概维持20ms以内,只要软件第一次检测到按键按下时,延时20ms,避开这个抖动区间就可以了; 示例代码: /* I/O define */ #define KEY_UP A1 #define KEY_DOWN A5 #define KEY_LEFT A3 #define KEY_RIGHT A2 #define KEY_ENTER A4 int key_release_flag = 1, i; int time_ticks = 0; void setup(void) { pinMode(13, OUTPUT); pinMode(KEY_UP, INPUT); digitalWrite(KEY_UP, HIGH); pinMode(KEY_DOWN, INPUT); digitalWrite(KEY_DOWN, HIGH); pinMode(KEY_LEFT, INPUT); digitalWrite(KEY_LEFT, HIGH); pinMode(KEY_RIGHT, INPUT); digitalWrite(KEY_RIGHT, HIGH); pinMode(KEY_ENTER, INPUT); digitalWrite(KEY_ENTER, HIGH); Serial.begin(9600); } void loop(void) { /* led flash */ delay(1); time_ticks++; if(time_ticks == 500) { digitalWrite(13, HIGH); } else if(time_ticks == 1000) { digitalWrite(13, LOW); time_ticks = 0; } /* keyboard scan */ if((digitalRead(KEY_UP) == LOW) || (digitalRead(KEY_DOWN) == LOW) || (digitalRead(KEY_LEFT) == LOW) || (digitalRead(KEY_RIGHT) == LOW) || (digitalRead(KEY_ENTER) == LOW)) { if(key_release_flag) { delay(10); if((digitalRead(KEY_UP) == LOW) || (digitalRead(KEY_DOWN) == LOW) || (digitalRead(KEY_LEFT) == LOW) || (digitalRead(KEY_RIGHT) == LOW) || (digitalRead(KEY_ENTER) == LOW)) { key_release_flag = 0; if(digitalRead(KEY_UP) == LOW) Serial.print("you press UP\n"); else if(digitalRead(KEY_DOWN) == LOW) Serial.print("you press DOWN\n"); else if(digitalRead(KEY_LEFT) == LOW) Serial.print("you press LEFT\n"); else if(digitalRead(KEY_RIGHT) == LOW) Serial.print("you press RIGHT\n"); else if(digitalRead(KEY_ENTER) == LOW) Serial.print("you press ENTER\n"); } } } else key_release_flag = 1; } 程序运行时板载的LED会以1秒为周期闪烁,提示系统正常工作;当按下任意一个按键时,串口监视器会显示当前按下的键位,例如“you press UP”。现象如下图: 源代码下载: |