基于STM32的按键扫描测试程序(学习记录):
目录:
- 源码;
- 4x4按键原理;
- 按键扫描逻辑;
Tips:
- 粘贴代码时,粘贴在源文件存放的位置中(如:HARDWARE中的.c和.h文件),用C++编译器打开,而不是kei;最后keil会正常显示中文字符;
- 程序使用嵌套循环实现4x4按键扫描,如果IO口设置过乱时,将循环拆分即可;
key4x4.h源文件
#ifndef __KEY4x4_H
#define __KEY4x4_H
#include "sys.h"
#define KEY_X(X) PEin(X) // 尽量避免使用PD以上GPIO,便于移植;
#define KEY_Y(Y) PEout(Y)
#define ALL_DOWN_KEY_Y { KEY_Y(11) = 0; KEY_Y(12) = 0; KEY_Y(13) = 0; KEY_Y(14) = 0;}
void KEY4x4_Init(void); // IO口初始化
u8 KEY4x4_Scan(void); // 矩阵按键反馈函数 // 可配置任意矩阵按键使用!!
u8 KEY16_Scan(void);
/**************
其他按键扫描方案:
按键使用8个输入IO口, 且所有IO口一端接VCC/VSS;
程序框架:
扫描检测哪两个IO口输入高/低电平;VCC/VSS
根据对应坐标,return对应编号;
**************/
#endif
key4x4.c源文件
#include "stm32f10x.h"
#include "key4x4.h"
#include "sys.h"
#include "delay.h"
#include "usart.h"
/*************************
X:
PEin 7-10
Y:
PEout 11-14
*************************/
// 矩阵按键初始化函数
void KEY4x4_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10;//KEY0-KEY1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置成下拉输入
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14; //LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOE, &GPIO_InitStructure); //根据设定参数初始化GPIOE
}
// 使所有输出拉低;初始化; // 可以使用define宏定义,执行速度更快,不用跳转函数!!
static void KEY_ALL_Pull_Down(void)
{
KEY_Y(11) = 0;
KEY_Y(12) = 0;
KEY_Y(13) = 0;
KEY_Y(14) = 0;
}
// 4x4按键扫描函数
// 使用一个嵌套循环,完成扫描X和Y;
// 原理: 通过Y 依次输出高电平,
// 扫描X 那个IO口输入高电平;
// X轴:输入检查、扫描;
// Y轴:设置输出状态;
// 该函数适合任意排列矩阵按键,只需修改循环中对应编号!!
// 注意: 1. 改变IO口时,该函数还需要改变循环中IO口编号;(可以定义好IO口编号,便于修改)
// 2. 该函数同样有优先级问题! 即同时按下时,只反馈先被扫描到的(0-15标号最小的)
// 3. 函数同一坐标轴的IO口编号必须相邻或能有 规律递增可寻;(否则无法用循环判断)
// 4. 暂时未添加功能(模式): 按键复用 和 长按;
// 2020-11-13 返回值调整为:1-16
// 11/14 不支持连按;解决重复反馈的问题;
u8 KEY4x4_Scan(void)
{
int i,j;
u8 IO_Sign = 0; // 很简便的一个IO反馈方式标签!!! 且嵌套循环特有!! // 能返回0-15,适合任意排列矩阵按键
static key_up = 1;
//KEY_ALL_Pull_Down(); // 初始化所有按键输出拉低;
for (i = 11; i <= 14; i++) // Y输出IO口编号;
for (j = 7; j <= 10; j++,IO_Sign++) // X输出IO口编号; // 递增IO_Sign,反馈对应值(0-15);
{
KEY_Y(i) = 1; // 使PEout(i)输出高电平;
if (KEY_Y(i)) // 扫描Y输出高电平, 可以取消此判断; 因为必须输出高电平时,才能正常判断!!
{
if (KEY_X(j) && key_up) // 当输入检查到高电平时;
{
key_up = 0;
printf("按键扫描反馈: %d \r\n",IO_Sign);
return IO_Sign;
}
else if (!KEY_X(7)&&!KEY_X(8)&&!KEY_X(9)&&!KEY_X(10)) // 当所有输入检测到低电平时,再次使能按键; 防止重复反馈
{
key_up = 1;
KEY_ALL_Pull_Down(); // 初始化所有按键输出拉低(低电平);必须在此位置;
}
}
else
printf("PEout:IO口%d输出异常! \r\n ", i);
}
delay_ms(10); // 按键防抖;
}
/******************************************标准扫描函数*********************************************/
// 支持连按
u8 KEY16_Scan(void)
{
int i,j;
u8 IO_Sign = 0; // 很简便的一个IO反馈方式标签!!! 且嵌套循环特有!! // 能返回0-15,适合任意排列矩阵按键
ALL_DOWN_KEY_Y // 初始化所有按键输出拉低;
for (i = 11; i <= 14; i++) // Y输出IO口编号;
for (j = 7; j <= 10; j++,IO_Sign++) // X输出IO口编号; // 递增IO_Sign,反馈对应值(0-15);
{
KEY_Y(i) = 1; // 使PEout(i)输出高电平;
if (KEY_X(j)) // 当输入检查到高电平时;
return IO_Sign;
}
delay_ms(20); // 按键防抖; // 连按延时;
}
*4x4按键原理图
-
按键工作原理:
当按键被按下时,相连的电路导通;即S1按下时,位于0行0列的线短路,使标号4和5对应的IO口相连(导通);
最后通过扫描检测输入输出状态即可判断出对应按键被按下; -
程序设计思路:
程序通过依次使标号1、2、3、4(列0-3)输出高电平,判断5/6/7/8(行0-3)状态;完成按键扫描;