M5StampS3でGROVE- Button(ボタンクラス)で遊ぶ。(M5Stack社さまのButtonClassを導入)


x 過去ログを見よ!!
x Arduino IDEの新規タブの意味のわかる人
x 非営利、研究開発目的でM5Stack社さまのプログラムを引用


結果

![o_coq565.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/d47d4c1d-bc7e-9f2d-0a74-126b7326d82e.jpeg)

![o_coq566.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/a1d716f6-3ea8-4632-7597-29b9c5884457.jpeg)


プログラム

```c++



//button_Grover_button_M5StampS3_1

/**
   @file button.ino
   @author SeanKwok (shaoxiang@m5stack.com)
   @brief
   @version 0.1
   @date 2024-03-19


   @Hardwares: M5NanoC6
   @Platform Version: Arduino ESP32 Board Manager v3.0.0-alpha3
   @Dependent Library:
   M5NanoC6: https://github.com/m5stack/M5NanoC6
*/

//#include <M5NanoC6.h>

#include <Arduino.h>
#include "Button_Class.hpp"

using namespace m5;

Button_Class BtnS;

void setup() {
  //NanoC6.begin();

  //シリアルの初期化処理
  Serial.begin(9600);

  Serial.println();
  Serial.println("START");
  Serial.println();

  pinMode(15, INPUT); //Grover GPIO1

  //GPIOの初期化 WS2812B
  pinMode(21, OUTPUT);

}

void loop() {

  //NanoC6.update();
  uint32_t ms = millis();
  BtnS.setRawState(ms, digitalRead(15)); //Grover GPIO15


  if (BtnS.wasPressed()) {
    Serial.println("Button A was pressed");
    neopixelWrite(21, 0, 64, 0);
  }

  if (BtnS.wasHold()) {
    Serial.println("Button A was hold");
    neopixelWrite(21, 0, 64, 0);
  }

  if (BtnS.wasReleased()) {
    Serial.println("Button A was released");
    neopixelWrite(21, 0, 0, 0);
  }
}


```

Button_Class.hpp

```c++

// Copyright (c) M5Stack. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full
// license information.

#ifndef __M5_BUTTON_CLASS_H__
#define __M5_BUTTON_CLASS_H__

#include <cstdint>

namespace m5 {
class Button_Class {
   public:
    enum button_state_t : std::uint8_t { state_nochange, state_clicked, state_hold, state_decide_click_count };

    /// Returns true when the button is pressed briefly and released.
    bool wasClicked(void) const {
        return _currentState == state_clicked;
    }

    /// Returns true when the button has been held pressed for a while.
    bool wasHold(void) const {
        return _currentState == state_hold;
    }

    /// Returns true when some time has passed since the button was single
    /// clicked.
    bool wasSingleClicked(void) const {
        return _currentState == state_decide_click_count && _clickCount == 1;
    }

    /// Returns true when some time has passed since the button was double
    /// clicked.
    bool wasDoubleClicked(void) const {
        return _currentState == state_decide_click_count && _clickCount == 2;
    }

    /// Returns true when some time has passed since the button was multiple
    /// clicked.
    bool wasDecideClickCount(void) const {
        return _currentState == state_decide_click_count;
    }

    [[deprecated("use wasDecideClickCount()")]] bool wasDeciedClickCount(void) const {
        return wasDecideClickCount();
    }

    std::uint8_t getClickCount(void) const {
        return _clickCount;
    }

    /// Returns true if the button is currently held pressed.
    bool isHolding(void) const {
        return _press == 2;
    }
    bool wasChangePressed(void) const {
        return ((bool)_press) != ((bool)_oldPress);
    }

    bool isPressed(void) const {
        return _press;
    }
    bool isReleased(void) const {
        return !_press;
    }
    bool wasPressed(void) const {
        return !_oldPress && _press;
    }
    bool wasReleased(void) const {
        return _oldPress && !_press;
    }
    bool wasReleasedAfterHold(void) const {
        return !_press && _oldPress == 2;
    }
    bool wasReleaseFor(std::uint32_t ms) const {
        return _oldPress && !_press && _lastHoldPeriod >= ms;
    }

    [[deprecated("use wasReleaseFor()")]] bool wasReleasefor(std::uint32_t ms) const {
        return wasReleaseFor(ms);
    }
    bool pressedFor(std::uint32_t ms) const {
        return (_press && _lastMsec - _lastChange >= ms);
    }
    bool releasedFor(std::uint32_t ms) const {
        return (!_press && _lastMsec - _lastChange >= ms);
    }

    void setDebounceThresh(std::uint32_t msec) {
        _msecDebounce = msec;
    }
    void setHoldThresh(std::uint32_t msec) {
        _msecHold = msec;
    }

    void setRawState(std::uint32_t msec, bool press);
    void setState(std::uint32_t msec, button_state_t state);
    button_state_t getState(void) const {
        return _currentState;
    }
    std::uint32_t lastChange(void) const {
        return _lastChange;
    }

    std::uint32_t getDebounceThresh(void) const {
        return _msecDebounce;
    }
    std::uint32_t getHoldThresh(void) const {
        return _msecHold;
    }

    std::uint32_t getUpdateMsec(void) const {
        return _lastMsec;
    }

   private:
    std::uint32_t _lastMsec       = 0;
    std::uint32_t _lastChange     = 0;
    std::uint32_t _lastRawChange  = 0;
    std::uint32_t _lastClicked    = 0;
    std::uint16_t _msecDebounce   = 10;
    std::uint16_t _msecHold       = 500;
    std::uint16_t _lastHoldPeriod = 0;
    button_state_t _currentState  = state_nochange;  // 0:nochange  1:click  2:hold
    bool _raw_press               = false;
    std::uint8_t _press           = 0;  // 0:release  1:click  2:holding
    std::uint8_t _oldPress        = 0;
    std::uint8_t _clickCount      = 0;
};

}  // namespace m5

#endif


```

Button_Class.cpp


```c++

// Copyright (c) M5Stack. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full
// license information.

#include "Button_Class.hpp"

namespace m5 {
void Button_Class::setState(std::uint32_t msec, button_state_t state) {
    if (_currentState == state_decide_click_count) {
        _clickCount = 0;
    }

    _lastMsec        = msec;
    bool flg_timeout = (msec - _lastClicked > _msecHold);
    switch (state) {
        case state_nochange:
            if (flg_timeout && !_press && _clickCount) {
                if (_oldPress == 0 && _currentState == state_nochange) {
                    state = state_decide_click_count;
                } else {
                    _clickCount = 0;
                }
            }
            break;

        case state_clicked:
            ++_clickCount;
            _lastClicked = msec;
            break;

        default:
            break;
    }
    _currentState = state;
}

void Button_Class::setRawState(std::uint32_t msec, bool press) {
    button_state_t state = button_state_t::state_nochange;
    bool disable_db      = (msec - _lastMsec) > _msecDebounce;
    auto oldPress        = _press;
    _oldPress            = oldPress;
    if (_raw_press != press) {
        _raw_press     = press;
        _lastRawChange = msec;
    }
    if (disable_db || msec - _lastRawChange >= _msecDebounce) {
        if (press != (0 != oldPress)) {
            _lastChange = msec;
        }

        if (press) {
            std::uint32_t holdPeriod = msec - _lastChange;
            _lastHoldPeriod          = holdPeriod;
            if (!oldPress) {
                _press = 1;
            } else if (oldPress == 1 && (holdPeriod >= _msecHold)) {
                _press = 2;
                state  = button_state_t::state_hold;
            }
        } else {
            _press = 0;
            if (oldPress == 1) {
                state = button_state_t::state_clicked;
            }
        }
    }
    setState(msec, state);
}
}  // namespace m5


```