Morse Code Decoder

VK2IDL Morse Decoder displaying live Morse from the VK2WI automated Morse practice transmission on 3.699 MHz.
VK2IDL Morse Decoder displaying live Morse from the VK2WI automated Morse practice transmission on 3.699 MHz.

The idea of building a Morse decoder is the result of having recently returned to amateur radio after a long absence. I had studied Morse Code back in the 1980’s as a requirement for my advanced AOCP and used it regularly enough to maintain a reasonable proficiency for a number of years. I started looking for on-line Morse training websites in the hope of recovering some of my proficiency. In the process I was curious to note that there were a number of hardware and software Morse decoder units available, although reports on their performance varied. And so, the idea of building my own Morse decoder was born.

The VK2IDL Morse Decoder is based on an excellent open source design by Budd Churchward, WB7FHC. The decoder will receive Morse code from an audio source, decode it and display it on a built-in 4 line, 20 character LCD. It includes a software controlled noise impulse filter, an automatic input-frequency tuning circuit and a switchable Farnsworth setting for receiving Morse that uses Farnsworth timing. All functions are controlled by three push buttons along the top of the unit. The unit automatically adjusts itself to the speed of the incoming Morse code and displays the speed on the LCD.

Budd’s original open source project doesn’t actually use an Arduino module as such, instead he incorporates the Arduino’s processor chip and clock components directly onto a ready-made decoder PCB. For my project I’ve integrated WB7FHC’s audio filtering circuit with a standard Arduino Nano and modified his software for my own feature preferences. In fact Budd’s software sketch will work just fine with my circuit although it will operate a little differently to mine. You are of course welcome to try and use Budd’s sketch in this project, you may prefer the operation of his decoder software to mine.

As with several of my projects, I am using the Arduino Nano for this project due to its conveniently small size. If you prefer or have one on hand, you can use an Arduino Uno if you wish, its just bigger and will require a larger case.

Circuit Diagram
As indicated earlier, I have integrated WB7FHC’s audio filtering circuit with an Arduino Nano.

The circuit consists of an LM567 tone decoder, an MPC41010 digital potentiometer, an Arduino Nano and an LCD.

The LM567 is a tone decoder with its centre frequency controlled by a voltage controlled oscillator (VCO). The VCO frequency is set by capacitor (C4) and a variable resistor placed across pins 5 & 6. Capacitors C1 & C2 form a filter with the bandwidth set by the value of C1. Using the component values provided, the bandwidth and frequency range is selective enough that you can select one of several stations that are transmitting close together just by tuning that station to the correct tone. Audio tones from the receiver are fed into pin 3. The output pin 8 normally floats to a logic high due to its output load R1/D1, however if the audio tone at the input matches the frequency of the VCO, the output pin 8 switches low. Hence the LM567 is able to turn a correctly tuned Morse code tone at the input into a series of logic 0s and 1s at the output. D1 switches on whenever pin 8 switches low giving a visual representation of the incoming Morse code.

The MPC41010 is a digital potentiometer. It provides a variable resistance across pins 5, 6 and 7 simulating a normal 3 terminal variable resistor or potentiometer. The value of the resistance is controlled by serial input data from the Arduino applied to pin 3. Pin 2 receives serial clock timing pulses from the Arduino to control the timing of the incoming data. Pin 1 is the Chip Select pin used to enable the MPC41010 for data control. Since the outputs on pins 5, 6 & 7 perfectly simulate a variable resistor, they can be connected directly to the pins 5 & 6 on the LM567 to precisely tune the LM567’s VCO frequency using serial data from the Arduino.

The LCD is a 4 line x 20 character backlit display. It can be purchased locally for under $10 shipped or even less from China. The one used for this project incorporates an I2C interface board piggybacked onto the back of the LCD. This is important as most LCD’s require a lot of wired connections, however the I2C adaptor allows the Arduino to communicate with the LCD using serial data thereby reducing the number of connections to just 4. The LCD can be purchased with a range of backlight colours including Blue, Orange and White. The choice is yours, but if you are planning on building both Morse projects, I’d suggest buying both LCDs at the same time to ensure the backlight colours match as the colour shades can vary between manufacturers and even batches. There is a link to the one I used at the end of this article.

LCD2004A, 20×4 Blue HD44780 Character LCD with an IIC/I2C Serial Interface

Note there is a small (blue) variable resistor on the LCD’s I2C interface board. This is used to control the contrast and is often turned to minimum when shipped. If your LCD backlight is lit but there are no visible characters on the display, adjust this resistor for the required contrast.

Control Switches
Three switches are connected to the Arduino to provide controls for the user selectable options.

SW1 controls the QRN filter settings. The QRN filter resamples the output from the LM567 after a set delay to help eliminate short burst noise pulses from displaying as erratic characters. Each press of SW1 steps upwards through set values displayed as 0 to 8 then cycles back to 0. The minimum filter setting is represented by 0.

SW2 is tunes the LM567 VCO to the frequency of the Morse input tone. With an input tone or Morse signal present at the input of the LM567, press SW2. The MPC41010 will sweep the digital potentiometer upwards then downwards several times to tune the LM567 VCO, while monitoring the LM567’s output pin. After several quick passes the unit will determine the value that places the input frequency at the centre of the tone decoder’s filter and will lock the VCO frequency using that value. The value will be displayed on the LCD as ‘T=xxx’ where xxx is the VCO tuning value. The sweep will tune input tones from around 200Hz up to around 2kHz. In an earlier version of this project I added a rotary control to allow manual tuning of the VCO but I found the digital method finds the centre point more accurately, so I removed the control.

SW3 enables the Farnsworth setting. Farnsworth timings are used for Morse training. The traditional method used for Morse training at slow speeds is to stretch out the timing to give the trainee time to count the dits and dahs for each character. Unfortunately, at higher speeds Morse characters tend to be recognised using rhythms rather than by counting which can result in problems for students as they transition to faster speeds. Farnsworth timing allows the characters to be sent at a faster speed where the rhythm is more obvious, but reduces the timing between characters so that the overall wpm speed is still slower. The problem for the Arduino Morse decoder is that it determines the Morse speed automatically by measuring the timing of the character elements (dits and dahs). If the character spacing is longer than expected, it will interpret these as word spaces and will print a word space between each character, affecting the readability. The Farnsworth switch applies a time-offset to the character spacing to eliminate these extra spaces. The Farnsworth switch has three settings: F0 = Off, F5 = 5 wpm and F8 = 8 wpm. Note that even with the Farnsworth settings on, the display will continue to display the normal calculated wpm based on the timing of the dits and dahs.

I have not provided a recommended PCB layout for this project. Most of the circuit is audio so layout is not too critical. My only recommendation is to mount C1 and C2 close to the LM567 pins. The components are hand wired onto some prototyping PCB. These have a series of plate-thru holds but no connected tracks. Simply solder the components into place then use the wire wrap wire to provide the interconnections underneath. There aren’t many components, so you should be able to keep the assembly quite compact. A photo of my PCB assembly is shown below. I’ve mounted the Nano on the same PCB then trimmed the PCB to size to fit into the Jiffy box. In time I may produce a PCB layout for this.

Main PCB Assembly

For connecting the LCD and switches I used normal multi-core hookup wire. Images of the prototype PCBs and wire-wrap wire I used are shown below for reference. Links and references to component sources are listed at the end of this page.

You can package the Morse decoder any way that’s convenient to you. I mounted mine in a Jaycar jiffy box. The LCD was mounted in the lid along with the LED. The switches were soldered to a strip of prototype PCB then mounted along the top and the sockets for connecting the audio input and USB power connector were placed at each end. Note that the USB socket needs to protrude through the case to allow the USB plug to be fitted.

As you can see I got lazy and didn’t go to too much trouble with the mounting mechanics as there’s not much mechanical stress. I made use of some hot melt glue to hold some of it in place. The only exception is the LCD and switch PCB which should be mounted using stand-offs to ensure it can withstand normal handing in the field. As you can see the LCD is a snug fit inside the lid so check you have it aligned correctly when cutting out the panel so that the edges of the box clear the PCB.

Inside Assembly
Lid Assembly

My software sketch is also based on WB7FHC’s Arduino sketch which I originally used to test my hardware, after which I made a number of modifications before getting to the final version. This circuit should still work with WB7FHC’s original software sketch so you are welcome to try both versions although the operation is quite different.

The VK2IDL Morse software sketch is available on GitHub – a software repository for storing code for public download. You will find the code for this project at

LCD Library

You will need to install the LCD library into your Arduino IDE to support the LCD. The library I used is from Francisco Malpartida and can be downloaded from . At the time of writing this, the latest version was 1.5.1 .

Customising the Code

There are a couple of sections of the software that you should ‘customise’ to your application.

Callsign: Your Call sign is displayed on the LCD at startup. It presently defaults to VK2IDL. You should alter this in the software. Look for the line shown below and simply change VK2IDL to your own call sign.

#define myCall "VK2IDL"         // Callsign of User

LCD Address: The Arduino identifies the LCD on the I2C bus by calling its address. My LCD uses the address 0x27 (27 Hex) which is a fairly common preset address for these modules. If for some reason your LCD has a different address you will need to determine what the new address is, then change the line below.

const int i2c_addr = 0x27;     // Define LCD I2C bus address 

To determine the address of your LCD, you can temporarily upload a free ‘Address Scanner’ sketch into the Arduino that will scan the I2C bus and display any addresses that it finds. The link to the scanner is:

NOTE: You will not not need to do this unless you cannot get your LCD to work. Before using the scanner program, try adjusting the blue pot on the LCD’s I2C board to see if the contrast has been turned down (this is common when the board is delivered). If are able to adjust the contrast and see the character blocks on the display but no text, then try the scanner to see if the address needs to be corrected. Details on how to use the scanner are shown further below.

To use the I2C Address Scanner, after connecting the LCD to your Arduino board, load the sketch above into the Arduino IDE and upload it into your Arduino Nano. Open the ‘Serial Monitor window’ of the IDE and the address should be printed on the monitor screen. Once you have the address, copy the address into the Morse Decoder sketch on the line shown above and save the sketch before writing it back to the Arduino Nano.

A few details about the code
The following code defines some of the pin connections used by the Nano, in case there comes a need during construction to make any changes. If you need (for example) to move a switch to a different pin, simply locate the line for that switch and change the pin number. If you use the NANO with the circuit supplied you will not need to make any changes to this part of the code, but its here for reference.

Line 72: #define farnsBUTTON 5            // Pin for Farnsworth Switch
Line 73: #define sweepBUTTON 6            // Pin for LM567 Decoder tuning Switch
Line 74: #define filterBUTTON 7           // Pin for QRN Filter Switch
Line 75: #define signalPIN 8              // LM567 Tone Decoder output connects here
Line 79: #define slaveSelectPin 10        // Connected to Pin 1 ‘CS’ of the MPC41010

Using a different Arduino module
If you have no previous experience with the Arduino I suggest you use the Nano as I’ve described here to ensure the correct pin connections. This is because the physical pinouts will vary among the different models. If you choose to use another Arduino module (perhaps you have a spare Uno in the workshop) then it is important to ensure that you download a diagram of the pin assignments for your board and compare them to that of the Nano. The pins are labelled by their functions, not by their physical pin positions (e.g. D5 is Digital port 5, A4 is Analog port 4, etc. You should therefore match the connections for different boards by their labels rather than their physical pin positions. Note also that the Arduino has dedicated serial communications ports which we have used to talk to the MPC41010 and the LCD. For the MPC41010 these pins are labelled SS, MOSI and SCK. For the LCD they are SCL and SDA. All Arduino boards will have these dedicated ports so look for these labels on the pin assignment diagram for your module if transposing the circuit to another module.

Power Source
The Arduino is powered by its USB connector and the entire project can be run from any USB power source. For portable use it will run for many hours on a portable mobile phone charger or the USB port of your laptop.

Instructions for Use
Plug the 5V power source into the USB socket. The unit will power up and display an introductory screen showing the software version and your call sign. After a few seconds it will switch to the main screen. At the top of the display are 4 fields.

QRN Filter
‘f1’ is the QRN filter setting. With clear conditions you can set this to 0. Under noisy conditions, if you are hearing static crashes or noise that triggers random characters on the display, increase the filter value by pressing the Filter switch. Each press increases the value by 1 up to a maximum of 8, then recycles back to 0. Be aware, the greater the filter value to more risk of decode errors because the filter adds a delay which can affect the Morse decoding

Tone Frequency
‘T’ is the Tone (VCO) frequency tuning value. It displays the value that the decoder is using to tune the VCO to your input tone frequency. The default setting (201) equates to a frequency of around 615Hz (which matches the side tone frequency of my FT757GX transceiver).

Farnsworth Timing
‘FO’ is the farnsworth setting. Farnsworth settings are used for Morse training by sending Morse characters at a higher speed (say 10 wpm) while the character spacing is slower (around 5 or 8 wpm). This allows a student to learn to recognise the pattern of the incoming characters at a more realistic speed while still allowing enough time to think between characters. The farnsworth setting is displayed as Fx where x is the wpm spacing between characters. Values are: FO (Off), F5 (5 wpm spacing) or F8 (8 wpm spacing).

When code with farnsworth timing is received on the Morse Decoder, the spaces between each character are incorrectly decoded as word spaces because the farnsworth timing makes them appear much longer that expected. This creates unwanted spaces on the display which makes the text more difficult to read. Pressing the Farnsworth switch adjusts the timing of the character spaces to be more inline with the expected timing. This removes the unwanted spaces making the text more readable on the display.

The WPM=xx value represents the calculated speed of the incoming Morse code in words per minute. It is calculated based on the measured timing of the incoming characters. In fact the software initially tracks the length of the dah’s, so the more dahs you receive at the beginning of the message, the sooner it locks onto the speed.

The audio input can be fed from any suitable audio output source (speaker, aux or headphone socket) on your radio. Alternatively you could connect a microphone with a pre-amplifier to the input to ‘hear’ Morse from virtually any nearby source.

In normal use, connect the speaker output from your HF radio or Morse code source to the input socket on the decoder. Adjust the volume for a normal listening level. Locate a Morse code signal and tune the radio so the Morse produces a comfortable audio tone. Most people to prefer a tone between 500Hz and 1 kHz.

Now press the SWEEP button. The unit will sweep the VCO frequency while monitoring the output from the LM567 and ‘Sweep Up’ / ‘Sweep Down’ will be displayed. When a tone is found, a series of dots is displayed as the unit stores values. After a couple of passes the program will use these values to determine the correct tuning point for the input tone and the display will return to normal with the value displayed as T=xxx (where xxx is the tuning value).

The default value is 201 which matches the side tone of my radio (615 Hz). To change the preset value to match your radio or your keyer’s side tone, connect the decoder to your radio/keyer and send some Morse while using the sweep function. The unit should lock to the frequency of your radio’s side tone. Make a note of the ‘T’ value on the display, then edit the following line within the software to change ‘201’ to your preferred value.

Line 84: int ToneSet = 201;		// A value bumped up or down by the Sweep function

After making the change, write the updated code to your Arduino through the USB port. When the unit restarts, the new value should be displayed. The unit will now automatically be tuned to your radio’s side tone at start up.

If you have any issues communicating with your Arduino Nano using the Arduino IDE, take a look at the Arduino tips section of my website for ideas on using the Arduino modules I recommend for my projects. Arduino modules are manufactured by wide range of companies and compatibility varies somewhat. Different manufacturers use different chips resulting in incompatibilities with USB drivers and IDE board types. Whatever the problem there is usually a simple solution available. If the tips on my website doesn’t solve them a google search will usually find a solution.

Parts List

Arduino Nano . . . . . . . . . . . . . . . 1 . . . . Nano . . . . . . . . . . . . Banggood (see link)
LCD 20 x 4 . . . . . . . . . . . . . . . . . . 1 . . . . LCD2004A . . . . . . . . eBay (see link)
LM567N . . . . . . . . . . . . . . . . . . . . 1 . . . . U1 . . . . . . . . . . . . . . . Jaycar
MPC41010 . . . . . . . . . . . . . . . . . . 1 . . . . U2 . . . . . . . . . . . . . . . RS Components
3.5mm Jack . . . . . . . . . . . . . . . . . 1 . . . . J1 . . . . . . . . . . . . . . . . Jaycar (PS0132)
2uF tantalum Capacitor . . . . . . 1 . . . . C1 . . . . . . . . . . . . . . . Jaycar
220nF Capacitor . . . . . . . . . . . . . 2 . . . . C2, C4 . . . . . . . . . . . . Jaycar
100nF Capacitor . . . . . . . . . . . . . 1 . . . . C3 . . . . . . . . . . . . . . . Jaycar
Red LED . . . . . . . . . . . . . . . . . . . . 1 . . . . LED . . . . . . . . . . . . . . Jaycar
220R Resistor . . . . . . . . . . . . . . . 1 . . . . R1 . . . . . . . . . . . . . . . . Jaycar
150R Resistor . . . . . . . . . . . . . . . 1 . . . . R2 . . . . . . . . . . . . . . . . Jaycar
Momentary Switch . . . . . . . . . . 3 . . . . SW1, SW2, SW3 . . . .Jaycar
Jiffy Box 130 x 68 x 44 mm . . . . 1 . . . . . . . . . . . . . . .. . . . . . . Jaycar (HB6023)


Arduino Nano v3 with ATmega328P:

LCD 20 x 4:×4-Blue-HD44780-Character-LCD-IIC-I2C-Serial-Interface-Module-for-Arduino/323987843312?hash=item4b6f2e28f0:g:WvIAAOSwPcVVyGzs&frcectupt=true

Prototyping PCBs:

Wire-wrap Wire:

Arduino IDE software:

VK2IDL Morse Decoder:

I2C Bus Address Scanner:

LCD Hardware Library for the Arduino IDE: