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.
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.
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.
[sourcecode lang=”cpp”]
//
// 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) ;
}
[/sourcecode]