TA3ZGR CW Keyer is an ESP32-based amateur-radio Morse keyer, hand-soldered on perfboard. It began as a simple iambic keyer and grew into a full-featured Morse trainer that needs no computer once flashed. Every setting, message memory, training progress and lifetime statistic is stored on the device and survives power-off.
Highlights
- Iambic keyer — modes A and B, adjustable weight, paddle L/R swap.
- Self-decoder — decodes what you send on the OLED, with prosign labels (
<SK> <AR> <BT> <AS> <KN>). - Radio-like sidetone — two audio engines on one pin: PWM buzzer, and a DAC sine wave with a raised-cosine envelope for a soft, click-free tone through a PAM8403 amp. Adjustable tone, volume and rise/fall.
- Rotary-encoder menu — 5 categories, long-press to go back; interrupt-driven so no detents are missed.
- Message memories — 4 slots + quick-CQ + a beacon (never overlaps).
- On-device text editor — edit messages without a computer.
- Koch / Farnsworth trainer — 9 modes, separate character speed, correct ARRL Farnsworth timing, adaptive weighting, a rolling-window level-up rule, lifetime accuracy stats.
- WiFi + web panel + OTA — all settings in a browser, plus wireless firmware updates.
- Radio key output — open-collector NPN; drives a rig's straight-key jack (QMX, Icom, etc.).
Training modes
Echo · Listen · Call · Word-recognition · Learn (crib) · Head-copy · QSO · Traffic (operating tokens) · Word (crib-based vocabulary). Level advancement is Koch-style: ≥90% over the last 20 attempts. Character speed is kept independent of effective speed, and the "highest level" record only rises in the crib-free Echo mode.
Hardware
| GPIO | Function | Connection / note |
|---|---|---|
| 32 | dit — paddle (left) | INPUT_PULLUP, active LOW · common → GND |
| 33 | dah — paddle (right) | INPUT_PULLUP, active LOW · common → GND |
| 34 | Pot — WPM | wiper · input-only pin |
| 25 | Sidetone (DAC1) | audio chain → PAM8403 |
| 27 | Key-out (radio) | 2.2k → NPN base → TRS jack |
| 26 / 14 / 13 | Encoder CLK / DT / SW | INPUT_PULLUP |
| 21 / 22 | OLED SDA / SCL | SSD1306 128×64, I²C 0x3C |
Audio chain — DAC → amplifier
ESP32 PAM8403 4-ohm SPEAKER
GPIO25 --[1k]--+----------[1uF]--> IN L VCC --- +5V L+ --+
(DAC1) | GND --- GND L- --+
+-[22nF]-+
| | Speaker BETWEEN L+/L- (BTL, never to GND)
[1k tune] GND Add 1000uF + 100nF across VCC-GND (recommended)
|
GND
Radio key output — open collector
GPIO27 --[2.2k]--+--- B --+
| +- C -----------> TIP = rig key (+)
[10k] +- E -----------> SLEEVE = GND
| RING = unused
GND Set the radio to STRAIGHT-KEY mode
Open source
All firmware, the schematic and 3D case files are on GitHub under the MIT license: github.com/innteger/ta3zgr-cw-keyer. Built with PlatformIO; the ESP32 Arduino core is intentionally pinned to 2.0.17. Use it, learn from it, build your own — 73!