I find the history of Morse code fascinating. I admire those that are able to send and interpret Morse code messages at high speed.
Some time ago I saw a YouTube video about a Morse Code decoder that was based on a micro controller. I didn’t see the schematic or the code but I was very impressed that it was possible with relatively few components. I didn’t know how it was achieved but the puzzle of the design continued to percolate away in the back of my mind.
A Morse code decoder has a lot of elements that interest me. It covers radio history, codes, electronics and programming. Attempting to design one was an opportunity to learn about detecting data patterns, try out some case build ideas I had as well as learn a bit more about Morse Code.
I had an idea that it may be possible using an interrupt routine and using it to look at the time between triggered interrupts. I set myself a challenge to design one. Soon I would be hearing messages by spies in exotic locations, possibly in an attic, wearing trench coats and fedoras tapping out their secret messages to their HQ, or more likely not.
I’ll say straight up that I am not a developer or have electronics training. This is just a hobby and I have not written a lot of code for the Arduino. This design is unlikely to be the best out there. It’s just a result of the result of the challenge I set myself. I’m just documenting the project for fun and maybe inspire others to design their own projects.
In designing the decoder I wanted to achieve:
- The decoder to use a microphone as the input. Any Morse it hears is displayed as plain text on a display.
- Convert text from a clear source with little noise that is sent at speeds in excess of 20 wpm
- Use an Arduino Nano as the microcontroller, not because it is the best, but because it is the only one that I am familiar with and I don’t have a desire to learn others at the moment.
- Other parts should be common components or modules and not many of them.
- Use a 20 x 4 LCD for simplicity. I really like these displays even though they are a bit old school. In my opinion, the glowing backlight seems to have the right aesthetic for the project.
- Display to show
- Top line: The length of the latest received dot and the speed set and speed received
- Middle two lines: Plain text of the latest received message
- Bottom line: The latest received dots and dashes
- Manual mode allows user to set speed using a potentiometer
- Auto mode that automatically tracks sending speed.
- Potentiometer to set the input sensitivity
- An LED that lights when the microphone module activates, that is it is receiving a dot or dash. There is one already on the microphone module I used.
- An LED that illuminates when the processor believes it is receiving a dot or dash. I started with D13 as it was already on the module.
- Build into a wooden box made from old timber I had. Part of the build was trying to come up with a simple to build and interesting project enclosures.
- Paint the front and back panels black.
The project was partly about trying out some ideas with the case as well as the actual unit.
While it could do with a bit more development and tweaking, it is now at a point that it works reasonably well, at least where the audio doesn’t have too much background static and hiss. It decodes the Morse of this recreation of the messages from the Titanic on this YouTube video fairly reliably.
I started with a simple Morse key that I made from a piece of scrap timber, bending a piece of metal strapping from around the packing of some large item we had purchased, a few screws and an old knob. Added a pulldown resistor and capacitor to reduce bouncing. I connected it to an LCD module and an Arduino Nano. After quite a bit of coding, well lots more thinking than coding, I was able to get it display a single character on the screen with input from the Morse key. Sending Morse using appropriate timing, even slowly is much harder than I expected. With that working I was encouraged and then added a standard audio module and gave up on the key. It was some time before I got any success with that, which brings me to an unexpected feature of the audio module.
The digital output of the audio module wasn’t what I expected
The audio module has two output pins; an audio output and a digital output. I was expecting the digital output would change when the audio tone of a beep was detected and change back when the tone ended. That’s not quite what I found. I have one of those really cheap data analysers that plug into my laptop. This is what I saw when I connected it up.
There are lots of ups and downs… a real lot. Perhaps it is changing at the frequency of the tone playing or at least at a ratio of the tone. If so that opens up further questions and ideas for exploration in the future. Meanwhile how do I get rid of those? I also had a look on the oscilloscope.
I tried adding a smoothing capacitor as they have in power supplies. I found 22uF worked but sometimes affected the first mark in a word resulting in the wrong character being displayed. What about a low pass filter? I don’t know much about them and I’ve never made one before. I found several sites that calculate the values of a resistor and capacitor for a low pass filter, but what frequency should I be aiming for? In the end I experimented with the output connected to an oscilloscope and Morse playing into the mic. The result is based on one of a few different capacitors I had and by tweaking a variable resistor. The waveform on the oscilloscope looks far from square, in fact it looks really bad.
It looks better on the data analyzer.
The text on the display Morse decoder was surprisingly accurate.
Prosigns. What are prosigns?
I was not aware of prosigns, but soon came across them on the Wikipedia Morse Code page. Prosigns are characters that have a value that is has a text equivalent that is more than one character. The most well known one outside of Morse operators is probably SOS. It is not designed to be sent as three different characters, rather as one long character, that is …—… The spacing between the S and O bits is the same spacing as the within the S and O bits. It seemed like a good idea to support SOS and if I was going to do that I may as well cover as many prosigns as possible. SOS also has the most marks (dots and dashes) of any I found, so the sketch supports up to 9 bit characters.
Wait, some characters can be a prosign or another character?
Yes they can. It looks like there have been different standards used that has resulted in some Morse patterns set to different characters or prosigns, for example -.–. can be KN or (
So far I have not been able to work out which is the best to use so I’ve taken the easy way out and display both. In this example <KN/(> is displayed.
Display update speed was important
When dots can be as short as 20-30 milliseconds the time to update the display becomes significant. Well the speed of the whole sketch probably becomes significant. I tried to improve the speed in the rest of the sketch as best I could, but I’m sure it could be improved further. Updating the display was definitely slow. I decided to try two methods to speed it up.
The first was to remove the I2C backpack from the display and connect it up directly to the Arduino. This meant more wiring and required another pot for the contrast and resistor for the backlight, but it was not that difficult. The display updated in about half the time. A good result.
The other idea was to try a different library. After reading this forum post I decided to give the hd44780 library a go. I was expecting significant code changes to get it to work, but instead I only needed to change a few lines at the start of the sketch. The result was another three times faster. That’s about 6 times faster with both changes. Not only that but the display seemed clearer. I suspect there is less clearing and overwriting text. This should make up for some of my less efficient code J
How do you calculate speed? Surely there is a single standard
To assist in setting the morse speed to ensure the timing is correct I’ve used the dot length in milliseconds to convert to words per minute. I based the conversion on the PARIS
Number of dot lengths per second = 1000 / dot length in ms
W = 1200 / T (ms)
Where: T is the unit time, or dot duration in milliseconds, W is the speed in wpm
Examples: 150ms = 8wpm, 100ms = 12wpm, 50ms = 24wpm, 20ms = 60wpm
It sounded simple enough but while there is standard timing, e.g. gaps between marks should be one dot length and dashes should be three dot lengths but that’s not always what is being sent. So the dot length may not reliably indicate how many words would actually be sent in a minute. I don’t know that it matters, but don’t know that it doesn’t.
A few notes about the code
The code is available in my Github repository https://github.com/garrysblog/Arduino-Morse-Code-Decoder
What could be improved?
Its structure could be improved. I am trying to write well structured code, but I’m not there yet.
It does not support some characters with homoglyphic diacritical marks, for example ä.
The automatic setting could be improved. If follows along with changing speeds ok, but it sometimes adds spaces when it shouldn’t, it also has trouble if it quickly changes for example when it switches between to senders that are using very different speeds.
The speed potentiometer can be set on the border of different speeds and the display flickers between two different speed numbers. Perhaps it would be better with a rotary encoder with the speed could be saved in EPROM memory so the setting is the same next time it is turned on. However, I do like the simplicity and usability of a potentiometer.
Auto speed sensing and noise handling also could be improved.
The hardware could be improved too. That method of filtering the incoming audio is not ideal.
Operation – twiddling the knobs
This is how I operate it:
- Place the microphone in front of the speaker sounding the Morse
- Adjust the input sensitivity so that the audio LED flashes in time with the sound of the Morse
- For manual operation, set the function to Manual
- Look at bottom line of the display and adjust the speed pot so that it is displaying both dots and dashes in the pattern I hear
- Look at the received and set speed numbers on the top line of the display and adjust so the set number is similar to the received number
- Look at the text being received. If necessary, tweak the speed setting to get spacing correct.
- For auto mode, simply set the function to Auto.
Switching to auto sets the speed to the current set speed and then tries to track the received speed by averaging the length of recent received dots. While it works ok, manual mode holds the speed to a more stable setting.
The case has built from some old timber. Originally destined for wooden crates it had been sitting in a shed since the 1960s or 70s.
There is a description of the wiring in the code, but I intend to also create a diagram that I will upload with the files in the Github repository.
- KY-037 Audio module to Detects sound. Digital output pin goes low when the sound level exceeds set threshold.
- Arduino Nano
- 20×4 LCD display. I like green best, but most YouTubers seem to prefer blue.
- 10K linear pot to adjust contrast of the display.
- 150 – 270 ohm resistor to limit the current of the display backlight.
- 1 x LED to replace the one on the audio module. This was only needed to make the status visible on the front panel of the case.
- 1 x LED to display the status of the Arduino. The built-in LED on the Arduino can be used instead of this LED and resistor below.
- 1 x resistor to limit current to the LED above.
- Pot to adjust the audio threshold. The Audio module has a pot built onto the module and that can be used for testing. It is fiddly to use so adding one in parallel makes it much easier to use.
- 10K linear pot to adjust the speed of the incoming transmission.
- 6.8 uF tantalum capacitor for low pass audio filter.
- 270 ohm resistor for low pass audio filter.
- SPST switch for power on/off. Not used if powering by USB.
- SPDT switch to switch between manual and auto mode.
- I started with an I2C backpack on the LCD but it was not able to handle faster Morse. If a backpack is used the contrast pot and backlight resistor are not needed.
The Audio module I have does not have any markings but it appears to be a KY-037. I found a circuit diagram for it here http://arduinolearning.com/code/ky038-microphone-module-and-arduino-example.php. Other microphone modules may also work.
The audio sensitivity trimmer pot
The KY-037 has a 100K potentiometer to adjust the threshold where the output triggers from high (nothing detected) to low (sound detected). I found this potentiometer to be very difficult to adjust. I removed the potentiometer and replaced it with an 10K pot and 22K resistor in series. That made it far easier to use and placed the threshold setting at about the midway point. It’s tricky to remove the built-in pot. If I was doing it again I would try soldering a 10k pot and another resistor (maybe 39K) in series with the onboard pot as that would be much easier to wire up.
Audio module LED
There is an LED on the audio module that lights when the output goes low (receive). This is very useful for both testing and adjusting the sensitivity while in operation. When I installed it in the case, I removed the existing LED on the audio module and replaced it with an ordinary 5mm red LED mounted on the front panel.
Filtering the output
The best results I have got is by connecting a resistor between the audio out and Arduino input and a capacitor from the input to ground. The input to the Arduino looks a bit ugly on the oscilloscope but was the best for operation that I tried.
The received status LED
I added this LED as a way to diagnose issues, but found it to be very useful in operation. This LED lights when the interrupt is triggered and the code believes there is a dot/dash being sent. Under ideal conditions, both LEDs should be flashing at the same time and both only when there is sound from the speaker being monitored. It’s a good indicator that something is not set or working correctly.
The speed pot
I used a standard 10K linear pot. This is only used for manual mode.
Should you build it?
Well that’s up to you, but I’ll repeat what I said early on. Building projects is just a hobby for me. I’m not a professional or have professional experience. Keep that in mind. At the very least I hope the project gives you inspiration.