首先声明,所写内容是协会成员集体成果。其中过程艰难坎坷,寻找过大量资料,失败过无数次,最终成功运行。其中仍有不足,欢迎大佬批评指正!
目录
一、扫描按键思路
二、状态机思路
三、代码部分
四、小结
一、扫描按键思路
1.原理图
2.使用引脚的选择
IO口的选择很重要,一定要选没有被复用的空闲端口,以及最好是连在一起的GPIO口,首先被复用的话就直接无法正常输入输出,也就无法编程;
连在一起是因为4*4矩阵键盘需要8个引脚,用库函数操作太麻烦了,所以我们直接采用寄存器操作,连在一起的话寄存器比较容易控制(其实我们也尝试过不连在一起,但由于寄存器方面知识学的不太好,怎么也实现不了,希望有大佬指点)
3.原理讲解
我们使用的方法是逐行扫描,读取列的电平来判断键值
- 首先,将PB8到PB11全部输出为高电平,如果,PB12到PB15不为0,则,有键按下。
- 然后,进行逐行检测,即将P8到P11依次置高,读取PB12到PB15的值,判断具体为哪个键被按下
(其中PB12到PB15一直为下拉输入模式,用于读取按键变化)
二、状态机思路
状态机我们先配置一个定时器,如TIM2,用于每10ms进入中断扫描一次按键,正好跳过抖动
然后状态设为3个,分别是:
状态一:KEY_Up ,空闲状态检测是否有按键按下
状态二:KEY_Rowscan,逐行检测判断具体哪个键按下
状态三:KEY_Wait,等待松手返回状态一
如果对状态机还有疑问,可参考这位大佬的:
https://blog.csdn.net/xdedmbb/article/details/129738797?app_version=5.15.0&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22129738797%22%2C%22source%22%3A%22xdedmbb%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app
三、代码部分
定时器部分需自己配,这里只展示按键部分和main.c
1.Matrix_Key.h
/**
******************************************************************************
* @file Matrix_Key.h
* @author 22级电子协会全体成员
* @version V1.0
* @date 18-March-2023
* @brief This file contains all the functions prototypes for the KEY
* firmware library.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, XuQQ SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT
* OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2022 XuQQ</center></h2>
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MATRIX_KEY_H
#define __MATRIX_KEY_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "sys.h"
/** @defgroup KEY_Exported_Macros 宏定义
* @{
*/
#define KEY_Up 1
#define KEY_Rowscan 2
#define KEY_Wait 3
#define key_allput_High GPIO_Write(GPIOB,(GPIOB_Out | 0x0f00)) //先让PB8到PB11全部输出高。
#define key_judge_have (GPIOB_In) != 0x0000 //如果,PB12到PB15不为0,则,有键按下
#define First_rowscan GPIO_Write(GPIOB,(GPIOB_Out | 0x0100)) //让PB11到PB8输出二进制的0001.
#define Second_rowscan GPIO_Write(GPIOB,(GPIOB_Out | 0x0200)) //让PB11到PB8输出二进制的0010.
#define Third_rowscan GPIO_Write(GPIOB,(GPIOB_Out | 0x0400)) //让PB11到PB8输出二进制的0100.
#define Fourth_rowscan GPIO_Write(GPIOB,(GPIOB_Out | 0x0800)) //让PB11到PB8输出二进制的1000.
#define key_row_down (GPIOB_In) > 0x0000 //单行 有按键按下
#define key_row_up (GPIOB_In) == 0x0000 //松手
#define GPIOB_Out GPIOB->ODR & 0xf0ff
#define GPIOB_In GPIOB->IDR & 0xf000
#define FALSE 0
#define TRUE 1
/**
* @}
*/
void Key_GPIO_Init(void);//IO初始化
void KEY_Scan(void); //按键扫描函数
#ifdef __cplusplus
}
#endif
#endif /* __KEY_H */
/******************* (C) COPYRIGHT 2022 XuQQ *****END OF FILE****/
2.Matrix_Key.c
/**
******************************************************************************
* @file Matrix_Key.c
* @author 22级电子协会全体成员
* @version V1.0
* @date 18-March-2023
* @brief This file provides all the KEY firmware functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, XuQQ SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT
* OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2022 XuQQ/center></h2>
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "Matrix_Key.h"
#include "delay.h"
/**
* @brief void KEY_Init(void); // 初始化程序
* @note 初始化程序
* @param None
* @retval None
*/
//4*4矩阵键盘 已经在STM32F103测试通过。
//2013-08-02 BY hjlmgc
///
//GPIO的硬件分配:
//第0行:PB8 ----|------|------|------|
//第1行:PB9 ----|------|------|------|
//第2行:PB10 ----|------|------|------|
//第3行:PB11 ----|------|------|------|
// PB12 PB13 PB14 PB15
// 第0列 第1列 第2列 第3列
/
//键值:
//1----2----3----C
//4----5----6----D
//7----8----9----E
//A----0----B----F
/
#define KEY_WAY_1 //第一种方法
//
//KEY_WAY_1的GPIO初始化
//
void Key_GPIO_Init(void)
{
#ifdef KEY_WAY_1
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //PB8-PB11推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PB12-15 下拉输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
#endif
}
//初始状态4列全部置0,逐行检测
///
u8 key_return=10;
void KEY_Scan(void)
{
#ifdef KEY_WAY_1
static u8 key_state=KEY_Up;
static u8 KEY_flag=FALSE;
int KeyVal=-1; //keyVal为按键数值
switch(key_state)
{
/********************状态1:KEY_Up*********************/
case KEY_Up:
{
key_allput_High;//先让PB8到PB11全部输出高。
if(key_judge_have)//如果,PB12到PB15不为0,则,有键按下
key_state = KEY_Rowscan;//判断是否抖动
}
break;
/********************状态2:KEY_Rowscan*********************/
case KEY_Rowscan:
{
if(KEY_flag==FALSE)
{
//扫描第一行
First_rowscan;
if(key_row_down)
{
switch(GPIOB_In) //对PB15到PB12的值进行判断,以输出不同的键值。
{
case 0x1000: KeyVal=1;KEY_flag=TRUE; break;
case 0x2000: KeyVal=2;KEY_flag=TRUE; break;
case 0x4000: KeyVal=3;KEY_flag=TRUE; break;
case 0x8000: KeyVal='C';KEY_flag=TRUE; break;
default: break;
}
// key_state = KEY_Wait;
}
}
if(KEY_flag==FALSE)
{
//扫描第二行
Second_rowscan;
if(key_row_down)
{
switch(GPIOB_In) //对PB15到PB12的值进行判断,以输出不同的键值。
{
case 0x1000: KeyVal=4;KEY_flag=TRUE; break;
case 0x2000: KeyVal=5;KEY_flag=TRUE; break;
case 0x4000: KeyVal=6;KEY_flag=TRUE; break;
case 0x8000: KeyVal='D';KEY_flag=TRUE; break;
default: break;
}
// key_state = KEY_Wait;
}
}
if(KEY_flag==FALSE)
{
//扫描第三行
Third_rowscan;
if(key_row_down)
{
switch(GPIOB->IDR & 0xf000) //对PB15到PB12的值进行判断,以输出不同的键值。
{
case 0x1000: KeyVal=7;KEY_flag=TRUE; break;
case 0x2000: KeyVal=8;KEY_flag=TRUE; break;
case 0x4000: KeyVal=9;KEY_flag=TRUE; break;
case 0x8000: KeyVal='E';KEY_flag=TRUE; break;
default: break;
}
// key_state = KEY_Wait;
}
}
if(KEY_flag==FALSE)
{
//扫描第四行
Fourth_rowscan;
if(key_row_down)
{
switch(GPIOB->IDR & 0xf000) //对PB15到PB12的值进行判断,以输出不同的键值。
{
case 0x1000: KeyVal='A';KEY_flag=TRUE; break;
case 0x2000: KeyVal=0;KEY_flag=TRUE; break;
case 0x4000: KeyVal='B';KEY_flag=TRUE; break;
case 0x8000: KeyVal='F';KEY_flag=TRUE; break;
default: break;
}
// key_state = KEY_Wait;
}
}
if(KEY_flag==TRUE)
key_state = KEY_Wait;
}
break;
/********************状态3:KEY_Wait*********************/
case KEY_Wait:
{
if(key_row_up)
{
key_state = KEY_Up;//完成一次按键动作,切换到状态1
}
}
break;
}
if(KEY_flag == TRUE)
{
key_return = KeyVal;
KEY_flag = FALSE;
}
#endif
}
/******************* (C) COPYRIGHT 2022 XUQQ *****END OF FILE****/
3.main.c
/**
******************************************************************************
* @file main.c
* @author 22级电子协会全体成员
* @version V3.5.0
* @date 18-March-2023
* @brief Main program body.
* (01)初始化按键;
* (02)按下按键控制相应的LED灯亮
*
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2011 XuQQ</center></h2>
******************************************************************************
*/
/* Includes ----------------------------------库文件--------------------------*/
#include "stm32f10x.h"
#include "bmp.h"
/** @addtogroup STM32F10x_StdPeriph_Examples
* @{
*/
/* Private typedef --------------------------变量类型重新定义-----------------*/
/* Private define ---------------------------私有定义-------------------------*/
/* Private macro ----------------------------私有宏定义-----------------------*/
/* Private variables ------------------------私有变量-------------------------*/
/* Private function prototypes --------------私有函数属性---------------------*/
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/* Private functions ------------------------私有函数-------------------------*/
/**
* @brief Main program.
* @note
* @param None
* @retval None
*/
int main(void)
{
LED_Init();
Key_GPIO_Init();
KEY_Scan();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
TIM2_Int_Init(19, 7199);//定时2ms进一次中断
while(1)
{
if(key_return==1)
{
PAout(0)=!PAout(0);//LED0取反
key_return=10;
}
if(key_return==2)
{
PAout(1)=!PAout(1);//LED1取反
key_return=10;
}
if(key_return==4)
{
PAout(0)=!PAout(0);//LED0取反
key_return=10;
}
if(key_return==7)
{
PAout(1)=!PAout(1);//LED1取反
key_return=10;
}
if(key_return==0)
{
PAout(0)=!PAout(0);//LED0取反
key_return=10;
}
}
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**
* @}
*/
/**
* @}
*/
/******************* (C) COPYRIGHT 2011 XuQQ *****END OF FILE****/
四、小结
写完了,还是有一些瑕疵,但还是希望能对你有所帮助,欢迎大佬批评指正!文章来源:https://www.toymoban.com/news/detail-671254.html
视频效果:stm32矩阵按键状态机效果_哔哩哔哩_bilibili文章来源地址https://www.toymoban.com/news/detail-671254.html
到了这里,关于stm32矩阵按键状态机(可快速移植)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!