acid-drop/lib/AceButton/examples/TunerButtons/TunerButtons.ino
2024-05-23 18:42:03 -04:00

192 lines
5.1 KiB
C++

/*
* Emulate the buttons of a car radio:
*
* - 3 preset buttons
* - 1 tune-up button
* - 1 tune-down button
*
* LongPress of a preset button stores the station.
* LongPress of a tune-up or tune-down button scans the radio frequency.
*/
#include <AceButton.h>
using namespace ace_button;
const int NUM_PRESETS = 3;
const int PRESET_1_PIN = 6;
const int PRESET_2_PIN = 5;
const int PRESET_3_PIN = 4;
const int TUNE_DOWN_PIN = 3;
const int TUNE_UP_PIN = 2;
// Frequency range of the FM radio.
const uint16_t FM_FREQ_MIN = 879; // 87.9 MHz
const uint16_t FM_FREQ_MAX = 1079; // 107.9 MHz
const uint16_t FM_FREQ_DELTA = 2; // 0.2 MHz increments in USA
// Preset buttons use the SystemButtonConfig.
AceButton presetButton1;
AceButton presetButton2;
AceButton presetButton3;
// Tune up or down buttons use a different ButtonConfig.
ButtonConfig tuneConfig;
AceButton tuneDownButton(&tuneConfig);
AceButton tuneUpButton(&tuneConfig);
// Array to hold the stations associated with the button whose id is an
// index into this array. The value is the 10 * station_frequency (e.g. 88.5 MHz
// is stored as 885).
//
// NOTE: It might be tempting to subclass the AceButton to hold this information
// but it's cleaner to keep this info separated from the AceButton class
// hierarchy.
uint16_t stations[NUM_PRESETS];
// The current station frequency.
uint16_t currentStation = FM_FREQ_MIN;
void handlePresetEvent(AceButton*, uint8_t, uint8_t);
void handleTuneEvent(AceButton*, uint8_t, uint8_t);
void setup() {
delay(1000); // some boards reboot twice
Serial.begin(115200);
while (! Serial); // Wait until Serial is ready - Leonardo/Micro
Serial.println(F("setup(): begin()"));
// Configs for the preset buttons. Need Released event to change the station,
// and LongPressed to memorize the current station. Don't need Clicked.
ButtonConfig* presetConfig = ButtonConfig::getSystemButtonConfig();
presetConfig->setEventHandler(handlePresetEvent);
presetConfig->setFeature(ButtonConfig::kFeatureLongPress);
presetConfig->setFeature(ButtonConfig::kFeatureSuppressAfterLongPress);
// Configs for the tune-up and tune-down buttons. Need RepeatPress instead of
// LongPress.
tuneConfig.setEventHandler(handleTuneEvent);
tuneConfig.setFeature(ButtonConfig::kFeatureClick);
tuneConfig.setFeature(ButtonConfig::kFeatureRepeatPress);
// These suppressions not really necessary but cleaner.
tuneConfig.setFeature(ButtonConfig::kFeatureSuppressAfterClick);
tuneConfig.setFeature(ButtonConfig::kFeatureSuppressAfterRepeatPress);
// Preset Button 1
pinMode(PRESET_1_PIN, INPUT_PULLUP);
presetButton1.init(PRESET_1_PIN, HIGH, 0 /* id */);
// Preset Button 2
pinMode(PRESET_2_PIN, INPUT_PULLUP);
presetButton2.init(PRESET_2_PIN, HIGH, 1 /* id */);
// Preset Button 3
pinMode(PRESET_3_PIN, INPUT_PULLUP);
presetButton3.init(PRESET_3_PIN, HIGH, 2 /* id */);
// Tune Down Button
pinMode(TUNE_DOWN_PIN, INPUT_PULLUP);
tuneDownButton.init(TUNE_DOWN_PIN);
// Tune Up Button
pinMode(TUNE_UP_PIN, INPUT_PULLUP);
tuneUpButton.init(TUNE_UP_PIN);
// init the stations associated with each button
initStations();
Serial.println(F("setup(): tuner buttons ready"));
printStation(currentStation);
}
void loop() {
presetButton1.check();
presetButton2.check();
presetButton3.check();
tuneUpButton.check();
tuneDownButton.check();
}
void initStations() {
for (int i = 0; i < NUM_PRESETS; i++) {
stations[i] = FM_FREQ_MIN;
}
}
void printStation(uint16_t frequency) {
Serial.print(F("station: "));
Serial.print(frequency / 10);
Serial.print('.');
Serial.println(frequency % 10);
}
void handlePresetEvent(AceButton* button, uint8_t eventType,
uint8_t /* buttonState */) {
switch (eventType) {
case AceButton::kEventReleased:
// We trigger on the Released event not the Pressed event to distinguish
// this event from the LongPressed event.
retrievePreset(button->getId());
break;
case AceButton::kEventLongPressed:
setPreset(button->getId());
break;
}
}
void handleTuneEvent(AceButton* button, uint8_t eventType,
uint8_t /* buttonState */) {
switch (eventType) {
case AceButton::kEventPressed:
case AceButton::kEventRepeatPressed: {
uint8_t pin = button->getPin();
switch (pin) {
case TUNE_UP_PIN:
tuneUp();
break;
case TUNE_DOWN_PIN:
tuneDown();
break;
}
}
}
}
void retrievePreset(uint8_t id) {
if (id < NUM_PRESETS) {
currentStation = stations[id];
Serial.print(F("memory "));
Serial.print(id + 1);
Serial.print(F(": "));
printStation(currentStation);
}
}
void setPreset(uint8_t id) {
if (id < NUM_PRESETS) {
stations[id] = currentStation;
Serial.print(F("memory "));
Serial.print(id + 1);
Serial.print(F(" set: "));
printStation(currentStation);
}
}
void tuneUp() {
currentStation += FM_FREQ_DELTA;
if (currentStation > FM_FREQ_MAX) {
currentStation = FM_FREQ_MIN;
}
printStation(currentStation);
}
void tuneDown() {
currentStation -= FM_FREQ_DELTA;
if (currentStation < FM_FREQ_MIN) {
currentStation = FM_FREQ_MAX;
}
printStation(currentStation);
}