|
发表于 2008-6-7 15:28:15
|
显示全部楼层
在我的教材中谈到过,看似简单的按键,实际上并不简单.因为实际上在每一个系统中,按键的功能和处理是不同的,比如是否使用组合键(需要辨别双键或多键),是否使用连_发键(需要判断按键按下时间的长短)等.按键功能越复杂,处理程序也随之复杂.
根据我的经验,建议如下:
1.首先要根据系统总体要实现的功能,确定按键的功能.能够使用简单的方式,尽量使用简单的方式,如不使用组合键等.当然,这样可能需要更多的按键,硬件上要多花费些,但是对于实际操作人员的使用确简单多了.实际使用者一般不喜欢使用所谓"多功能"按键,因为他们往往记不住过多的组合方式和功能,操作上也不容易掌握,如"先"按哪个,"再"按哪个等(实际操作中,很难做到"同时"按下的).我通常不主张使用组合键,用的比较多的是某几个键的连_发(参考P287).
2.按键处理部分的程序结构最好是将读键和判别键值做处理分成两个部分,这样既方便调试,程序结构好,同时也便于底层硬件变化后的移植.
3.尽管AVR等新型单片机提供了片内比较充足的程序和数据储存器,但还是有限的,尽量要根据实际需要编写按键处理程序,而不是放上一个全功能的处理程序,这样会浪费资源.6楼的意见是对的,掌握和使用状态机的思想非常重要,不仅对处理按键,在其它方面也是非常实用的方法.在我的书中,是借按键的例子引出状态机的思想和方法,在后面的例子中实际有很多地方都采用了该方法(比如USART的中断接收).
下面根据LZ的出题,给出我的答卷(cvavr).当然,LZ的题目并没有详细说明8个按键具体的操作要求,所以我代码实现的是最简单的判定.
假定:无连_发,无组合键,仅是单键的简单操作,按下去(不管多长时间)算一次按键,其它按键方式做无效处理.
#define key_input PINA
#defien key_1 0b11111110
#defien key_2 0b11111101
#defien key_3 0b11111011
#defien key_4 0b11110111
#defien key_5 0b11101111
#defien key_6 0b11011111
#defien key_7 0b10111111
#defien key_8 0b01111111
#defien key_no 0b11111111
#define key_state_0 0
#define key_state_1 1
#define key_state_2 2
unsigned char read_key(void) //读键状态机,每10-20ms执行一次
{
static unsigned char key_state = 0,key_old;
unsigned char key_press,key_return = key_no;
key_press = key_input; // 读按键I/O电平
switch (key_state)
{
case key_state_0: // 按键初始态
if (key_press != key_no) key_state = key_state_1; // 键被按下,状态转换到键确认态
break;
case key_state_1: // 按键确认态
if (key_press == key_old) // 与原电平比较(消抖处理)
{
key_return = key_press;
key_state = key_state_2; // 状态转换到判键释放态
}
else
key_state = key_state_0; // 按键已抬起,转换到按键初始态(消抖)
break;
case key_state_2:
if (key_press != key_old)
key_state = key_state_0; //按键已释放(或转按其它键),转换到按键初始态
break;
}
key_old = key_press;
return key_return;
}
main()
{
unsigned char key_value;
......
key_value = read_key(); //注意控制10-20ms执行一次.
if (key_value != key_no) //判别键值并做相应的处理
{
switch (key_value)
{
case key_1:
//do samething
break;
case key_2:
// do ....
break;
.........
case key_8:
// do .....
break;
}
}
............
} |
|