How to use AceButton with Keyes Keyer-AD-Key (5 key ladder)

Hi,

For those that might need it, I wanted to show you how to use the " KEYES AD Keyboard", using 5 Volts at VCC which looks like this:


(I've annotated the buttons on top, for more clarity)

For starters, I had to measure the value received by analogRead() for each key, and since I bought two of them I was expecting slight differences between them, and indeed there were (see below); I measured the ADC readings in 10 bit, 12 bit and 14 bit resolutions.

Here are the two tables with ADC readings and corresponding voltages:

D1 = Device 1
D2 = Device 2

Column nomenclature is Device@ADCResolution

ADC Readings Table 5 Volts at VCC:

Switch D1@10b D1@12b D1@14b D2@10b D2@12b D2@14b
SW1 0 0 0 0 0 0
SW2 144 577 2310 146 588 2530
SW3 324 1300 5190 328 1315 5260
SW4 498 1990 7980 499 1995 7990
SW5 734 2940 11750 737 2950 11800
Nothing 1023 4095 16380 1023 4095 16380

Voltage Table 5 Volts at VCC:

Switch D1@10b Voltage (V) D1@12b Voltage (V) D1@14b Voltage (V) D2@10b Voltage (V) D2@12b Voltage (V) D2@14b Voltage (V)
SW1 0.000 0.000 0.000 0.000 0.000 0.000
SW2 0.704 0.705 0.705 0.714 0.718 0.772
SW3 1.584 1.587 1.584 1.603 1.606 1.605
SW4 2.434 2.430 2.435 2.439 2.436 2.439
SW5 3.587 3.590 3.586 3.602 3.602 3.601
Nothing 5.000 5.000 5.000 5.000 5.000 5.000

Here are each of the voltages charted per button, compared using the 3 resolutions, pretty much the values correlate as expected:


Why AceButton?

First time I saw it, was on the factory demo of Lily's T3S3 LoRa32, I liked it was responsive for single click, double clicks or even long clicks, handling all that for you...!

So, how to use it with AceButton?...

Here is the code for that:

#include <AceButton.h>
using namespace ace_button;

static const uint8_t BUTTON_PIN = A0;

// Create 5 AceButton objects, with specific names for each button.
static const uint8_t NUM_BUTTONS = 5;
static AceButton btnLeft(nullptr, 0);   // Left button (SW1)
static AceButton btnUp(nullptr, 1);     // Up button (SW2)
static AceButton btnDown(nullptr, 2);   // Down button (SW3)
static AceButton btnRight(nullptr, 3);  // Right button (SW4)
static AceButton btnSelect(nullptr, 4); // Select button (SW5)
static AceButton* const BUTTONS[NUM_BUTTONS] = {
    &btnLeft, &btnUp, &btnDown, &btnRight, &btnSelect
};

// Define specific ADC thresholds based on resolution (10-bit, 12-bit, or 14-bit)
static const uint16_t LEVELS_10BIT[] = { 0, 144, 324, 498, 734, 1023 };    // 10-bit resolution
static const uint16_t LEVELS_12BIT[] = { 0, 577, 1300, 1990, 2940, 4095 }; // 12-bit resolution
static const uint16_t LEVELS_14BIT[] = { 0, 2310, 5190, 7980, 11750, 16380 }; // 14-bit resolution

// Pointer to the button config object
LadderButtonConfig* buttonConfig = nullptr;

// Function to dynamically update levels based on resolution
void setLevelsBasedOnResolution(uint8_t resolution) {
  delete buttonConfig;  // Delete the previous buttonConfig instance if it exists

  switch (resolution) {
    case 10: // 10-bit resolution
      buttonConfig = new LadderButtonConfig(BUTTON_PIN, NUM_BUTTONS + 1, LEVELS_10BIT, NUM_BUTTONS, BUTTONS);
      Serial.println("Using 10-bit resolution ADC levels.");
      break;
    case 12: // 12-bit resolution
      buttonConfig = new LadderButtonConfig(BUTTON_PIN, NUM_BUTTONS + 1, LEVELS_12BIT, NUM_BUTTONS, BUTTONS);
      Serial.println("Using 12-bit resolution ADC levels.");
      break;
    case 14: // 14-bit resolution
      buttonConfig = new LadderButtonConfig(BUTTON_PIN, NUM_BUTTONS + 1, LEVELS_14BIT, NUM_BUTTONS, BUTTONS);
      Serial.println("Using 14-bit resolution ADC levels.");
      break;
    default: // Fallback to 10-bit if unknown
      buttonConfig = new LadderButtonConfig(BUTTON_PIN, NUM_BUTTONS + 1, LEVELS_10BIT, NUM_BUTTONS, BUTTONS);
      Serial.println("Unknown resolution, using 10-bit by default.");
      break;
  }

  // Reassign the event handler and enable features after reinitializing buttonConfig
  buttonConfig->setEventHandler(handleEvent);
  buttonConfig->setFeature(ButtonConfig::kFeatureClick);
  buttonConfig->setFeature(ButtonConfig::kFeatureDoubleClick);
  buttonConfig->setFeature(ButtonConfig::kFeatureLongPress);
  buttonConfig->setFeature(ButtonConfig::kFeatureRepeatPress);
}

// Event handler for each button press.
void handleEvent(AceButton* button, uint8_t eventType, uint8_t buttonState) {
  Serial.print(F("Button: "));

  // Identify which button was pressed
  switch (button->getPin()) {
    case 0:
      Serial.print("Left");
      break;
    case 1:
      Serial.print("Up");
      break;
    case 2:
      Serial.print("Down");
      break;
    case 3:
      Serial.print("Right");
      break;
    case 4:
      Serial.print("Select");
      break;
    default:
      Serial.print("Unknown");
      break;
  }

  Serial.print(F(" - Event Type: "));

  // Handle each event type
  switch (eventType) {
    case AceButton::kEventPressed:
      Serial.println("Pressed");
      break;
    case AceButton::kEventReleased:
      Serial.println("Released");
      break;
    case AceButton::kEventClicked:
      Serial.println("Click");
      break;
    case AceButton::kEventDoubleClicked:
      Serial.println("Double Click");
      break;
    case AceButton::kEventLongPressed:
      Serial.println("Long Press");
      break;
    case AceButton::kEventRepeatPressed:
      Serial.println("Repeat Press");
      break;
    default:
      Serial.println("Unknown Event");
      break;
  }
}

void setup() {
  delay(1000);
  Serial.begin(115200);
  while (!Serial);

  pinMode(BUTTON_PIN, INPUT);

  // Set ADC levels based on device resolution (example: 10-bit resolution)
  setLevelsBasedOnResolution(10); // Adjust the parameter (10, 12, 14) based on your current resolution
}

// Call checkButtons every 5ms or faster for debounce.
void checkButtons() {
  static unsigned long prev = millis();
  unsigned long now = millis();
  if (now - prev > 5) {
    buttonConfig->checkButtons();
    prev = now;
  }
}

void loop() {
  checkButtons();
}

Example output:

15:15:54.569 -> Button: Up - Event Type: Pressed
15:15:54.661 -> Button: Up - Event Type: Click
15:15:54.661 -> Button: Up - Event Type: Released
15:15:55.748 -> Button: Up - Event Type: Pressed
15:15:55.840 -> Button: Up - Event Type: Click
15:15:55.840 -> Button: Up - Event Type: Released
15:15:55.933 -> Button: Up - Event Type: Pressed
15:15:56.025 -> Button: Up - Event Type: Double Click
15:15:56.025 -> Button: Up - Event Type: Released
15:15:56.953 -> Button: Up - Event Type: Pressed
15:15:57.958 -> Button: Up - Event Type: Long Press
15:15:57.958 -> Button: Up - Event Type: Repeat Press
15:15:58.130 -> Button: Up - Event Type: Repeat Press
15:15:58.361 -> Button: Up - Event Type: Repeat Press
15:15:58.538 -> Button: Up - Event Type: Repeat Press
15:15:58.765 -> Button: Up - Event Type: Repeat Press

I hope this helps you on whatever project you have and with the ADC resolution you might have on your board.

Perhaps you ordered this board and are waiting for it to do something similar?. if so, I hope the values I've measured help you out to continue your development while waiting.

Hello coloboxp,

You posted in the 'uncategorised' section.

There is a post 'about the uncategorized category' telling you not to post there.

I have moved your post to the 'Introductory Tutorials' section as that seemed most appropriate for your topic.

EDIT,
It has been pointed out to me that I should not have moved it to the 'Introductory Tutorials' section, and that 'Programming Questions' might be more appropriate.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.