STM32单片机 按键检测&矩阵键盘实操

发布时间 2023-11-02 02:01:47作者: 旺tA菌

目录

1.来先康康原理图

2.按键检测实操

3.按键软件消抖

4.矩阵键盘原理

5.总结

0.本文主要讲解按键检测

1.来先康康原理图

2.按键检测实操

1.1 原理简述

我们知道 GPIO 的输入输出功能分别可以输出或检测一个引脚的高低电平,即当一个 IO 口作为输出引脚时,将一个引脚的状态设为 1 为高电平设为 0 为低电平,当 IO 作为输入引脚时,此引脚的高低电平状态对应 1 和 0.

1.2 按键对应引脚

那么我们使用学习板上的 KEY0 按键(PA0)进行按键检测的实验。让我们看到原理图

1.3CUBEMX 配置

1.3.1 新建工程就不多说啦~选择自己所用的单片机型号,F401 还是 F411。

1.3.2 时钟配置

配置好是这样的

1.3.3 引脚配置,分别对应按键检测和点亮 LED 灯的 IO。PA0 设置为上拉

1.3.4 工程管理并打开工程

1.4 代码

  /* USER CODE BEGIN WHILE */
  while (1)
  {
      if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0)    //判断按键是否被按下
      {

          HAL_Delay(50);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0)
          {
            HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8);   //将PA0设置为翻转电平,即点亮(关闭)led
          }
      }
      /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

编译烧录结束。

  • 效果:

  • 按下 KEY0 蓝灯开启或者关闭

注:如果没有反应先按下RST键哦

3.按键软件消抖

注:也可以使用硬件消抖感兴趣可以自己上网了解哦

3.1 软件消抖原理

通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。 抖动时间的长短由按键的机械特性决定,一般为 5ms ~ 10ms。这是一个很重要的时间参数,在很多场合都要用到。按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。为确保 CPU 对键的一次闭合仅作一次处理,必须去除键抖动。在键闭合稳定时读取键的状态,并且必须判别到键释放稳定后再作处理。

3.2 simple 消抖/

  /* USER CODE BEGIN WHILE */
  while (1)
  {
      if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0)    //判断按键是否被按下
      {

          HAL_Delay(50);
          if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0)
          {
            HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8);   //将翻转PA8的电平,即点亮(关闭)led
          }
      }
      /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

  • 效果:按一下 KEY0,蓝灯由亮变暗或者由暗变亮(红灯改变原有状态)

  • 优点:简单

  • 缺点:HAL_DELAY() 空占用 CPU 资源却不干活,非常可恶,尽量少用。还有该方法其实并没有做到按一次,触发一次该事件,大家试试就知道咯。

3.3 plus 版

  /* USER CODE BEGIN 2 */
    uint32_t tick=HAL_GetTick();
    int key0=1;

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

    key0=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);//检测按键返回键值到变量key里
    if(key0==0) //如果按键被触发
    {
        if(HAL_GetTick()-tick>20) //按键消抖
        {
            tick=HAL_GetTick();
        }
        else
        {
          key0=1;
        }
    }
    if(key0==0)        //按键被按下
    {
        HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8);  //将翻转PA8的电平,即点亮(关闭)led

    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

优点:按一次触发一次,且判断准确。(方法稍微复杂一点点。但简单实用,好评)

3.3 super plus 版

  • 状态机消抖

可以准确的控制按键每一按下和松开时触发的事件。 (有点复杂,需要花比较长的时 间去学习)

4.矩阵键盘原理

2.1 原理图,看到矩阵键盘框框,是这样子嘟

2.2 CUBEMX 配置

从上面的单个按键检测实操工程继续回到 STM32CUBEMX

配置引脚:

结束,生成代码

2.3 KEIL

/* USER CODE BEGIN PFP */
uint32_t keyboard_scan(void)
{ uint8_t press_key=0;
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_15,1);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,0);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,0);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,0);
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12)) press_key=1;
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13)) press_key=2;
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14)) press_key=3;
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_15)) press_key=4;
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_15,0);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,1);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,0);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,0);
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12)) press_key=5;
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13)) press_key=6;
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14)) press_key=7;
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_15)) press_key=8;
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_15,0);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,0);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,1);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,0);
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12)) press_key=9;
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13)) press_key=10;
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14)) press_key=11;
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_15)) press_key=12;
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_15,0);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,0);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,0);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,1);
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12)) press_key=13;
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13)) press_key=14;
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14)) press_key=15;
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_15)) press_key=16;
	return press_key;
	}
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  /* USER CODE BEGIN 2 */
    uint32_t tick=HAL_GetTick();
    int key0=1;

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

    uint32_t key=keyboard_scan();//检测按键返回键值到变量key里
	  if(key!=0)
	  {
		  if(HAL_GetTick()-tick>200) //按键消抖
		  {
			  tick=HAL_GetTick();
		  }
		  else
		  {
			  key=0;
		  }
	  }
    //if(key==1)  do something
    //if(key==2)  do something
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

由于没有学习到串口或 PWM 或者屏幕显示,所以矩阵键盘的实操部分就到达这里。大家已经学习了后面知识的同学可以判断键值来让单片机在屏幕上显示或者控制灯的亮度或者从串口输出。

5.总结

至此,按键输入部分结束,祝大家成功控制按键点亮自己的 led。

ps:笔者编写文档的是时候过于匆忙,格式问题多多谅解~另外,如果文档有任何问题欢迎提出,马上更改

校科协电子部第一次授课

By 马旺塔

2023.10.29