从单片机基础到程序框架(全集 2019pdf版) - 第489页
上图 10 2.1.3 3*3 矩阵按键的 电路 “任意 行输入”是指 能兼容“异行 输入”与 “同行输入” 这两种按键 状态。 何谓 “异行输入 ” 何谓 “同行输入” ?如上图矩阵按 键, P2.2, P2.1, P2.0 是输 入行, P2.5, P2.4, P2.3 是输出列。 以 S 1 按键为 例,很明显 ,S2 和 S3 都是属于 S 1 的“同行输入” ,都是属于 P2.2 的输入行。除了 S2 和 S3 以外,其它 所…

第一百零二节: 两个“任意行输入”矩阵按键的“有序”组合触发。
【102.1 “异行输入”“同行输入”“有序”。】
上图 102.1.1 有源蜂鸣器电路
上图 102.1.2 LED 电路

上图 102.1.3 3*3 矩阵按键的电路
“任意行输入”是指能兼容“异行输入”与“同行输入”这两种按键状态。
何谓“异行输入”何谓“同行输入”?如上图矩阵按键,P2.2,P2.1,P2.0 是输入行,P2.5,P2.4,P2.3
是输出列。以 S1 按键为例,很明显,S2 和 S3 都是属于 S1 的“同行输入”,都是属于 P2.2 的输入行。除了
S2 和 S3 以外,其它所有的按键都是 S1 的“异行输入”,比如 S5 按键就是 S1 的“异行输入”,因为 S1 是属
于 P2.2 的输入行,而 S5 是属于 P2.1 的输入行。
何谓“有序”组合触发?就是两个按键的触发必须遵守“先后顺序”才能构成“组合触发”。比如,像
电脑的复制快捷键(Ctrl+C),你必须先按住 Ctrl 再按住 C 此时“复制快捷键”才有效,如果你先按住 C 再
按住 Ctrl 此时“复制快捷键”无效。
“异行输入”与“同行输入”,相比之下,“同行输入”更难更有代表性,如果把“同行输入”的程序写
出来了,那么完全按“同行输入”的思路,就可以把“异行输入”的程序写出来。因此,只要把“同行输入”
的程序写出来了,也就意味着“任意行输入”的程序也就实现了。本节以 S1 和 S2 的“同行输入”按键为例,
S1 是主键,类似复制快捷键的 Ctrl 键;S2 是从键,类似复制快捷键的 C 键。要触发组合键(S1+S2),必须
先按住 S1 再按 S2 才有效。功能如下:(1)S1 每单击一次,LED 要么从“灭”变成“亮”,要么从“亮”变
成“灭”,在两种状态之间切换。(2)如果先按住 S1 再按 S2,就认为构造了“有序”组合键,蜂鸣器发出“嘀”
的一声。
#include "REG52.H"
#define KEY_VOICE_TIME 50
#define KEY_SHORT_TIME 20
void T0_time();
void SystemInitial(void) ;
void Delay(unsigned long u32DelayTime) ;
void PeripheralInitial(void) ;
void BeepOpen(void);
void BeepClose(void);
void LedOpen(void);
void LedClose(void);
void VoiceScan(void);
void KeyScan(void);
void SingleKeyTask(void);
void DoubleKeyTask(void);
sbit P3_4=P3^4;
sbit P1_4=P1^4;
sbit ROW_INPUT1=P2^2; //第 1 行输入口。
sbit ROW_INPUT2=P2^1; //第 2 行输入口。
sbit ROW_INPUT3=P2^0; //第 3 行输入口。

sbit COLUMN_OUTPUT1=P2^5; //第 1 列输出口。
sbit COLUMN_OUTPUT2=P2^4; //第 2 列输出口。
sbit COLUMN_OUTPUT3=P2^3; //第 3 列输出口。
volatile unsigned char vGu8BeepTimerFlag=0;
volatile unsigned int vGu16BeepTimerCnt=0;
unsigned char Gu8LedStatus=0;
volatile unsigned char vGu8SingleKeySec=0;
volatile unsigned char vGu8DoubleKeySec=0;
void main()
{
SystemInitial();
Delay(10000);
PeripheralInitial();
while(1)
{
SingleKeyTask();
DoubleKeyTask();
}
}
/* 注释一:
* 两个“任意行输入”矩阵按键“有序”触发的两个最关键地方:
* (1)当 S1 按键被按下单击触发之后, “马上更新输出列的信号状态”,然后切换到后面的步骤。
* (2)在后面的步骤里,进入到 S1 和 S2 两个按键的轮番循环监控之中,如果发现 S1 按键率先
* 被松开了,就把步骤切换到开始的第一步,重新开始新一轮的按键扫描。
* (3)按照这个模板,只需“更改不同的列输出,判断不同的行输入”,就可以实现“任意行输入”
* 矩阵按键的“有序”组合触发。
*/
void KeyScan(void) //此函数放在定时中断里每 1ms 扫描一次
{
static unsigned char Su8KeyLock=0;
static unsigned int Su16KeyCnt=0;
static unsigned char Su8KeyStep=1;
static unsigned char Su8ColumnRecord=0;
switch(Su8KeyStep)
{
case 1: