三行代码
keycode = ~(keycloumn | keyrow);
key = keycode & (keycode ^ keybefore);
keybefore = keycode;
三行代码理解:
一般情况不会同时按下两个及以上的按键,以下不考虑同时按下不同按键的情况。
keycode为当前扫描得到的按键编码,有按键按下不为0,否则为0,keybefore为上一次扫描时得到的按键值。
第一行是按键编码取反,将按下的按键所在行和列二进制值取1,(如按下第一行第二列keycode为0x41, 高四位从高位到低位对应第一列到第四列,低四位从低位到高位对应第一行到第四行);
第二行是松手检测加消抖。当前和上一次扫描时按键的状态有四种情况,为消抖,只在情况②(刚刚按下按键)时读取按键编码
①:上一次未按下,当前未按下;
②:上一次未按下,当前按下;
③:上一次按下,当前按下;
④:上一次按下,当前未按下;
异或运算即不相同为1,相同为0,只有②和④两种情况keycode与keybefore不相同,因此只有②和④两种情况keycode^keybefore不为0。这两种情况都是一个为0的值与一个不为0的值位异或,那么②和④两种情况下 keycode ^ keybefore的值等于不为0的那个值(比如0x87 ^ 0x00 = 0x87),所以只有情况②keycode ^ keybefore = keycode(当前扫描时按键编码)。异或得到的值还得与keycode进行位于操作,情况④keycode = 0,与(keybefore ^ keycode)位与结果为0,但是情况②keycode为当前按下按键编码,而(keybefore ^ keycode)也为当前按下按键编码,因此key也为当前按下按键编码。综上,只有情况②key的值为当前按下按键编码,其余三种情况key = 0。
第三行:
保存上一次按下按键编码。
源代码
#include<stc15f2k60s2.h>
#define uchar unsigned char
code uchar semg[12] = { 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90,
0xbf, 0xff};
code uchar semg_bit[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
uchar semg_temp[8] = { 11, 11, 11, 11, 11, 11, 11, 11};
//自定义按键排列,-1表示按键无效显'-'
code char keymap[4][4] = { { 0, 1, 2, -1}, { 3, 4, 5, -1}, { 6, 7, 8, -1}, { 9, 10, 11, -1}};
void allinit()
{
P2 = 0x80; P0 = 0xff;
P2 = 0xa0; P0 = 0x00;
P2 = 0xc0; P0 = 0xff;
P2 = 0xe0; P0 = 0xff;
}
void Timer0Init(void) //2毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA = 1;
ET0 = 1;
}
void display()
{
uchar i;
P2 = 0xe0; P0 = semg[semg_temp[i]];
P2 = 0xc0; P0 = semg_bit[i];
P2 = 0x00; P0 = 0xff;
i++;
if(i == 8)
i = 0;
}
void fun() interrupt 1
{
display();
}
char keyscan()
{
static uchar keybefore = 100;
char keyvalue = 100;
uchar keyrow = 0, keycloumn = 0, keycode = 0, key = 0, i = 0, j = 0;
P3 = 0x0f; P44 = 0; P42 = 0; P35 = 0;
keyrow = P3 & 0x0f;
P3 = 0xf0; P44 = 1; P42 = 1; P35 = 1;
if(P44 == 0) keycloumn = 0x70;
else if(P42 == 0) keycloumn = 0xb0;
else keycloumn = P3 & 0xf0;
//以下为三行代码
keycode = ~(keycloumn | keyrow);
key = keycode & (keycode ^ keybefore);
keybefore = keycode;
if(key)
{
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
if(key == (0x80 >> j | 0x01 << i))
{
keyvalue = keymap[i][j];
break;
}
}
return keyvalue;
}
void menu(char keyvalue)
{
if(keyvalue >= 0 && keyvalue <= 11)
{
if((keyvalue / 10) > 0)
semg_temp[6] = keyvalue / 10;
else
semg_temp[6] = 11;
semg_temp[7] = keyvalue % 10;
}
else if(keyvalue == -1)
{
semg_temp[6] = 11;
semg_temp[7] = 10;
}
else ;
}
void main()
{
allinit();
Timer0Init();
while(1)
{
menu( keyscan() );
}
}