天天看点

STM32F103系列(十一):按键检测

1、硬件设计

按键机械触点断开、闭合时,由于触电的弹性作用,按键开关不会马上稳定接通或一下子断开,使用按键时会产生11的抖动,需要用软件消抖处理滤波,不方便输入检测。本实验板中连接有按键附带硬件消抖功能,如图1-2,它利用电容充放电的延时消除了波纹,从而简化软件的处理,软件只需要直接检测引脚的电平即可。

STM32F103系列(十一):按键检测
STM32F103系列(十一):按键检测

从按键的原理图可知,这些按键在没有被按下的时候,GPIO引脚的输入状态为低电平(按键所在的电路不通,引脚接地);

当按键按下时,GPIO引脚的输入状态为高电平(按键所在的电路导通,引脚接到电源)。只要我们检测引脚的输入电平,即可判断按键是否被按下。

若使用的实验板按键的连接方式或引脚不一样,只需根据工程修改引脚即可,程序的控制原理相同。

2 软件设计

与LED的相同,为了使工程更加有条理,我们把与按键相关的代码独立分开存储,方便以后移植。在“工程模板”之上新建bsp_key.c及bsp_key.h文件,这些文件也可根据个人喜好命名。这些文件不属于STM32标准库的内容,是由我们自己根据应用需要编写的。

2.1 编程要点

1)使能GPIO端口时钟;

2)初始化GPIO目标引脚为输入模式(浮空输入);

3)编写简单测试程序,检测按键的状态,实现按键控制LED。

2.2 代码分析

1.按键引脚宏定义

同样,在编写按键驱动时,也要考虑更改硬件环境的情况。我们把按键检测引脚相关的宏定义到bsp_key.h文件中,见代码清单1-1。

代码清单1-1 按键检测引脚相关的宏

1 // 引脚定义
    2 #define    KEY1_GPIO_CLK     RCC_APB2Periph_GPIOA
    3 #define    KEY1_GPIO_PORT    GPIOA
    4 #define    KEY1_GPIO_PIN     GPIO_Pin_0
    5
    6 #define    KEY2_GPIO_CLK     RCC_APB2Periph_GPIOC
    7 #define    KEY2_GPIO_PORT    GPIOC
    8 #define    KEY2_GPIO_PIN     GPIO_Pin_13
           

以上代码根据按键的硬件连接,把检测按键输入的GPIO端口、GPIO引脚号以及GPIO端口时钟封装起来了。

2.按键GPIO初始化函数

利用上面的宏,编写按键的初始化函数,见代码清单1-2。

代码清单1-2 按键GPIO初始化函数

1 void Key_GPIO_Config(void)
    2 {
    3     GPIO_Init Type Def GPIO_Init Structure;
    4
    5     /*开启按键端口的时钟*/
    6     RCC_APB2Periph Clock Cmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);
    7
    8     //选择按键的引脚
    9     GPIO_Init Structure.GPIO_Pin = KEY1_GPIO_PIN;
    10     //设置按键的引脚为浮空输入
    11     GPIO_Init Structure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    12     //使用结构体初始化按键
    13     GPIO_Init(KEY1_GPIO_PORT, &GPIO_Init Structure);
    14
    15     //选择按键的引脚
    16     GPIO_Init Structure.GPIO_Pin = KEY2_GPIO_PIN;
    17     //设置按键的引脚为浮空输入
    18     GPIO_Init Structure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    19     //使用结构体初始化按键
    20     GPIO_Init(KEY2_GPIO_PORT, &GPIO_Init Structure);
    21 }
           

函数执行流程如下:

1)使用GPIO_Init Type Def定义GPIO初始化结构体变量,以便后面用于存储GPIO配置。

2)调用库函数RCC_APB2Periph Clock Cmd来使能按键的GPIO端口时钟,调用时使用“|”操作同时配置两个按键的时钟。

3)向GPIO初始化结构体赋值,把引脚初始化成浮空输入模式,其中的GPIO_Pin使用宏KEYx_GPIO_PIN来赋值,使函数的实现方便移植。由于引脚的默认电平受按键电路影响,所以设置成浮空输入。

4)使用以上初始化结构体的配置,调用GPIO_Init函数向寄存器写入参数,完成GPIO的初始化,这里的GPIO端口使用KEYx_GPIO_PORT宏来赋值,也是为了程序移植方便。

5)使用同样的初始化结构体,只修改控制的引脚和端口,初始化其他按键检测时使用的GPIO引脚。

3.检测按键的状态

初始化按键后,就可以通过检测对应引脚的电平来判断按键状态了,见代码清单12-3。

代码清单12-3 检测按键的状态

1 /** 按键按下标志宏
   2   * 若按键按下为高电平,设置KEY_ON=1,KEY_OFF=0
   3   * 若按键按下为低电平,把宏设置成KEY_ON=0,KEY_OFF=1即可
   4   */
   5 #define KEY_ON  1
   6 #define KEY_OFF 0
   7
   8 /**
   9     * @brief   检测是否有按键按下
  10     * @param  GPIOx:具体的端口,x可以是(A...G)
  11     * @param  GPIO_PIN:具体的端口位,可以是GPIO_PIN_x(x可以是0~15)
  12     * @retval  按键的状态
  13     *     @arg KEY_ON:按键按下
  14     *     @arg KEY_OFF:按键没按下
  15     */
  16 uint8_t Key_Scan(GPIO_Type Def* GPIOx,uint16_t GPIO_Pin)
  17 {
  18          /*检测是否有按键按下 */
  19          if (GPIO_Read Input Data Bit(GPIOx,GPIO_Pin) == KEY_ON ) {
  20              /*等待按键释放 */
  21              while (GPIO_Read Input Data Bit(GPIOx,GPIO_Pin) == KEY_ON);
  22              return  KEY_ON;
  23          } else
  24              return KEY_OFF;
  25 }
           

在这里我们定义了一个Key_Scan函数用于扫描按键状态。

GPIO引脚的输入电平可通过读取IDR寄存器对应的数据位来感知,而STM32标准库提供了库函数GPIO_Read Input Data Bit来获取位状态,该函数输入GPIO端口及引脚号,返回该引脚的电平状态,高电平返回1,低电平返回0。

Key_Scan函数中用GPIO_Read Input Data Bit的返回值与自定义的宏KEY_ON对比,若检测到按键按下,则使用while循环持续检测按键状态,直到按键释放,按键释放后Key_Scan函数返回一个KEY_ON值;若没有检测到按键按下,则函数直接返回KEY_OFF。

若按键的硬件没有做消抖处理,则需要在这个Key_Scan函数中做软件滤波,防止波纹抖动引起误触发。

4.main函数

接下来使用main函数编写按键检测程序,见代码清单1-4。

代码清单1-4 按键检测main函数

1 /**
   2     * @brief  main函数
   3     * @param  无
   4     * @retval无
   5     */
   6 int main(void)
   7 {
   8     /* LED端口初始化 */
   9     LED_GPIO_Config();
  10
  11     /*初始化按键*/
  12     Key_GPIO_Config();
  13
  14     /* 轮询按键状态,若按键按下,则反转LED */
  15     while (1) {
  16          if ( Key_Scan(KEY1_GPIO_PORT,KEY1_PIN) == KEY_ON  ) {
  17              /*LED1反转*/
  18              LED1_TOGGLE;
  19          }
  20
  21          if ( Key_Scan(KEY2_GPIO_PORT,KEY2_PIN) == KEY_ON  ) {
  22              /*LED2反转*/
  23              LED2_TOGGLE;
  24          }
  25     }
  26 }
           

代码中初始化LED及按键后,在while函数里不断调用Key_Scan函数,并判断其返回值,若返回值表示按键按下,则反转LED的状态。

3 下载验证

把编译好的程序下载到开发板并复位,按下按键可以控制LED亮、灭状态。