stm32矩阵按键状态机(可快速移植)


首先声明,所写内容是协会成员集体成果。其中过程艰难坎坷,寻找过大量资料,失败过无数次,最终成功运行。其中仍有不足,欢迎大佬批评指正!


目录

一、扫描按键思路

二、状态机思路

三、代码部分

四、小结

 


一、扫描按键思路

1.原理图

stm32矩阵按键状态机(可快速移植)_第1张图片

 2.使用引脚的选择

IO口的选择很重要,一定要选没有被复用的空闲端口,以及最好是连在一起的GPIO口,首先被复用的话就直接无法正常输入输出,也就无法编程;

连在一起是因为4*4矩阵键盘需要8个引脚,用库函数操作太麻烦了,所以我们直接采用寄存器操作,连在一起的话寄存器比较容易控制(其实我们也尝试过不连在一起,但由于寄存器方面知识学的不太好,怎么也实现不了,希望有大佬指点)

3.原理讲解

stm32矩阵按键状态机(可快速移植)_第2张图片 

我们使用的方法是逐行扫描,读取列的电平来判断键值

  1. 首先,将PB8到PB11全部输出为高电平,如果,PB12到PB15不为0,则,有键按下。
  2. 然后,进行逐行检测,即将P8到P11依次置高,读取PB12到PB15的值,判断具体为哪个键被按下

其中PB12到PB15一直为下拉输入模式,用于读取按键变化

二、状态机思路

状态机我们先配置一个定时器,如TIM2,用于每10ms进入中断扫描一次按键,正好跳过抖动

然后状态设为3个,分别是:

 状态一:KEY_Up ,空闲状态检测是否有按键按下

 状态二:KEY_Rowscan,逐行检测判断具体哪个键按下

 状态三:KEY_Wait,等待松手返回状态一

stm32矩阵按键状态机(可快速移植)_第3张图片

 如果对状态机还有疑问,可参考这位大佬的:

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.
  *
  * 

© COPYRIGHT 2022 XuQQ

****************************************************************************** */ /* 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.
  *
  * 

© COPYRIGHT 2022 XuQQ/center>

****************************************************************************** */ /* 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.
  *
  * 

© COPYRIGHT 2011 XuQQ

****************************************************************************** */ /* 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****/

四、小结

 写完了,还是有一些瑕疵,但还是希望能对你有所帮助,欢迎大佬批评指正!

视频效果:stm32矩阵按键状态机效果_哔哩哔哩_bilibili

你可能感兴趣的:(stm32学习,单片机,stm32)