目录
一、前提
按键这一板块主要是以记忆为主,我直接给大家讲解代码去实现我要配置的功能。本次我要做的项目是板子上的按键有S4~S19,我希望任意一个按键可以显示对应的两位数,按下两个不同的按键可以一前一后各显示出两位数字,也就是生成四位数字,再按下另外一个按键实现清零的功能。
按键的原理图

这是板子上按键的原理图,如果要切换独立按键和矩阵键盘,那么我们需要将板子上J5部分的小插口的东西插到对应的位置上去,本项目是在KBD上,12是KBD矩阵键盘,23是BTN独立按键,如下图:

那么如何扫描呢?答:先锁定行,再锁定列,举个例子:假如说,我现在想要扫描S4这个按键,我们先要锁定从左往右数第一列连接对应的引脚是P44,S4对应的行是P33

二、代码配置

我们这里只用到Timer、init、seg、key,led,本文章没写的代码可以去我这个蓝桥杯第一个系列观看,里面有很详细的代码简介
bsp_key.c文件
cs
#include "bsp_key.h"
//函数名:按键码值读取函数
//入口参数:无
//返回值:按键的码值
//函数功能:返回按键码
unsigned char Key_Read(void)
{
unsigned int Key_NEW;
unsigned char Key_Value;//返回值
P44 = 0;P42 = 1;P35 = 1;P34 = 1;//第一列扫描
Key_NEW = P3 & 0X0F; //P3 = 0000 1000---P37~P30,高位无效,只看P33~P30
P44 = 1;P42 =0;P35 = 1;P34 = 1;//第二列扫描
Key_NEW = (Key_NEW << 4) | (P3 & 0X0F); //将原来的数值挪到次4位,本次数值放到最低4位,占用了8位
P44 = 1;P42 =1;P35 = 0;P34 = 1;//第三列扫描
Key_NEW = (Key_NEW << 4) | (P3 & 0X0F); //将原来的数值挪到次次4位,本次数值放到最低4位,占用了12位
P44 = 1;P42 =1;P35 = 1;P34 = 0;//第三列扫描
Key_NEW = (Key_NEW << 4) | (P3 & 0X0F); //将原来的数值挪到次次次4位,本次数值放到最低4位,占用了16位
switch(~Key_NEW)//Key_Value的数值对应按键的编号
{
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;
}
疑问
在中switch中,为什么进行Key_New的取反?
答:一般来说,按键配置的时候,我们配置的是上拉输入,在没按按键的时候,对应的是高电平,按下去,是低电平,那么我们通过取反,就是按下去成为高电平1,利用哪个地方是1,进行选择对应的case
main.c文件
cs
#include "bsp_init.h"
#include "bsp_seg.h"
#include "Timer0.h"
#include "bsp_key.h"
#include "bsp_key.h"
#include "STDIO.H"
/* 函数声明 */
void Key_Proc(void);//按键处理
void Seg_Proc(void);//显示处理
/* 全局变量 */
unsigned char seg_buf[8];//放置字符串转换后的段码到数组
unsigned char seg_string[10];//放置字符串
unsigned char pos = 0;//中断显示专用
unsigned char Key_Value;//读取按键的数值存储变量
unsigned char Key_Down,Key_Old;
unsigned char num_buffer[2] = {0, 0}; // 存储2个按键编号
unsigned char num_count = 0; // 当前存储的数字个数
unsigned char Seg_Show_Num;//准备显示出来的数值
void main()
{
Cls_Peripheral();
Timer0Init(); //1毫秒@12.000MHz
EA = 1;
while(1)
{
Key_Proc();//按键处理
Seg_Proc();//显示处理
}
}
/* Timer0 interrupt routine */
void tm0_isr() interrupt 1
{
Seg_Disp( seg_buf, pos );
if(++pos ==8) pos = 0;
}
/* Key_Proc */
void Key_Proc(void)//按键处理,底层数据变更
{
Key_Value = Key_Read();//读取按键按下的编号
Key_Down = Key_Value & (Key_Old ^ Key_Value);//^异或(0000^0101)= 0101 0101 & 0101 = //0101 如果按键发生了下降沿的变化,输出结果和本次按键数值相同
//^异或(0101^0101)= 0000 0101 & 0000 = //0000 如果按键发生了下降沿的变化,输出结果和本次按键数值相同
Key_Old = Key_Value;
if(Key_Down)//如果捕捉到下降沿跳变
{
if (num_count < 2) // 如果存储的按键个数小于2
{
num_buffer[num_count++] = Key_Down; // 存储按键编号
}
else // 如果已经存储了两个按键编号
{
// 清零操作
num_count = 0; // 清空按键个数
}
}
}
/* Seg_Proc */
void Seg_Proc(void)//显示处理,显示信息生成
{
if (num_count == 1) // 如果只存储了一个按键编号
{
// 显示第一个按键编号的两位数字
sprintf(seg_string, " %02d", (unsigned int)num_buffer[0]);
}
else if (num_count == 2) // 如果存储了两个按键编号
{
// 显示两个按键编号的四位数字
sprintf(seg_string, " %02d%02d", (unsigned int)num_buffer[0], (unsigned int)num_buffer[1]);
}
else // 如果没有存储任何按键编号
{
// 显示全0
sprintf(seg_string, " 0000");
}
Seg_Tran( seg_string,seg_buf);
}
main.c文件的详细讲解
假如说,我现在按下去了S4,那么检测到了S4处有下降沿,并且将这个数值给一个变量Key_Val,然后这个变量就给到了Seg_Show_Num,此刻还是一个二进制数,无法显示到数码管上,然后将这个Seg_Show_Num通过sprintf转化成字符串,字符串在Seg_Disp函数下,将段码转化成能看懂的数字,最后利用定时器中断每1ms进行刷新数码管上的东西
-
显示逻辑调整 : 在
Seg_Proc
函数中:-
如果
num_count
为0,显示全0。 -
如果
num_count == 2
,显示两个按键编号的四位数字(如0405
)。 -
如果
num_count == 1
,只显示第一个按键编号的两位数字(如04
)。
-
-
按键逻辑调整:
在
Key_Proc
函数中:-
如果
num_count == 2
,按下任意按键清零。 -
如果
num_count < 2
,存储按键编号。
-
-
数码管显示位数调整:
数码管的动态扫描范围为8位,显示内容通过
sprintf
格式化为8位数码管的显示格式。
功能实现
-
按下第一个按键:
- 显示该按键对应的两位数字(如
04
)。
- 显示该按键对应的两位数字(如
-
按下第二个按键:
- 显示两个按键对应的四位数字(如
0405
)。
- 显示两个按键对应的四位数字(如
-
按下任意第三个按键:
- 清零显示内容,显示
0000
。
- 清零显示内容,显示
注意事项
确保按键编号S4
到S19
与实际硬件的按键编号一致。
如果按键编号不是从4
到19
的连续数字,需要根据实际硬件调整按键编号的判断逻辑。
显示内容前面有4个空格,确保显示内容在8位数码管的中间位置。如果需要调整显示位置,可以修改sprintf
中的空格数量。