1、按键的基本介绍
CT107D的按键分为独立按键和矩阵按键,跳帽 J5 接在 BTN(button)时,左边的独立按键生效,接在 KBD(keyboard)时矩阵按键生效。
2、独立按键的基本介绍
当为独立按键时候 按键按下会引起响应P3置零
按键号 | 对应IO |
---|---|
S7 | P30 |
S6 | P31 |
S5 | P32 |
S4 | P33 |
如果用学校教的方式写按键有两大缺陷:
1.没有按键消抖,致命缺陷
2.不方便拓展为按下触发、松开触发、长按等等
下面提供两种方案:
2.1 方案一代码
扫描按键函数
unsigned char KeyScan(void)
{
unsigned char keyValue;//返回值
//速记 P3 1234 7654
if(P30 == 0) keyValue= 7;
else if(P31 == 0) keyValue= 6;
else if(P32 == 0) keyValue= 5;
else if(P33 == 0) keyValue= 4;
else keyValue= 0;
return keyValue;
}
按键处理函数
void KeyMain(void)
{
if(keyCount) return; //当到达设定扫描时间才可以执行
keyCount= 1; //重新计数扫描函数
keyValue = KeyScan(); //获取读取的值
//下降沿 等于 读取的值异或之前的值 与上读取的值
keyDown = keyValue & (keyBefore ^ keyValue);
//上升沿 =- 下降沿取反
keyUp = ~Key_Value & (keyBefore ^ keyValue);
//检测电平,一直按着一直等于一个数
keyBefore = keyValue ;
//具体判断逻辑
}
2.1 方案二代码
void Key_scan()
{
//把P3的值取反 ^1 表示位取反 ^0不变
//例当第一个按键按下时 01111 1111 -> 1000 0000
uchar ReadDat = P3^0xff;
// 用于判断按键是否抬起
// 以第一个按键按下位例
// Cnt在第一次按下时候等于 0000 0000
// 当第一个按键没有抬起时候 1000 0000
// 当第一个按键第一次按下时候
// 1000 0000 & (1000 0000 ^ 0000 0000 ) = 1000 0000 & 1000 0000 = 1000 0000
// 当第一个按键没有抬起扫描到时候
// 1000 0000 &(1000 0000 ^ 1000 0000) = 1000 0000 & 0000 0000 = 0000 0000
Trg = ReadDat & (ReadDat^Cnt);
Cnt = ReadDat;
if(Trg & 0x01) //检测到按下S7,用(Trg==0x01)会使按键不灵敏
{
//S7按下要实现的逻辑
}
else if(Trg & 0x02)
{
//S6按下要实现的逻辑
}
else if(Trg & 0x04) /
{
//S5按下要实现的逻辑
}
else if(Trg & 0x08)
{
//S4按下要实现的逻辑
}
P2 = //打开锁存器控制
P2 = 0x00; //关闭锁存器
}
2.3 独立按键练习操作
习题:S7按下点亮L7,S6按下点亮L6,S5按下点亮L5,S4按下点亮L4,
#include <STC15F2K60S2.H>
typedef unsigned char uchar;
typedef unsigned int uint;
uchar Cnt,Trg;
uchar countBotton;
void Delayms(int ms)
{
unsigned char i, j;
while(ms--)
{
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
void Key_scan()
{
uchar ReadDat= P3^0xff;
Trg=ReadDat&(ReadDat^Cnt);
Cnt=ReadDat;
if(Trg&0x01){P0=~0x40;P2 = 0x80; P2 = 0x00; }
else if(Trg & 0x02) {P0=~0x20; P2 = 0x80; P2 = 0x00; }
else if(Trg & 0x04) {P0 = ~0x10;P2 = 0x80; P2 = 0x00; }
else if(Trg & 0x08) {P0 =~0x08;P2 = 0x80; P2 = 0x00; }
}
void Time0_init(void) //1毫秒 @11.0592MHz
{
AUXR |= 0x80;
TMOD &= 0xF0;
TL0 =0xCD;
TH0 = 0xD4;
TR0=1;
ET0=1;
EA= 1;
}
void Time0_isr() interrupt 1
{
++countBotton;
}
void main()
{
P0=0xff;
P2=0x80;
P2=0x00;
P0=0x00;
P2=0xa0;
P2=0x00;
Time0_init();
while(1)
{
if(countBotton > 9)
{
countBotton = 0;
Key_scan();
}
}
}
3、矩阵按键的基本介绍
3.1、方案一:
选择一列扫描行,有点麻烦
unsigned char Keys_Scan(void)
{
unsigned int Key_New;//0x0000 存放每一列的结果
unsigned char Key_Value;//对应的按键编号
//第一次扫描时候直接取P3的第四位,其他的左移4位再取P3的低四位或上之前的值
//0在哪扫描哪
P44 = 0; P42 = 1; P35 = 1; P34 = 1; // 0111
Key_New = P3 & 0X0F; //P3高四位清0 低四位赋值给 Key_New 000a
P44 = 1; P42 = 0; P35 = 1; P34 = 1; // 1011
Key_New = (Key_New << 4) | (P3 & 0X0F); // 00ab
P44 = 1; P42 = 1; P35 = 0; P34 = 1; // 1101
Key_New = (Key_New << 4) | (P3 & 0X0F); // 0abc
P44 = 1; P42 = 1; P35 = 1; P34 = 0; // 1110
Key_New = (Key_New << 4) | (P3 & 0X0F); // acbd
switch(~Key_New)//Key_Value的数值对应按键的编号 记得取反
{
//每一列8421 一直加 没不是结果为0
case 0x8000: Key_Value = 4; break;
case 0x4000: Key_Value = 5; break;
case 0x2000: Key_Value = 6; break;
case 0x1000: Key_Value = 7; break;
case 0x0800: Key_Value = 8; break;
case 0x0400: Key_Value = 9; break;
case 0x0200: Key_Value = 10; break;
case 0x0100: Key_Value = 11; break;
case 0x0080: Key_Value = 12; break;
case 0x0040: Key_Value = 13; break;
case 0x0020: Key_Value = 14; break;
case 0x0010: Key_Value = 15; break;
case 0x0008: Key_Value = 16; break;
case 0x0004: Key_Value = 17; break;
case 0x0002: Key_Value = 18; break;
case 0x0001: Key_Value = 19; break;
default : Key_Value = 0;
}
return Key_Value;
}
3.2、方案二:
**扫描行扫描列 **
void scan_key()
{
static uchar key_state=0;
uchar key_val=0, key_x=0, key_y=0;
//行扫描
P3=0x0f; P4=0x00;
if(!P30) key_x=3;
else if(!P31) key_x=2;
else if(!P32) key_x=1;
else if(!P33) key_x=0;
//X=3210 Y=4321 特别易记
//列扫描 对行扫描取反
P3=0xf0; P4=0xff;
if(!P34) key_y=4;
else if(!P35) key_y=3;
else if(!P42) key_y=2;
else if(!P44) key_y=1;
key_val=key_x+ key_y*4;//综合行、列扫描的结果,判断具体位置
switch(key_state)
{
case 0:
if(key_val!=0) key_state = 1; //第一次检测到有按键按下,状态为1
break;
case 1:
if(key_val==0) key_state=0;//第二次(10ms后)若检测到无按键按下,返回状态0
else
{
key_state = 2; //第二次(10ms 后)再次检测到有按键按下状态为2
value = key_val; ///将按键值传给需要显示的变量
switch(key_val)
{
case 4: P0=~0x04;P2=0x80;P2=0; break;//按下S4
case 5: P0=~0x05;P2=0x80;P2=0; break;//按下S5
case 6: P0=~0x06;P2=0x80;P2=0; break; //按下S6
case 7: P0=~0x07;P2=0x80;P2=0; break; //按下S7
case 8: P0=~0x08;P2=0x80;P2=0; break;//按下S8
case 9: P0=~0x09;P2=0x80;P2=0; break;//按下S9
case 10: P0=~0x0a;P2=0x80;P2=0; break;//按下S10
case 11: P0=~0x0b;P2=0x80;P2=0; break; //按下S11
case 12: P0=~0x0c;P2=0x80;P2=0; break;//按下S12
case 13: P0=~0x0d;P2=0x80;P2=0; break; //按下S13
case 14: P0=~0x0e;P2=0x80;P2=0; break;//按下S14
case 15: P0=~0x0f;P2=0x80;P2=0; break;//按下S15
case 16: P0=~0x10;P2=0x80;P2=0; break;//按下S16
case 17: P0=~0x11;P2=0x80;P2=0; break;//按下S17
case 18: P0=~0x12;P2=0x80;P2=0; break;//按下S18
case 19: P0=~0x13;P2=0x80;P2=0; break;//按下S19
}
}
case 2:if(key_val==0) key_state = 0;//第三次若检测到无按键按下,返回状态0。
}
}
3.3、矩阵按键的练习操作
习题:用L1到L8显示矩阵按键对应的二进制
#include <STC15F2K60S2.H>
typedef unsigned char uchar;
typedef unsigned int uint;
uchar countkey;
void Time0_init(void)
{
AUXR |= 0x80;
TMOD &= 0xF0;
TL0 =0xCD;
TH0 = 0xD4;
TR0=1;
ET0=1;
EA= 1;
}
void Time0_isr() interrupt 1
{
countkey++;
}
void scan_key()
{
static uchar key_state=0;
uchar key_val=0, key_x=0, key_y=0;
//行扫描
P3=0x0f; P4=0x00;
if(!P30) key_x=3;
else if(!P31) key_x=2;
else if(!P32) key_x=1;
else if(!P33) key_x=0;
//X=3210 Y=4321 特别易记
//列扫描
P3=0xf0; P4=0xff;
if(!P34) key_y=4;
else if(!P35) key_y=3;
else if(!P42) key_y=2;
else if(!P44) key_y=1;
key_val=key_x+ key_y*4;//综合行、列扫描的结果,判断具体位置
switch(key_state)
{
case 0:
if(key_val!=0) key_state = 1; //第一次检测到有按键按下,状态为1
break;
case 1:
if(key_val==0) key_state=0;//第二次(10ms后)若检测到无按键按下,返回状态0
else
{
key_state = 2; //第二次(10ms 后)再次检测到有按键按下状态为2
switch(key_val)
{
case 4: P0=~0x04;P2=0x80;P2=0; break;//按下S4
case 5: P0=~0x05;P2=0x80;P2=0; break;//按下S5
case 6: P0=~0x06;P2=0x80;P2=0; break; //按下S6
case 7: P0=~0x07;P2=0x80;P2=0; break; //按下S7
case 8: P0=~0x08;P2=0x80;P2=0; break;//按下S8
case 9: P0=~0x09;P2=0x80;P2=0; break;//按下S9
case 10: P0=~0x0a;P2=0x80;P2=0; break;//按下S10
case 11: P0=~0x0b;P2=0x80;P2=0; break; //按下S11
case 12: P0=~0x0c;P2=0x80;P2=0; break;//按下S12
case 13: P0=~0x0d;P2=0x80;P2=0; break; //按下S13
case 14: P0=~0x0e;P2=0x80;P2=0; break;//按下S14
case 15: P0=~0x0f;P2=0x80;P2=0; break;//按下S15
case 16: P0=~0x10;P2=0x80;P2=0; break;//按下S16
case 17: P0=~0x11;P2=0x80;P2=0; break;//按下S17
case 18: P0=~0x12;P2=0x80;P2=0; break;//按下S18
case 19: P0=~0x13;P2=0x80;P2=0; break;//按下S19
}
}
case 2:if(key_val==0) key_state = 0;//第三次若检测到无按键按下,返回状态0。
}
}
void main()
{
P0=0xff;P2=0x80;P2=0x00;
P0=0x00;P2=0xa0;P2=0x00;
Time0_init();
while(1)
{
if(countkey>9)
{
countkey=0;
scan_key();
}
}
}