基于蓝桥杯的单片机模块练习——矩阵键盘算法
功能概述
通过矩阵键盘控制8个数码管同时显示一个字符。
C代码
#include "stc15f2k60s2.h"
//行
***it R1 = P3^0;
***it R2 = P3^1;
***it R3 = P3^2;
***it R4 = P3^3;
//列
***it C1 = P4^4;
***it C2 = P4^2;
***it C3 = P3^5;
***it C4 = P3^4;
unsigned char code SMG_duanma[] = {0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,
0xc6,0xa1,0x86,0x8e,
0xbf,0x7f};
void ScanKey();
void DisplayAll(unsigned char num);
void SystemInit();
void SelectHC573(unsigned channel);
void Timer0_Init();
void KeyAction(unsigned char KeyCode);
void main()
{
SystemInit();
Timer0_Init();
while(1)
{
ScanKey();
}
}
void SelectHC573(unsigned channel)
{
switch(channel)
{
case 0 : P2 = (P2 & 0X1F) | 0X00;break;
case 4 : P2 = (P2 & 0X1F) | 0X80;break;
case 5 : P2 = (P2 & 0X1F) | 0XA0;break;
case 6 : P2 = (P2 & 0X1F) | 0XC0;break;
case 7 : P2 = (P2 & 0X1F) | 0XE0;break;
}
}
void SystemInit()
{
SelectHC573(5);
P0 = 0x00;
SelectHC573(0);
P0 = 0xff;
}
void DisplayAll(unsigned char num)
{
SelectHC573(6);
P0 = 0xff;
SelectHC573(7);
P0 = SMG_duanma[num];
}
unsigned char KeyStat[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};//经消抖之后的键值
//矩阵按键编号的映射表,按照键盘标号映射.比如S7就映射0x07
unsigned char code KeyCodeMap[4][4] = {{0x07,0x11,0x15,0x19},
{0x06,0x10,0x14,0x18},
{0x05,0x09,0x13,0x17},
{0x04,0x08,0x12,0x16}
};
void KeyAction(unsigned char KeyCode)//对照着映射表完成相应按键的动作
{
switch(KeyCode)
{
case 0x04 : DisplayAll(4);break;
case 0x05 : DisplayAll(5);break;
case 0x06 : DisplayAll(6);break;
case 0x07 : DisplayAll(7);break;
case 0x08 : DisplayAll(8);break;
case 0x09 : DisplayAll(9);break;
case 0x10 : DisplayAll(10);break;
case 0x11 : DisplayAll(11);break;
case 0x12 : DisplayAll(12);break;
case 0x13 : DisplayAll(13);break;
case 0x14 : DisplayAll(14);break;
case 0x15 : DisplayAll(15);break;
case 0x16 : DisplayAll(16);break;
case 0x17 : DisplayAll(17);break;
case 0x18 : DisplayAll(17);break;
case 0x19 : DisplayAll(17);break;
}
}
void ScanKey()
{
unsigned char i,j;
static unsigned char backup[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};储存上一次的键值
for(i = 0; i<4; i++)
{
for(j = 0; j<4;j++)
{
if(backup[j] != KeyStat[j])
{
if(backup[j] == 0)//松手检测,松开按键后动作
{
KeyAction(KeyCodeMap[j]);
}
backup[j] = KeyStat[j];
}
}
}
}
void Timer0_Init()
{
TMOD = 0X00;
TH0 = (65536 - 1000) / 256;
TL0 = (65536 - 1000) % 256;
EA = 1;
ET0 = 1;
TR0 = 1;
}
void Timer0_Service() interrupt 1
{
unsigned char i;
static unsigned char keyout = 0; //矩阵按键扫描输出索引
static unsigned char Keybuf[4][4] = { //矩阵按键扫描缓冲区
{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}
};
//将一行的4个按键值移入缓冲区
Keybuf[keyout][0] = (Keybuf[keyout][0] << 1) | C1;
Keybuf[keyout][1] = (Keybuf[keyout][1] << 1) | C2;
Keybuf[keyout][2] = (Keybuf[keyout][2] << 1) | C3;
Keybuf[keyout][3] = (Keybuf[keyout][3] << 1) | C4;
//消抖后更新按键状态
for (i=0; i<4; i++) //每行4个按键,所以循环4次
{
if ((Keybuf[keyout] & 0x0F) == 0x00)
{ //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下
KeyStat[keyout] = 0;
}
else if (( Keybuf[keyout] & 0x0F) == 0x0F)
{ //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起
KeyStat[keyout] = 1;
}
}
//执行下一次的扫描输出
keyout++; //输出索引递增
keyout = keyout & 0x03; //索引值加到4即归零
switch (keyout) //根据索引,释放当前输出引脚,拉低下次的输出引脚
{
case 0: R4 = 1; R1 = 0; break;//因为总共有四行,所以同一行是间隔4ms检测一下状态
case 1: R1 = 1; R2 = 0; break;
case 2: R2 = 1; R3 = 0; break;
case 3: R3 = 1; R4 = 0; break;
}
}
相关知识点
keyout = keyout & 0x03; //加到4即归零
keyout = keyout & 0x01; //加到2即归零
keyout = keyout & 0x07; //加到8即归零
keyout = keyout & 0x0f; //加到16即归零
拓展功能
长、短按键的算法
void KeyScan()
{
unsigned char i,j;
static unsigned char backup[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};
for(i=0; i<4; i++)
{
for(j=0; j<4; j++)
{
if(backup[j] != KeySta[j])
{
lkey_flag = 0;
count_key = 0;
while(KeySta[j]==0);
if(backup[j] == 1)
{
if(lkey_flag)
KeyAction(KeyCodemap[j]);//长按键
else
KeyAction(255 - KeyCodemap[j]);//短按键
}
backup[j] = KeySta[j];
}
}
}
}
//****************在中断里的计时判断**********
//count_key每1ms自加一
if(count_key == 1000)
{
lkey_flag = 1;
count_key = 0;
}
//*******************************************
哪位大佬有没有更高级的长短按键判断的算法,告诉兄弟一下。抱拳了!!!
switch (keyout) //根据索引,释放当前输出引脚,拉低下次的输出引脚
{
case 0: R4 = 1; R1 = 0; break;//因为总共有四行,所以同一行是间隔4ms检测一下状态
case 1: R1 = 1; R2 = 0; break;
case 2: R2 = 1; R3 = 0; break;
case 3: R3 = 1; R4 = 0; break;
}
这部分代码在用到串口通讯时需要修改,不能再对R1和R2进行操作。
基于蓝桥杯的单片机模块练习——矩阵键盘算法
功能概述
通过矩阵键盘控制8个数码管同时显示一个字符。
C代码
#include "stc15f2k60s2.h"
//行
***it R1 = P3^0;
***it R2 = P3^1;
***it R3 = P3^2;
***it R4 = P3^3;
//列
***it C1 = P4^4;
***it C2 = P4^2;
***it C3 = P3^5;
***it C4 = P3^4;
unsigned char code SMG_duanma[] = {0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,
0xc6,0xa1,0x86,0x8e,
0xbf,0x7f};
void ScanKey();
void DisplayAll(unsigned char num);
void SystemInit();
void SelectHC573(unsigned channel);
void Timer0_Init();
void KeyAction(unsigned char KeyCode);
void main()
{
SystemInit();
Timer0_Init();
while(1)
{
ScanKey();
}
}
void SelectHC573(unsigned channel)
{
switch(channel)
{
case 0 : P2 = (P2 & 0X1F) | 0X00;break;
case 4 : P2 = (P2 & 0X1F) | 0X80;break;
case 5 : P2 = (P2 & 0X1F) | 0XA0;break;
case 6 : P2 = (P2 & 0X1F) | 0XC0;break;
case 7 : P2 = (P2 & 0X1F) | 0XE0;break;
}
}
void SystemInit()
{
SelectHC573(5);
P0 = 0x00;
SelectHC573(0);
P0 = 0xff;
}
void DisplayAll(unsigned char num)
{
SelectHC573(6);
P0 = 0xff;
SelectHC573(7);
P0 = SMG_duanma[num];
}
unsigned char KeyStat[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};//经消抖之后的键值
//矩阵按键编号的映射表,按照键盘标号映射.比如S7就映射0x07
unsigned char code KeyCodeMap[4][4] = {{0x07,0x11,0x15,0x19},
{0x06,0x10,0x14,0x18},
{0x05,0x09,0x13,0x17},
{0x04,0x08,0x12,0x16}
};
void KeyAction(unsigned char KeyCode)//对照着映射表完成相应按键的动作
{
switch(KeyCode)
{
case 0x04 : DisplayAll(4);break;
case 0x05 : DisplayAll(5);break;
case 0x06 : DisplayAll(6);break;
case 0x07 : DisplayAll(7);break;
case 0x08 : DisplayAll(8);break;
case 0x09 : DisplayAll(9);break;
case 0x10 : DisplayAll(10);break;
case 0x11 : DisplayAll(11);break;
case 0x12 : DisplayAll(12);break;
case 0x13 : DisplayAll(13);break;
case 0x14 : DisplayAll(14);break;
case 0x15 : DisplayAll(15);break;
case 0x16 : DisplayAll(16);break;
case 0x17 : DisplayAll(17);break;
case 0x18 : DisplayAll(17);break;
case 0x19 : DisplayAll(17);break;
}
}
void ScanKey()
{
unsigned char i,j;
static unsigned char backup[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};储存上一次的键值
for(i = 0; i<4; i++)
{
for(j = 0; j<4;j++)
{
if(backup[j] != KeyStat[j])
{
if(backup[j] == 0)//松手检测,松开按键后动作
{
KeyAction(KeyCodeMap[j]);
}
backup[j] = KeyStat[j];
}
}
}
}
void Timer0_Init()
{
TMOD = 0X00;
TH0 = (65536 - 1000) / 256;
TL0 = (65536 - 1000) % 256;
EA = 1;
ET0 = 1;
TR0 = 1;
}
void Timer0_Service() interrupt 1
{
unsigned char i;
static unsigned char keyout = 0; //矩阵按键扫描输出索引
static unsigned char Keybuf[4][4] = { //矩阵按键扫描缓冲区
{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}
};
//将一行的4个按键值移入缓冲区
Keybuf[keyout][0] = (Keybuf[keyout][0] << 1) | C1;
Keybuf[keyout][1] = (Keybuf[keyout][1] << 1) | C2;
Keybuf[keyout][2] = (Keybuf[keyout][2] << 1) | C3;
Keybuf[keyout][3] = (Keybuf[keyout][3] << 1) | C4;
//消抖后更新按键状态
for (i=0; i<4; i++) //每行4个按键,所以循环4次
{
if ((Keybuf[keyout] & 0x0F) == 0x00)
{ //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下
KeyStat[keyout] = 0;
}
else if (( Keybuf[keyout] & 0x0F) == 0x0F)
{ //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起
KeyStat[keyout] = 1;
}
}
//执行下一次的扫描输出
keyout++; //输出索引递增
keyout = keyout & 0x03; //索引值加到4即归零
switch (keyout) //根据索引,释放当前输出引脚,拉低下次的输出引脚
{
case 0: R4 = 1; R1 = 0; break;//因为总共有四行,所以同一行是间隔4ms检测一下状态
case 1: R1 = 1; R2 = 0; break;
case 2: R2 = 1; R3 = 0; break;
case 3: R3 = 1; R4 = 0; break;
}
}
相关知识点
keyout = keyout & 0x03; //加到4即归零
keyout = keyout & 0x01; //加到2即归零
keyout = keyout & 0x07; //加到8即归零
keyout = keyout & 0x0f; //加到16即归零
拓展功能
长、短按键的算法
void KeyScan()
{
unsigned char i,j;
static unsigned char backup[4][4] = {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};
for(i=0; i<4; i++)
{
for(j=0; j<4; j++)
{
if(backup[j] != KeySta[j])
{
lkey_flag = 0;
count_key = 0;
while(KeySta[j]==0);
if(backup[j] == 1)
{
if(lkey_flag)
KeyAction(KeyCodemap[j]);//长按键
else
KeyAction(255 - KeyCodemap[j]);//短按键
}
backup[j] = KeySta[j];
}
}
}
}
//****************在中断里的计时判断**********
//count_key每1ms自加一
if(count_key == 1000)
{
lkey_flag = 1;
count_key = 0;
}
//*******************************************
哪位大佬有没有更高级的长短按键判断的算法,告诉兄弟一下。抱拳了!!!
switch (keyout) //根据索引,释放当前输出引脚,拉低下次的输出引脚
{
case 0: R4 = 1; R1 = 0; break;//因为总共有四行,所以同一行是间隔4ms检测一下状态
case 1: R1 = 1; R2 = 0; break;
case 2: R2 = 1; R3 = 0; break;
case 3: R3 = 1; R4 = 0; break;
}
这部分代码在用到串口通讯时需要修改,不能再对R1和R2进行操作。
举报