/* * SibKeyer.ino * The Simpler Is Better Morse Code Keyer * (But not so simple that it doesn't do everything your want it to do.) * This is the bare-bones minimalistic version, see SibKeyerQSK.ino for * the full QSK version with extra blinky lights. * Note that there are some residual parts of the * QSK version source code here and in the schematic. * * Author: G. Forrest Cook, W0RIO * License: GPL Version 3. * * This is a minimalistic keyer design with only a few features including: * - Dot and Dash paddle inputs * - A manual key input which doubles as a TX tune control. * - Buffered inputs via a 74LS14 to keep static zaps away from the * microprocessor and invert the logic for pull-down key inputs * - dot and dash memories for (mode B) iambic keying * - Positive and inverted TX outputs * - A Keyer Active output which can be used for T/R switching, * muting a receiver and activating a VFO * - An Analog speed control for smooth speed adjustment * * This has been developed on an Arduino Nano but should work with * other Atmega328P based Arduinos such as the Uno, it will also work * with a standalone Atmega328P IC. * * Project Started: Dec 17, 2024 * Version: see the Serial.println statement below * * The keyer is clocked by an interrupt signal on digital pin 2 (IRQ 0) * which is generated by an NMOS or CMOS 555 timer chip. * This produces a wide-range analog-adjustable speed control. * The first clock pulse from the 555 takes longer than the rest, * by counting multiple clock pulses for dot, dash and space timing, the * first pulse timing error is minimized. */ // Define the I/O pins const int ClockIrq = 2; // 555 timer output (interrupt 0) const int Int1 = 3; // Unused interrupt const int DotKey = 4; // Dot paddle (buffered) const int DashKey = 5; // Dash paddle (buffered) const int TuneKey = 6; // Tune switch const int Active = 7; // 555 timer control and keyer active signal const int TxOut = 8; // Transmit output const int RxOut = 9; // Receive output for QSK (unused) const int DashOut = 10; // dash output for two-tone CW (unused) const int DotOut = 11; // dot output for two-tone CW (unused) const int Dout12 = 12; const int NanoLED = 13; // Red LED on Nano const int Dotcount = 10; // clock pulses for dot on time const int Spacecount = 10; // clock pulses for space time const int Dashcount = 30; // clock pulses for dash on time const int ClockTout = 500; // clock pulses before shutting clock down const long ActiveTout = 500; // stop the 555 clock after idle time (mSec) unsigned long Mstime; // running milliseconds counter volatile byte Tcount = 0; // interrupt routine element time counter byte dotmem = 0; // dot paddle pressed memory byte dashmem = 0; // dash paddle pressed menory void setup() { pinMode (ClockIrq, INPUT); pinMode (Int1, OUTPUT); // unused irq pin pinMode (Active, OUTPUT); pinMode (DotKey, INPUT); pinMode (DashKey, INPUT); pinMode (TuneKey, INPUT); pinMode (TxOut, OUTPUT); pinMode (RxOut, OUTPUT); pinMode (DashOut, OUTPUT); pinMode (DotOut, OUTPUT); pinMode (Dout12, OUTPUT); pinMode (NanoLED, OUTPUT); // Set initial output values digitalWrite(Active, LOW); digitalWrite(TxOut, LOW); digitalWrite(RxOut, HIGH); digitalWrite(DashOut, LOW); digitalWrite(DotOut, LOW); Serial.begin (19200); // Initialize serial port, set the baud rate attachInterrupt(0, timerint, RISING); // Int 0 causes dacstep to run. Serial.println (F("W0RIO SIB Keyer Minimal Version, rev: 17 Dec, 2024")); Mstime = millis(); // mark the real time } void loop() { if (dotmem) { dotmem=0; sendDot(); } else if (digitalRead (DotKey)) sendDot(); if (dashmem) { dashmem=0; sendDash(); } else if (digitalRead (DashKey)) sendDash(); if (digitalRead (TuneKey)) { digitalWrite(Active, HIGH); // start the 555 timer and active sig digitalWrite(TxOut, HIGH); while (digitalRead (TuneKey)); // loop while tune mode is pressed digitalWrite(TxOut, LOW); Mstime = millis(); // mark the real time } // Stop the 555 timer after the timeout period. if (millis() >= Mstime + ActiveTout) digitalWrite(Active, LOW); } void sendDot() { digitalWrite(Active, HIGH); // start the 555 timer and active sig Tcount=Dotcount; digitalWrite(TxOut, HIGH); while (Tcount) // check for dash paddle if (digitalRead (DashKey)) dashmem=1; Tcount=Spacecount; digitalWrite(TxOut, LOW); while (Tcount) // check for dash paddle if (digitalRead (DashKey)) dashmem=1; Mstime = millis(); // mark the real time } void sendDash() { digitalWrite(Active, HIGH); // start the 555 timer and active sig Tcount=Dashcount; digitalWrite(TxOut, HIGH); while (Tcount) // check for dot paddle if (digitalRead (DotKey)) dotmem=1; Tcount=Spacecount; digitalWrite(TxOut, LOW); while (Tcount) // check for dot paddle if (digitalRead (DotKey)) dotmem=1; Mstime = millis(); // mark the real time } void timerint() { if (Tcount) Tcount--; // count element counter down to 0 }