从单片机基础到程序框架(全集 2019pdf版).pdf - 第501页
volatile u nsigned i nt vGu16BeepTi merCnt=0; unsigned c har Gu8Le dStatus_P1_4 =0; //P1.4 所在的 L ED 的状态 unsigned c har Gu8Le dStatus_P1_5 =0; //P1.5 所在的 L ED 的状态 volatile u nsigned c har vGu8Sing leKeySec= 0; volatile u …

上图 103.1.3 3*3 矩阵按键的电路
“无序”是指两个组合按键不分先后顺序,都能构成组合触发。比如,要触发组合键(S1+S2),先按 S1
再按 S2,或者先按 S2 再按 S1,功能都是一样的。
本节程序功能如下:(1)S1 每单击一次,P1.4 所在的 LED 要么从“灭”变成“亮”,要么从“亮”变成
“灭”,在两种状态之间切换。(2)S2 每单击一次,P1.5 所在的 LED 要么从“灭”变成“亮”,要么从“亮”
变成“灭”,在两种状态之间切换。(3)如果先按住 S1 再按 S2,或者先按住 S2 再按 S1,都认为构造了“无
序”组合键,蜂鸣器发出“嘀”的一声。
#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_P1_4(void);
void LedClose_P1_4(void);
void LedOpen_P1_5(void);
void LedClose_P1_5(void);
void VoiceScan(void);
void KeyScan(void);
void SingleKeyTask(void);
void DoubleKeyTask(void);
sbit P3_4=P3^4;
sbit P1_4=P1^4; //P1.4 所在的 LED
sbit P1_5=P1^5; //P1.5 所在的 LED
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_P1_4=0; //P1.4 所在的 LED 的状态
unsigned char Gu8LedStatus_P1_5=0; //P1.5 所在的 LED 的状态
volatile unsigned char vGu8SingleKeySec=0;
volatile unsigned char vGu8DoubleKeySec=0;
void main()
{
SystemInitial();
Delay(10000);
PeripheralInitial();
while(1)
{
SingleKeyTask();
DoubleKeyTask();
}
}
/* 注释一:
* 矩阵按键“无序”触发的两个最关键地方:
* (1)如果是 S1 按键先被按下并且单击触发之后,“马上更新输出列的信号状态”,然后切换到
* “S1 后面所在的步骤里”,进入到 S1 和 S2 两个按键的轮番循环监控之中,如果发现 S1 按键率先
* 被松开了,就把步骤切换到开始的第一步,重新开始新一轮的按键扫描。
* (2)如果是 S2 按键先被按下并且单击触发之后,“马上更新输出列的信号状态”,然后切换到
* “S2 后面所在的步骤里”,进入到 S1 和 S2 两个按键的轮番循环监控之中,如果发现 S2 按键率先
* 被松开了,就把步骤切换到开始的第一步,重新开始新一轮的按键扫描。
* (3)上面两个描述中的两种步骤,“S1 后面所在的步骤里”和“S2 后面所在的步骤里”是分开的,
* 不共用的,这是本节破题的关键。
*/
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:
if(0==Su8ColumnRecord)
{

COLUMN_OUTPUT1=0;
COLUMN_OUTPUT2=1;
COLUMN_OUTPUT3=1;
}
else if(1==Su8ColumnRecord)
{
COLUMN_OUTPUT1=1;
COLUMN_OUTPUT2=0;
COLUMN_OUTPUT3=1;
}
else
{
COLUMN_OUTPUT1=1;
COLUMN_OUTPUT2=1;
COLUMN_OUTPUT3=0;
}
Su16KeyCnt=0;
Su8KeyStep++;
break;
case 2: //等待列输出稳定,但不是去抖动延时
Su16KeyCnt++;
if(Su16KeyCnt>=2)
{
Su16KeyCnt=0;
Su8KeyStep++;
}
break;
case 3:
if(1==ROW_INPUT1&&1==ROW_INPUT2&&1==ROW_INPUT3)
{
Su8KeyStep=1;
Su8KeyLock=0;
Su16KeyCnt=0;
Su8ColumnRecord++;
if(Su8ColumnRecord>=3)
{
Su8ColumnRecord=0;
}
}
else if(0==Su8KeyLock)
{