Minor tweaks to Arduino Morse Sketch…

Commenter Andy wanted a version of my classic code that could generate a tone instead of just blinking an LED. I mentioned that I had done this before, but frankly couldn’t find the source code, so I modified my existing program to implement the simplest possible tone: a simple square wave.

Rather than using a speaker, I wired up a little piezo element which I had soldered a couple of leads onto my junk pile. These disks are terrible at reproducing low frequencies and have strong resonances, but for this purpose, it was convenient. You can substitute a speaker if you like. It’s probably a good idea to use a little drive transistor with an 8 ohm speaker to provide more drive: you can see the basic idea here. It is nominally targeted toward mbed microcontrollers, but nothing about it is specific to those. Anyway, I hooked the positive lead of the element up to pin 9, and the negative lead to ground.

IMG_5699

I also hooked up my oscilloscope so I could verify that the tone was coming out at the proper frequency. Indeed, it appears that it works just fine.

IMG_5697

Additionally, I made a few other small changes to my program. The prior version stored the static table in RAM, which is wasteful of a hundred or so bytes of RAM. It doesn’t sound like a lot, but there are only 2048 bytes of RAM available, so every little bit helps.

Addendum: If you want to generate nicer looking sine waves, you could do a lot worse than to use this circuit from Jason, NT7S which serves as a nice little oscillator. It’s a nice little Twin-T oscillator, followed by a very simple little amplifier. You could use an optocoupler in place of the key to drive it, or probably just key it with another 2N2222 or similar transistor.

Addendum2: If you want to go all out, a circuit like this one has a very pretty keying waveform.

//
// Simple Arduino Morse Beacon
// Written by Mark VandeWettering K6HX
// Email: k6hx@arrl.net
// 
// This code is so trivial that I'm releasing it completely without 
// restrictions.  If you find it useful, it would be nice if you dropped
// me an email, maybe plugged my blog @ https://brainwagon.org or included
// a brief acknowledgement in whatever derivative you create, but that's
// just a courtesy.  Feel free to do whatever.
//
// At the request of Andy, I added support to use the Arduino Tone library
// to generate an audio signal (really just a square wave) at 700hz on 
// pin 9 (can be any pin which supports PWM, on the Arduino Uno, those pins
// are 3, 5, 6, 9, 10 or 11, and are usually marked with a dash next to them).
// 
// NOTE: the audio signals is just a square wave.  It's not got a great 
// tone, and may click or chirp at the end.  It's mostly useful as a 
// sidetone generator, and probably should not be fed into the mic input
// of a transmitter to send MCW.

// This defines the pin that will have the audio signal

const int sndPin = 9 ;        

// Sound frequency (in Hz)
#define SND_FREQ        (700)

// If you leave NOISY defined, the Arduino will print out each character
// as it is sent to the serial port.  You might want to comment this out
// (put // at the start of the line) if you are especially cramped for
// memory, otherwise it doesn't hurt to leave it in place, even if you
// don't hook the serial port to anything.
//
// If NOISY is defined, then the size of the program is...
//      Program:    4938 bytes (15.1% Full)
//      (.text + .data + .bootloader)
//
//      Data:        399 bytes (19.5% Full)
//      (.data + .bss + .noinit)
// 
// If NOISY isn't defined
//      Program:    2964 bytes (9.0% Full)
//      (.text + .data + .bootloader)
// 
//      Data:         48 bytes (2.3% Full)
//      (.data + .bss + .noinit)
//

#define NOISY

struct t_mtab { char c, pat; } ;

// Compared to my earlier version of this code, we can 
// save some precious RAM by storing this constant table
// in flash memory.  

const struct t_mtab morsetab[] PROGMEM = {
    {'.', 106},
    {',', 115},
    {'?', 76},
    {'/', 41},
    {'A', 6},
    {'B', 17},
    {'C', 21},
    {'D', 9},
    {'E', 2},
    {'F', 20},
    {'G', 11},
    {'H', 16},
    {'I', 4},
    {'J', 30},
    {'K', 13},
    {'L', 18},
    {'M', 7},
    {'N', 5},
    {'O', 15},
    {'P', 22},
    {'Q', 27},
    {'R', 10},
    {'S', 8},
    {'T', 3},
    {'U', 12},
    {'V', 24},
    {'W', 14},
    {'X', 25},
    {'Y', 29},
    {'Z', 19},
    {'1', 62},
    {'2', 60},
    {'3', 56},
    {'4', 48},
    {'5', 32},
    {'6', 33},
    {'7', 35},
    {'8', 39},
    {'9', 47},
    {'0', 63}
} ;

#define N_MORSE  (sizeof(morsetab)/sizeof(morsetab[0]))

#define SPEED  (12)
#define DOTLEN  (1200/SPEED)
#define DASHLEN  (3*(1200/SPEED))

const int LEDpin = 13 ;

void
dash()
{
  digitalWrite(LEDpin, HIGH) ;      // turn on the LED
  tone(sndPin, SND_FREQ) ;          // and the sound output..
  delay(DASHLEN);
  digitalWrite(LEDpin, LOW) ;       // then back off
  noTone(sndPin) ;                  // and silence...
  delay(DOTLEN) ;
}

void
dit()
{
  digitalWrite(LEDpin, HIGH) ;      // again, LED on...
  tone(sndPin, SND_FREQ);           // and sound...
  delay(DOTLEN);
  digitalWrite(LEDpin, LOW) ;       // off...
  noTone(sndPin) ;                  // quiet...
  delay(DOTLEN);
}

void
send(char c)
{
  unsigned int i ;
  if (c == ' ') {
#ifdef NOISY
    Serial.print(c) ;
#endif
    delay(7*DOTLEN) ;
    return ;
  }
  for (i=0; i<N_MORSE; i++) {
    if (pgm_read_byte(&(morsetab[i].c)) == c) {
      unsigned char p = pgm_read_byte(&(morsetab[i].pat)) ;
#ifdef NOISY
      Serial.print(c) ;
#endif
      while (p != 1) {
          if (p & 1)
            dash() ;
          else
            dit() ;
          p = p / 2 ;
      }
      delay(2*DOTLEN) ;
      return ;
    }
  }
  /* if we drop off the end, then we send a space */
#ifdef NOISY
  Serial.print("?") ;
#endif
}

void
sendmsg(const char *str)
{
  while (*str)
    send(*str++) ;
#ifdef NOISY
  Serial.println("");
#endif
}

void setup() {
  pinMode(LEDpin, OUTPUT) ;
  pinMode(sndPin, OUTPUT) ;
#ifdef NOISY
  Serial.begin(9600) ;
  Serial.println("Simple Arduino Morse Beacon v1.0") ;
  Serial.println("Written by Mark VandeWettering <brainwagon@gmail.com>") ;
  Serial.println("Check out my blog @ https://brainwagon.org") ;
  Serial.print("LED will blink on pin ");
  Serial.println(LEDpin);
  Serial.print("Sound will be generated on pin ");
  Serial.println(sndPin);
  Serial.println("") ;
#endif
}

void loop() {
  sendmsg("K6HX/B CM87") ;

  tone(sndPin, SND_FREQ) ;
  delay(20000);
  noTone(sndPin) ;
  delay(3000) ;
}