//avr 单片机 中4*3扫描状态机实现
char read_keyboard_FUN2()
{
static char key_state = 0, key_value, key_line,key_time;
char
key_return = No_key,i;
switch (key_state)
{
case 0:
//最初的状态,进行3*4的键盘扫描
key_line = 0b00001000;
for
(i=1; i<=4; i++)
// 扫描键盘
{
PORTD = ~key_line; // 输出行线电平
PORTD =
~key_line; // 必须送2次!!!(注1)
key_value = Key_mask
& PIND; // 读列电平
if (key_value == Key_mask)
key_line
<<= 1; // 没有按键,继续扫描
else
{
key_state++; //
有按键,停止扫描
break; //
转消抖确认状态
}
}
break;
case 1:
//此状态来判断按键是不是抖动引起的
if (key_value == (Key_mask &
PIND)) // 再次读列电平,
{
key_state++; // 转入等待按键释放状态
key_time=0;
}
else
key_state--; //
两次列电平不同返回状态0,(消抖处理)
break;
case 2: // 等待按键释放状态
PORTD
= 0b00000111; // 行线全部输出低电平
PORTD = 0b00000111; // 重复送一次
if (
(Key_mask & PIND) ==
Key_mask)
{
key_state=0; //
列线全部为高电平返回状态0
key_return=
(key_line |
key_value);//获得了键值
}
else
if(++key_time>=100)//如果长时间没有释放
{
key_time=0;
key_state=3;//进入连键状态
key_return=
(key_line | key_value);
}
break;
case
3://对于连键,每隔50ms就得到一次键值,windows xp 系统就是这样做的
PORTD = 0b00000111; //
行线全部输出低电平
PORTD = 0b00000111; // 重复送一次
if ( (Key_mask &
PIND) == Key_mask)
key_state=0; // 列线全部为高电平返回状态0
else
if(++key_time>=5)
//每隔50MS为一次连击的按键
{
key_time=0;
key_return= (key_line |
key_value);
}
break;
}
return key_return;
}
以上用了4个状态,一般的键盘扫描只用前面3个状态就可以了,后面一个状态是为增加“连键”功能设计的。连键——即如果按下某个键不放,则迅速的多次响应
该键值,直到其释放。在主循环中每隔10ms让该键盘扫描函数执行一次即可;我们定其时限为10ms,当然要求并不严格。 |