跳至主要內容

按键输入

大约 4 分钟

简介

本文将介绍使用 Air001 开发板按键打印按键状态。

硬件准备

Air001开发板一块。

提示

在 Air001 开发板上,BOOT按键可作为通用按键使用,GPIO 编号为PB6,具体可参考 Air001 硬件手册。

软件部分

首先,在代码的开头定义一下全局变量:

int ButtonState = LOW;
#define Button PB_6
  • 定义ButtonState变量,用于存储上一次的按键状态。
  • Button的值定义为PB_6BOOT按键所属的 GPIO。

接着,在setup()函数中,添加如下代码:

void setup() {
  Serial.begin(9600);
  pinMode(Button, INPUT_PULLDOWN);
}
  • 初始化串口为9600波特率,用于打印按键状态。
  • 使用pinMode函数初始化PB6这个GPIO,并且设置为INPUT_PULLDOWN下拉输入模式。

最后,我们在loop()函数中添加剩下的代码,轮询当前 GPIO 的状态:

void loop() {
  int state = digitalRead(Button);
  if(ButtonState==state)
    return;
  if (state == LOW) {
    Serial.println("key up");
  } else {
    Serial.println("key pressed");
  }
  ButtonState = state;
}
  • 我们首先获取这一次的按键电平状态,存入state变量中。
  • 接着对比这一次的电平是否变化,如果没变化,退出这次检测。
  • 如果有变化,我们打印一下当前按钮的电平状态,这里使用了三元运算符
  • 最后将当前的电平状态存入ButtonState,提供给下一次读取使用。

输出结果

可以在串口监视器中看到:

  • 当按下按键时,打印key pressed
  • 松开时打印key up
key pressed
key up
key pressed
key up
key pressed
key up
key pressed
key up

注意

由于使用了BOOT按键,有概率会影响到自动进入BOOT模式的逻辑。
如若无法进入BOOT模式导致无法烧录,可尝试下面的步骤进行烧录:

  • 断开 USB 的连接
  • 按住BOOT按键,不要松开
  • 插入 USB
  • 松开BOOT按键
  • 点击电脑上的烧录按键,开始烧录

进一步优化

我们会发现,loop()函数中只进行了轮询按键的判断,如果这个函数中添加了其他耗时的操作(比如进行了delay操作),那么按键打印将变得不够及时。

我们可以使用GPIO 中断来摆脱这种轮询逻辑造成的问题。

提示

中断就是 CPU 在运行过程中上报的一种异常(只是叫做异常,不一定真的运行异常),它可以打断当前代码的运行,优先执行中断的操作。
中断处理完后,再继续运行当前代码。
这里的GPIO 中断就是当 GPIO 的状态符合某种条件时,会触发的中断

首先,在代码的开头定义一下全局变量:

#define Button PB_6
  • Button的值定义为PB_6BOOT按键所属的 GPIO。

接着,新建一个中断回调函数,该函数用于触发中断后,进行调用

void onChange() {
  if (digitalRead(Button) == LOW) {
    Serial.println("key up");
  } else {
    Serial.println("key pressed");
  }
}
  • 当触发onChange函数后,获取一下当前的GPIO状态,用来判断时按下还是松开

提示

中断回调函数是这个中断被触发后会被调用的函数。当这个函数运行完毕后,其他代码会继续执行。

setup()函数中,添加如下代码:

void setup() {
  Serial.begin(9600);      //打开串口
  pinMode(Button, INPUT_PULLDOWN);  //设置管脚为输入
  attachInterrupt(digitalPinToInterrupt(Button), onChange, CHANGE);
  /*
   LOW 当引脚为低电平时,触发中断
   CHANGE 当引脚电平发生改变时,触发中断
   RISING 当引脚由低电平变为高电平时,触发中断
   FALLING 当引脚由高电平变为低电平时,触发中断
   */
  pinMode(PB_1, OUTPUT);
}
  • 初始化串口为9600波特率,用于打印按键状态。
  • 使用attachInterrupt函数初始化一个中断事件,编号可以由digitalPinToInterrupt函数获取,触发标志设置为CHANGE
  • 我们使用pinMode函数初始化PB1,并且设置为OUTPUT输出模式,用来闪灯。

最后我们可以在我们在loop()函数中添加剩下的代码,为了演示不影响按键响应,我们加一个闪灯的功能代码:

void loop() {
  digitalWrite(PB_1, HIGH);
  delay(500);
  digitalWrite(PB_1, LOW);
  delay(500);
}

当使用中断方式编写代码时,loop()函数中的延时将不会对按键状态变化时的相应造成影响。

优化后的结果

我们可以看到开发板上的 LED 灯正常闪烁,并且串口监视器中的按键事件打印也很及时。