Another try at an Arduino Based Morse Beacon

November 14, 2009 | Amateur Radio | By: Mark VandeWettering

Back in 2008, I blogged about a stupid program I wrote to implement a Morse Beacon on the Arduino. I couldn’t find that code, and it was stupid anyway, so I went ahead and implemented a new version, with an added improvement: it doesn’t hardcode dots and dashes, it has a built in table. Right now, the message is hardcoded into the program, but in the future, I’ll probably work up a trivial command language so you can change the message and speed, and store the message in the on-chip eprom. On the other hand, doing it by modifying the program source code isn’t really very much harder than getting a terminal to talk to your Arduino (it might even be easier) so this still might be the best way.

Basically, this just puts a logic high state on output pin #13 whenever the keydown should occur, and low when it is released. My Arduino is one of the older ones, so I needed to put an LED in myself, but I understand more modern ones have a built in LED. You could use whatever output pin you like though, with the obvious modification. To turn it into a full fledged keyer, you just need a transistor to handle the switching. On this model of Arduino, pin 13 has a 1K resistor in series to current limit, so you should just be able to put in any NPN transistor (base in pin 13, emitter to ground) and then use the collector/emitter to key the transmitter (I might also think about using an optoisolator, just to be safe).

This is overkill in a lot of ways: the program, sloppily as it is written only takes about 1/7 of the memory on my Arduino, and modern ones have double the space. We could do the same with a very small Atmel. But Arduinos are available and versatile, and have considerable potential. Worth playing with.

//
// 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.
//


struct t_mtab { char c, pat; } ;

struct t_mtab morsetab[] = {
  	{'.', 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))

int LEDpin = 13 ;

void
dash()
{
  digitalWrite(LEDpin, HIGH) ;
  delay(DASHLEN);
  digitalWrite(LEDpin, LOW) ;
  delay(DOTLEN) ;
}

void
dit()
{
  digitalWrite(LEDpin, HIGH) ;
  delay(DOTLEN);
  digitalWrite(LEDpin, LOW) ;
  delay(DOTLEN);
}

void
send(char c)
{
  int i ;
  if (c == ' ') {
    Serial.print(c) ;
    delay(7*DOTLEN) ;
    return ;
  }
  for (i=0; i<N_MORSE; i++) {
    if (morsetab[i].c == c) {
      unsigned char p = morsetab[i].pat ;
      Serial.print(morsetab[i].c) ;

      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 */
  Serial.print("?") ;
}

void
sendmsg(char *str)
{
  while (*str)
    send(*str++) ;
  Serial.println("");
}

void setup() {
  pinMode(LEDpin, OUTPUT) ;
  Serial.begin(9600) ;
  Serial.println("Simple Arduino Morse Beacon v0.0") ;
  Serial.println("Written by Mark VandeWettering <k6hx@arrl.net>") ;
  Serial.println("Check out my blog @ https://brainwagon.org") ;
  Serial.println("") ;
}

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

Addendum:


Addendum2:

Josh asked me how the morse code table works. It’s a little bit clever (a very little bit) but I guess it does require some explanation. Morse code characters are all length six or less, and each element is either a dot or a dash, so it would seem that we can store the pattern in six bits. Let’s say that dits are zero and dahs are one. Lets store them so the first element gets stored in the least significant bit, and the next in the second most, and so on. The only trick is knowing when there are no elements left, because otherwise we can’t tell (for example) K (-.-) from C (-.-.) To do that, we store a single extra one after all the other elements are taken care of. Then, when we are looping, we do the following. If the pattern is equal to one, we are done (that’s our guard bit). If not, we look at the least significant digit. If it is a zero, we have a dit, if we have a one, it’s a dah. We then get rid of that element (by dividing by two, or shifting right if that floats your boat) and repeat. Voila. Each character takes only a single byte to store its pattern, and decoding is just done in a few instructions.

Hope that helps.

Addendum3: Well, I couldn’t leave that alone, witness this…


There are many examples that people use to output sound, most of which seem to bang an output pin high or low, call delay to wait a given number of microseconds, then change its state. This seems odd to me, because the Arduino has some pretty good pulse width modulation. This can be used to make higher quality sound, but for me, it also proved to be easier. I just configured pin 9 to be an output pin, and then used analogWrite(9, 128) to turn on the sound, and analogWrite(9, 0) to turn the sound off. That’s it! You get about a 500hz tone, and it works really well.

Click here for the source code.

Comments

Comment from Josh Smith (kd8hrx)
Time 11/14/2009 at 2:14 pm

Mark,
Perhaps it’s my lack of morse knowledge but I’m having trouble understanding how your morse table works. Would you care to explain it?

Comment from Josh Smith (kd8hrx)
Time 11/14/2009 at 5:49 pm

Mark,
Thanks for the explanation. It makes perfect sense now, I’m not sure why I couldn’t wrap my head around it earlier.

Pingback from Morse code beacon using Arduino | SquareCows
Time 11/19/2009 at 6:04 am

[…] a quick-and-dirty morse code beacon? Then you might be interested in Mark VandeWettering’s Arduino Based Morse Beacon. I really like the clever way that he stores the code sequences for each […]

Pingback from innismir.net — Arduino Project #1: Trivial Morse Beacon
Time 12/30/2009 at 10:06 am

[…] Uhhh… Yeah, so I guess Mark updated his beacon and did some pretty impressive stuff, making my implementation look like a Pinto while his is a Corvette. Oh well. It was a learning […]

Pingback from Rob’s Blog » Blog Archive » Unimaginably Pointless Arduino Projects
Time 1/1/2010 at 11:26 pm

[…] Mark VandeWettering’s excellent morse implementation, documented here […]

Comment from Joe
Time 4/2/2010 at 12:19 pm

Mark, Really like this beacon. I am turning it into a memory keyer. I hooked it up to my rig to send CQ. I would like to add more messages and make them switch selectable. Any ideas how I could do that? 73 -Joe

Comment from dmeon
Time 5/29/2010 at 12:11 am

Hey! Really like your method of storing the code sequences.

Comment from lastaid
Time 10/7/2010 at 1:27 pm

thanks a lot for the code, did a quick port for msp430 🙂

http://www.youtube.com/watch?v=_ZhDaLsDFAA

have fun

Comment from David Bamford
Time 10/17/2010 at 9:33 am

Mark: Can you provide a link to your amended code for generating sound? (current link is broken) Thanks and 73 W2DAB

Pingback from Beacon morse | CheapArt
Time 3/4/2011 at 4:03 am

[…] brainwagon » Blog Archive » Another try at an Arduino Based MorseBack in 2008, I blogged about a stupid program I wrote to implement a Morse Beacon on the Arduino. I couldn’t find that code, and it was stupid anyway, so I went ahead and implemented a new version, with an added improvement: it doesn’t hardcode dots and dashes, it has a built in table. […]

Comment from Costas SV1XV
Time 6/25/2011 at 9:39 am

Nice application for Arduino. I have uploaded it to an Arduino Mega and I am experimenting with different more code speeds, delays etc.

Comment from peter sawyers
Time 7/10/2011 at 1:01 pm

Hi, i’m a newbie to Arduino and was wondering if you could configure a output to turn on the transmitter when sending the morse id and the off when done. thanks Pete

Comment from JP McGinley
Time 8/30/2011 at 6:42 pm

Mark,
Thanks a bunch. Tell your son we Thank him for his service to our country. As far as keying the transmitter, I am going to try the FET like on K1ELs K12 keyer. I am trying to get this to work on a teensyduino 2.0, No joy. I have changed the LED Pin to 11 and have had no success. Has anyone else tried this on a teesy?
TNX 73s
J.P.

Comment from John Coleman
Time 11/12/2011 at 6:43 pm

Hi Mark, great code, just what I wanted to use for a beacon on a spare 10 meter rig I have.
I shall use it to drive a 5 volt relay which will act as a key.
73
John VK7CTK

Comment from Eric
Time 11/15/2011 at 5:25 pm

Would it be possible to get an example of the optoisolator to use this setup to key my FT-817, safely? One could put this on one of the smaller Arduino’s and make a nice portable beacon. Good stuff!! Thanks!

Comment from Mark VandeWettering
Time 11/16/2011 at 12:35 pm

I haven’t done this, but I imagine what you want to find is a photodarlington. The collector/emitter would be connected to key inputs on the FT-817, the other side would be hooked through a current limiting resistor (maybe 1K?) to the emitter / ground side. That’s pretty much it… A reasonable part would be the 4N25.

When I experimented with this, I didn’t bother with an optoisolator: I simply keyed it using an NPN transistor. But this is probably a good idea: I will consider it for a more indepth blog post in the future.

Comment from Mark VandeWettering
Time 11/16/2011 at 12:43 pm

Addendum: http://www.qsl.net/wm2u/interface.html has a schematic which should work just fine:

http://www.qsl.net/wm2u/images/interface_dtr_opto.gif

Comment from Chris GW6KZZ
Time 4/2/2012 at 5:27 pm

Hi Mark, sadly the link to download your Morse Beacon code is broken but managed to grab it from your page above and import it onto Arduino 1.0 programmer. Like a few people I want to use my Arduino Nano in a similar way to K1EL PIC K-12 keyer on a nanowave project. Thanks for taking the time to put your morse code beacon code online for others to try, good to see how different people see a way of creating code too. All the best, Chris.

Comment from Mark VandeWettering
Time 4/2/2012 at 8:05 pm

Thanks Chris! Glad to be of help.

Comment from Niceto
Time 5/5/2013 at 10:36 am

Hi, Mark
Many thanks for sharing your fantastic code to generate CW on arduino plattform.
Just used your code to make a CW qrpp beacon, using an Arduino uno and an inexpensive DDS board with the AD9850.
Just heard from Remote RX site 22km apart (4499
Code can be downloaded from: http://www.verfotos.es/intercambio/arduinobeacon.ino

I also attach the code:
// Modified and adapted as a qrpp CW beacon using arduino uno and AD98550 board
// Hardware wiring and Code to send a sinewave carrier with AD9850 taken from
// http://nr8o.dhlpilotcentral.com/?p=83 Thanks Ron!!
// CW sending code was taken from https://brainwagon.org Thanks Mark!!
// Almost all merit belongs to the above authors. I only did the adapting job and added “+ – = ” codes
// I am not a good programmer, but it works!. Feel free to improve and correct bugs.
// If you modify will be nice to send a brief note to Mark and Ron, real fathers of code
// I also will appreciate you send a note with the improved/modified code to ea5ehs[at]gmail.com Niceto Muñoz
// 73 es DX from Niceto (EA5EHS)

// Modificado y adaptado como baliza CW qrpp, usando “Arduino uno” y una placa con “AD9850”
// El conexionado y el código para generar una señal senoidal con el AD9850 se ha tomado de
// http://nr8o.dhlpilotcentral.com/?p=83 Gracias Ron!!
// El código para generar los caracteres CW se ha tomado de https://brainwagon.org Gracias Mark!!
// Casi todo el mérito pertenece a los autores anteriores. Yo únicamente hice el trabajo de adaptar los dos códigos,
// añadiendo tambien los caracteres cw para “+ – =”.
// Yo no soy un buen programador, pero funciona!. El código es totalmente libre para mejorarlo y corregir errores.
// Si lo modificas, estaría bien que enviaras una pequeña nota a Mark y Ron, padres reales del código.
// Tambien me gustaría que me enviaras una copia del código mejorado/modificado a mi correo ea5ehs[arroba]gmail.com
// 73 es Dx Niceto (EA5EHS)

struct t_mtab { char c, pat; } ;

struct t_mtab morsetab[] = {
{‘+’, 42},
{‘-‘, 97},
{‘=’, 49},
{‘.’, 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 W_CLK 8 // Pin 8 – connect to AD9850 module word load clock pin (CLK)
#define FQ_UD 9 // Pin 9 – connect to freq update pin (FQ)
#define DATA 10 // Pin 10 – connect to serial data load pin (DATA)
#define RESET 11 // Pin 11 – connect to reset pin (RST).

#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }

#define FREQUENCY 10133500
#define FREQUENCY2 0 //putting a second frequency different from 0, you also generate an inverse keying CW signal that can be heard using FM mode 🙂
#define N_MORSE (sizeof(morsetab)/sizeof(morsetab[0]))
#define SPEED (12)
#define DOTLEN (1200/SPEED)
#define DASHLEN (3*(1200/SPEED))

void
dash()
{
sendFrequency(FREQUENCY);
delay(DASHLEN);
sendFrequency(FREQUENCY2);
delay(DOTLEN);
}

void
dit()
{
sendFrequency(FREQUENCY);
delay(DOTLEN);
sendFrequency(FREQUENCY2);
delay(DOTLEN);
}

void
send(char c)
{
int i ;
if (c == ‘ ‘) {
delay(7*DOTLEN) ;
return ;
}
for (i=0; i<N_MORSE; i++) {
if (morsetab[i].c == c) {
unsigned char p = morsetab[i].pat ;

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 */
Serial.print("?") ;
}

void
sendmsg(char *str)
{
while (*str)
send(*str++) ;
}
// transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA line
void tfr_byte(byte data)
{
for (int i=0; i>=1) {
digitalWrite(DATA, data & 0x01);
pulseHigh(W_CLK); //after each bit sent, CLK is pulsed high
}
}

// frequency calc from datasheet page 8 = * /2^32
void sendFrequency(double frequency) {
int32_t freq = frequency * 4294967295/125000000; // note 125 MHz clock on 9850
for (int b=0; b>=8) {
tfr_byte(freq & 0xFF);
}
tfr_byte(0x000); // Final control byte, all 0 for 9850 chip
pulseHigh(FQ_UD); // Done! Should see output
}

void setup() {
// configure arduino data pins for output
pinMode(FQ_UD, OUTPUT);
pinMode(W_CLK, OUTPUT);
pinMode(DATA, OUTPUT);
pinMode(RESET, OUTPUT);

pulseHigh(RESET);
pulseHigh(W_CLK);
pulseHigh(FQ_UD); // this pulse enables serial mode – Datasheet page 12 figure 10
}

void loop() {
sendmsg(” V V V XX0XX/B QRPP BEACON E E E E E E E E E E”) ;
delay(1500) ;
}

Comment from Ty Tower
Time 11/26/2013 at 2:28 pm

Thanks -good fun
Did you get the side tone in pwm done? Is there a link to the code?

Comment from Ty Tower
Time 11/27/2013 at 12:59 pm

Silly me , there it was in the notes
” I just configured pin 9 to be an output pin, and then used analogWrite(9, 128) to turn on the sound, and analogWrite(9, 0) to turn the sound off. That’s it! You get about a 500hz tone, and it works really well.”
And I agree thanks

Comment from Ty Tower
Time 11/28/2013 at 1:27 pm

The link above needs a slash after org/ in the url Still gives a 404 but at least it gets there

Comment from Michele
Time 12/31/2013 at 7:45 am

I’ve found very useful your program. Only one thing how to send a long line for example 3 second using just a “letter” example underscore?

Pingback from Les applications Arduino Hamradio | Le Blog de F8ASB
Time 2/15/2014 at 6:50 am

[…] Balice CW video de […]

Comment from Kent
Time 4/9/2014 at 4:45 pm

The link to the source code that you wrote the addendum to add sound does not seem to work. configured pin 9 to be an output pin, and then used analogWrite(9, 128) to turn on the sound, and analogWrite(9, 0) to turn the sound off. That’s it! You get about a 500hz tone, and it works really well. I am not sure where to add these lines. Could you send me that code. I am an absolute newb at coding and arduino. Thanks for a great blog!! Kent.

Comment from John W
Time 5/1/2014 at 2:02 pm

Used your code which is going in a soon to be built beacon. Great code made it easy to change if I have to. After I get my beacon going I am going to try to write code to also send the temperature at the end.https://www.youtube.com/watch?v=-uPV6eKAHNo&list=UUXYM5DZfQMm1zIYbeDgn_9A

Comment from DP
Time 11/23/2014 at 6:09 am

Hi everyone,
could someone please help me finding a way to transmit the value of an integer variable? the function sendmsg() should be used to send a string which corresponds, for example, to an analog reading of a sensor.
regards and thanks.
73

Comment from Andy
Time 3/29/2015 at 12:46 pm

Hi Mark, thank you for the arduino keyer. I- m building a 10 ghz beacon and I would like to use arduino for keyng cw it. I would like to try the other software, the one with the sound (analogwrit …), but I can’t find it. I’m not a software writer…. Can you help me?
Thanks
Andrea iw0eac Rome italy

Comment from Bert Gnaccarini
Time 5/7/2015 at 6:28 am

Thanks Mark. Excellent piece of code and very readable. I used a modified version of your code for our club’s new 2m beacon. I combined into a state machine program that also looks at some alarms from the TX and the GPSDO and uses the alarms to change the message keyed out as well as the keying speed. Your good work is acknowledged in the code header.
Cheers,
Bert, VK3TU

Comment from Dream Island
Time 6/6/2015 at 9:07 am

Thanks for your perfect code, but I have a question about sending data using CC1101 and Arduino and using these principle to send Morse Code, could you help me, I need it please, I hope you give an idea about sending data using CW with CC1101+Arduino.
Regards.

Comment from Jean-Luc
Time 9/1/2015 at 9:18 am

Bravo and thank you for this code, it is a good job!
I just finished a radio beacon and it’s your code that generates the CW.
Thanks again.
F1IEY – Jean-Luc

Comment from N5EN
Time 11/26/2015 at 7:54 am

Mark,

Thanks so much for the wonderful code. I am using it on a “smart” DTMF controller project to give me feedback when I successfully enter a 4 digit DTMF code to turn on or off several relays. I have the receiving radio go into transmit and send back information in CW if a relay was turned off or on.

Anyway, I was getting a compiler warning with the following statement:

void sendmsg(char *str)

it still worked, but I found that changing it to:

void sendmsg(const char str[])

made the compiler happier and no warning. I don’t completely understand what the problem was, but this works without warnings now.

Thanks again,

Neal N5EN

Comment from David Palm
Time 7/28/2016 at 10:22 am

Code works great! I have grand visions of a multi-band beacon up on my silo, all Arduino-controlled. I’m gathering parts, but it’s a great initial start just to get some nice, well-spaced CW out of the Arduino. The next step will be to run some RF into an Analog Devices ADG918 RF switch, key that with the Arduino running this code, and see how that sounds on a receiver. I’ll update my own blog as I make progress. Tnx de W9HQ.