背景
Adafruit Feather ESP32-S3 TFT 开发板板载两个按键:
- Reset 按键:按下就会导致开发板复位,无需检测;
- Boot 按键:连接到 GPIO0,程序可以检测到。
从下面的原理图得知,BOOT 按键没有按下时是高电平,按下时为低电平。
基础按键检测
按键对应的管脚配置为 INPUT_PULLUP;
按键检测通过读取管脚电平,如果是 LOW 表示按键按下,如果是 HIGH 表示按键释放;
高级按键检测
引用 Bounce2 按键检测库,可以实现消抖检测按键,并设置消抖时间。
一般的使用流程如下:
1. 初始化全局变量 Bounce boot_btn = Bounce() 创建一个按键对象;
2. 调用 boot_btn.attach(pin, mode) 绑定按键对应的管脚并设置管脚上下拉模式;
3. 调用 boot_btn.interval(ms) 设置消抖时间;
4. 在 loop() 中周期性调用 boot_btn.update() 更新按键状态;
5. 在需要读取按键状态的代码位置调用 boot_btn.chagned() 判断状态是否发生改变,调用 boot_btn.read() 读取按键状态,按下还是释放;
我的按键检测示例
检测 BOOT 按键状态,只有当按键释放时切换 LED 状态,即每释放一次按键点亮/熄灭一次 LED。
演示视频:
【电子测光笔DIY--板载BOOT按键检测】 https://www.bilibili.com/video/BV1g7DZYLEpK/?share_source=copy_web&vd_source=a96f26eed24136ca40c5afd28478f4f8
源码如下:
// SPDX-FileCopyrightText: 2022 Limor Fried for Adafruit Industries // // SPDX-License-Identifier: MIT /* Includes * --------------------------------------------------------------------------------------*/ #include <Arduino.h> #include "Adafruit_LC709203F.h" /* 电池管理 -- 未检测到 */ #include "Adafruit_MAX1704X.h" /* 电池管理 -- 当前板载的 */ #include <Adafruit_NeoPixel.h> #include <Adafruit_ST7789.h> #include <Fonts/FreeSans12pt7b.h> #include <Bounce2.h> /* 按键检测 */ /* Constants -------------------------------------------------------------------------------------*/ #define LCD_WIDTH 240 /* 显示屏宽度 240 像素 */ #define LCD_HEIGHT 135 /* 显示屏高度 135 像素 */ /** * @brief boot 按键的管脚 */ #define BOOT_BTN_PIN 0 /** * @brief 内置的 LED 管脚 */ #define LED_PIN LED_BUILTIN /* Variables * -------------------------------------------------------------------------------------*/ /* 电池管理器,硬件对象 */ Adafruit_LC709203F lc_bat; bool lc_bat_found = false; /* 电池管理器,硬件对象 */ Adafruit_MAX17048 max_bat; bool max_bat_found = false; /* 显示屏,硬件对象 */ Adafruit_ST7789 display = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST); /* 软件对象,画布:现在画布绘画,最后必须刷新到显示屏对象上 */ GFXcanvas16 canvas(LCD_WIDTH, LCD_HEIGHT); /* 这里仅分配一块连续的内存地址 */ /** * @brief 定义 Boot 按键对象 */ Bounce boot_btn = Bounce(); uint8_t led_status = 0; /* LED 状态:点亮还是熄灭 */ uint8_t loop_cnt = 0; /* Function Declarations * -----------------------------------------------------------------------------------------------*/ /** * @brief 按键硬件初始化、对象初始化 */ void btn_init(void) { pinMode(BOOT_BTN_PIN, INPUT_PULLUP); /* 按键硬件初始化,输入上拉模式 */ boot_btn.attach(BOOT_BTN_PIN); /* 按键对象绑定到硬件 */ boot_btn.interval(10); /* 设置按键消抖时间 */ } void led_init(void) { pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, led_status); pinMode(NEOPIXEL_POWER, OUTPUT); digitalWrite(NEOPIXEL_POWER, HIGH); } /** * @brief 显示屏初始化,整屏刷新为黑色 * * @param */ void screen_init(void) { /* turn on the TFT / I2C power supply */ pinMode(TFT_I2C_POWER, OUTPUT); /* 这个管脚是必须拉高的 */ digitalWrite(TFT_I2C_POWER, HIGH); /* 因为这里旋转了屏幕的方向,所以初始化的屏幕尺寸和实际使用的尺寸颠倒了 */ display.init(LCD_HEIGHT, LCD_WIDTH); // Init ST7789 240x135 display.setRotation(3); canvas.setFont(&FreeSans12pt7b); canvas.setTextColor(ST77XX_WHITE); canvas.fillScreen(ST77XX_BLACK); canvas.setCursor(0, 25); canvas.setTextColor(ST77XX_RED); canvas.println("Adafruit Feather"); canvas.setTextColor(ST77XX_YELLOW); canvas.println("ESP32-S3 TFT Demo"); /* 最后必须调用 display.drawRGBBitmap() 方法来刷新屏幕 */ display.drawRGBBitmap(0, 0, canvas.getBuffer(), LCD_WIDTH, LCD_HEIGHT); pinMode(TFT_BACKLITE, OUTPUT); digitalWrite(TFT_BACKLITE, HIGH); } void battery_monitor_init(void) { /* 初始化电池检测 */ if (lc_bat.begin()) { /* LC709X not found */ Serial.println("Found LC709203F"); Serial.print("Version: 0x"); Serial.println(lc_bat.getICversion(), HEX); lc_bat.setPackSize(LC709203F_APA_500MAH); lc_bat_found = true; } else { Serial.println(F( "Couldnt find Adafruit LC709203F?\nChecking for Adafruit MAX1704X..")); delay(200); if (!max_bat.begin()) { Serial.println(F("Couldnt find Adafruit MAX1704X?\nMake sure a battery " "is plugged in!")); while (1) delay(10); } Serial.print(F("Found MAX17048")); Serial.print(F(" with Chip ID: 0x")); Serial.println(max_bat.getChipID(), HEX); max_bat_found = true; } canvas.setTextColor(ST77XX_GREEN); canvas.print("Battery: "); canvas.setTextColor(ST77XX_WHITE); if (lc_bat_found == true) { canvas.print(lc_bat.cellVoltage(), 1); canvas.print(" V / "); canvas.print(lc_bat.cellPercent(), 0); canvas.println("%"); } else { canvas.print(max_bat.cellVoltage(), 1); canvas.print(" V / "); canvas.print(max_bat.cellPercent(), 0); canvas.println("%"); } canvas.setTextColor(ST77XX_BLUE); canvas.print("Battery: "); canvas.setTextColor(ST77XX_WHITE); if (lc_bat_found) { canvas.println("LC709X"); } else if (max_bat_found) { canvas.println("MAX170X"); } else { canvas.println("unknown"); } /* 最后必须调用 display.drawRGBBitmap() 方法来刷新屏幕 */ display.drawRGBBitmap(0, 0, canvas.getBuffer(), LCD_WIDTH, LCD_HEIGHT); } /** * @brief 在新的界面上显示按键是否按下 * * @param isPressed */ void screen_button_status(bool isPressed) { canvas.fillScreen(ST77XX_BLACK); canvas.setCursor(0, 25); canvas.setTextColor(ST77XX_BLUE); canvas.print("Button: "); canvas.setTextColor(ST77XX_YELLOW); if(isPressed) { canvas.println("Pressed"); } else { canvas.println("Released"); } display.drawRGBBitmap(0, 0, canvas.getBuffer(), LCD_WIDTH, LCD_HEIGHT); } /** * @brief 在主循环中调用此函数 * * @param */ void btn_process(void) { /* 在此更新所有的按键状态 */ boot_btn.update(); if (boot_btn.changed()) { /* 按键状态变化了 */ if (boot_btn.read()) { /* 高电平表示按键释放 */ led_status = !led_status; screen_button_status(false); } else { /* 低电平表示按键按下 */ screen_button_status(true); } } digitalWrite(LED_PIN, led_status); } /* Function Implementations * ----------------------------------------------------------------------*/ void setup() { Serial.begin(115200); uint32_t wait_cnt = 5; while (!Serial && (wait_cnt-- > 0)) { /* 等待串口软件连接 */ delay(1000); } // delay(3000); Serial.println("Adafruit Feather ESP32-S3 TFT"); Serial.println("Build: " + String(__DATE__) + " " + String(__TIME__)); screen_init(); btn_init(); led_init(); battery_monitor_init(); delay(10); } void loop() { btn_process(); loop_cnt++; delay(10); }