|
爱科技、爱创意、爱折腾、爱极致,我们都是技术控
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 jjbboox 于 2020-2-19 13:27 编辑
gpio_button.h文件修改了一下,原来的版本定义多个按钮的时候事件响应会混乱
处理按键其实很简单,Arduino可以用C++,所以我们可以定义一个类来处理按键。
关键就是我们把按键定义在哪个GPIO口,以及按键按下后需要进行哪些处理。
简单的类定义不需要cpp,直接一个.h文件就可以了。
将该文件放在.ino同一个目录中就可以了。
gpio_button.h- #ifndef _GPIO_BUTTON_H_
- #define _GPIO_BUTTON_H_
- #include <Arduino.h>
- #define DEF_ELIMINATING_JITTER_MS 20 // 默认消抖延时
- #define DEF_LONG_PRESS_WAIT_MS 1000 // 默认长按延时
- class GpioButton {
- public:
- // 构造函数,定义端口号,回调函数,初始化默认值
- GpioButton(uint8_t gpio_pin, void(*btn_press_event)()=nullptr) :
- GpioPin(gpio_pin),
- ButtonPressEvent(btn_press_event),
- LongPressWaitMS(DEF_LONG_PRESS_WAIT_MS),
- ButtonLongPressEvent(nullptr),
- key_down_millis(0),
- action_done(false) {
- pinMode(GpioPin, INPUT_PULLUP);
- digitalWrite(GpioPin, HIGH);
- };
- // 绑定按键回调函数
- void BindBtnPress(void(*btn_press_event)()) {ButtonPressEvent = btn_press_event;};
- // 绑定长按事件回调函数和长按的判定时长
- bool BindBtnLongPress(void(*btn_long_press_event)(), uint16_t wait_ms=DEF_LONG_PRESS_WAIT_MS) {
- if(wait_ms < DEF_LONG_PRESS_WAIT_MS) return false;
- ButtonLongPressEvent = btn_long_press_event;
- LongPressWaitMS = wait_ms;
- return true;
- };
- // 轮询函数
- void loop(){
- // 读取端口状态
- uint8_t pin_val = digitalRead(GpioPin);
- // 获取当前系统时间
- uint32_t now_millis = millis();
- // 计算按下时点到当前经过的毫秒数
- uint32_t pass_millis = now_millis - key_down_millis;
- // 记录按键按下时点的系统时间,清楚动作执行标志
- if(pin_val == LOW && key_down_millis == 0) {
- key_down_millis = now_millis;
- action_done = false;
- }
- // 按键按下状态如果超过长按判定时长时,调用长按事件回调(如果已绑定长按事件回调)
- else if(pin_val == LOW && ButtonLongPressEvent != nullptr && pass_millis > LongPressWaitMS && !action_done) {
- // 防止重复调用,设置执行标志
- action_done = true;
- // 调用回调方法
- ButtonLongPressEvent();
- }
- // 按键释放状态
- else if(pin_val == HIGH) {
- // 如果是按键释放瞬间,按下时长超过消抖间隔时长,且尚未执行过回调函数
- if(!action_done && key_down_millis > 0 && pass_millis > DEF_ELIMINATING_JITTER_MS && ButtonPressEvent != nullptr) {
- // 设置执行标志
- action_done = true;
- // 调用回调方法
- ButtonPressEvent();
- }
- // 清空按下时点的值
- key_down_millis = 0;
- }
- };
- protected:
- uint8_t GpioPin;
- void (*ButtonPressEvent)();
- uint16_t LongPressWaitMS;
- void (*ButtonLongPressEvent)();
- uint32_t key_down_millis;
- bool action_done;
- };
- #endif
复制代码
使用方法(例)
GPIOButtonTest.ino
- #include <Arduino.h>
- #include <gpio_button.h>
- #define MY_BUTTON_PIN 8
- // 定义按钮对象,指定按钮的GPIO口
- GpioButton myButton(MY_BUTTON_PIN);
- void setup() {
- Serial.begin(9600);
- Serial.println("Start.");
-
- // 初始化板载LED信号灯
- pinMode(LED_BUILTIN, OUTPUT);
-
- // 绑定按钮事件处理
- myButton.BindBtnPress([](){
- Serial.println("Led Button Press Event\r\n\tSetup Bind Event.");
- digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
- });
- // 绑定长按事件处理(长按判定为1500ms)
- myButton.BindBtnLongPress([](){
- Serial.println("Led Button Long Press Event\r\n\tSetup Bind Event.");
- digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
- }, 1500);
- }
- void loop() {
- // 调用按键轮询处理
- myButton.loop();
- }
复制代码 同样可以先在代码中写好事件处理函数(void onButtonClick()),在setup中用myButton.BindBtnPress(onButtonClick)的形式绑定回调函数。
绑定长按事件的时候可以指定时间,上例中持续按下1.5s后执行长按事件。
不绑定任何回调事件的时候按键不会执行任何处理,也不会导致系统崩溃。
有兴趣的兄弟可以完善一下,让这个类能够实现双击功能。
已做消抖处理,使用的时候无需考虑硬件消抖,按键一只脚接地,另一只脚直接接GPIO口。
对象初始化时会自动将该端口设定为内部上拉方式。
|
打赏
-
查看全部打赏
|