#include <Adafruit_NeoPixel.h>
#define BUTTON_PIN 1 // button pin (other leg -> GND)
#define LED_PIN 2 // NeoPixel data pin
#define NUMPIXELS 2 // two LEDs chained
Adafruit_NeoPixel pixels(NUMPIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);
// Morse timing
#define WPM 10
const unsigned long UNIT_MS = 1200UL / WPM;
const unsigned long DOT_DASH_THRESH_MS = (unsigned long)(2.5 * UNIT_MS);
const unsigned long LETTER_GAP_MS = (unsigned long)(3.5 * UNIT_MS);
const unsigned long WORD_GAP_MS = (unsigned long)(7.0 * UNIT_MS);
const unsigned long DEBOUNCE_MS = 25;
bool lastLevel = HIGH;
unsigned long lastEdgeMs = 0;
unsigned long pressStartMs = 0;
unsigned long lastReleaseMs = 0;
String currentMorse;
struct MorseEntry { const char* code; char ch; };
const MorseEntry table[] PROGMEM = {
{".-", 'A'}, {"-...", 'B'}, {"-.-.", 'C'}, {"-..", 'D'}, {".", 'E'},
{"..-.", 'F'}, {"--.", 'G'}, {"....", 'H'}, {"..", 'I'}, {".---", 'J'},
{"-.-", 'K'}, {".-..", 'L'}, {"--", 'M'}, {"-.", 'N'}, {"---", 'O'},
{".--.", 'P'}, {"--.-", 'Q'}, {".-.", 'R'}, {"...", 'S'}, {"-", 'T'},
{"..-", 'U'}, {"...-", 'V'}, {".--", 'W'}, {"-..-", 'X'}, {"-.--", 'Y'},
{"--..", 'Z'},
{"-----",'0'}, {".----",'1'}, {"..---",'2'}, {"...--",'3'}, {"....-",'4'},
{".....",'5'}, {"-....",'6'}, {"--...",'7'}, {"---..",'8'}, {"----.",'9'},
};
char decode(const String& code) {
for (auto &e : table) if (code == e.code) return e.ch;
return '?';
}
void flashDot() {
pixels.clear();
pixels.setPixelColor(0, pixels.Color(0, 0, 255)); // blue for dot
pixels.show();
delay(UNIT_MS);
pixels.clear(); pixels.show();
}
void flashDash() {
pixels.clear();
pixels.setPixelColor(0, pixels.Color(255, 0, 0)); // both red
pixels.setPixelColor(1, pixels.Color(255, 0, 0));
pixels.show();
delay(3 * UNIT_MS);
pixels.clear(); pixels.show();
}
void endLetter() {
if (currentMorse.isEmpty()) return;
Serial.print(decode(currentMorse));
currentMorse = "";
}
void setup() {
Serial.begin(115200);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pixels.begin();
pixels.clear(); pixels.show();
Serial.println("Morse ready: short=dot, long=dash, LED feedback enabled");
}
void loop() {
unsigned long now = millis();
int level = digitalRead(BUTTON_PIN);
if (level != lastLevel && (now - lastEdgeMs) > DEBOUNCE_MS) {
lastEdgeMs = now;
if (level == LOW) {
pressStartMs = now;
} else {
unsigned long dur = now - pressStartMs;
lastReleaseMs = now;
if (dur < DOT_DASH_THRESH_MS) {
Serial.print('.');
currentMorse += '.';
flashDot();
} else {
Serial.print('-');
currentMorse += '-';
flashDash();
}
}
lastLevel = level;
}
if (lastLevel == HIGH && lastReleaseMs != 0) {
unsigned long idle = now - lastReleaseMs;
if (idle >= LETTER_GAP_MS && currentMorse.length() > 0) {
endLetter();
lastReleaseMs = now;
}
if (idle >= WORD_GAP_MS) {
Serial.print(' ');
lastReleaseMs = now;
}
}
}
Loading
xiao-esp32-s3
xiao-esp32-s3