An Arduino Morse Reader
An Arduino Morse Reader
An Arduino Morse Reader
• E-mail: [email protected]
W An Arduino
elcome to my second
Arduino project,
a Morse reader I
call ARD071, Fig. 1.
Morse Reader
Writing this, I’m glad
I developed my Morse sender (ARD070,
PW November) first because this is much
more complicated. A Morse reader has to
process an audio stream first into dots and
dashes, then group them into single Morse
characters, then translate those into text
and display the output − all in real time! Tony Jones G7ETW follows up his Morse Tutor project
To understand this, take a look at Fig.
2. Morse is binary; a low-to-high change (November 2017) with an Arduino-based Morse reader.
means a character element (a dot or a
dash) has just started, and the converse
signifies one has finished. By timing the
states, character elements can be identi-
fied. An Arduino read takes about 1ms,
and at 20 Words per Minute (WPM) a dot
lasts 60ms, so this is all very doable. The
detailed logic is explained in the Decoding
sidebar.
I got ARD071 working using a digital
data stream first. I connected ARD070’s
pin 13 − the LED flasher output − to
ARD071’s digital pin 3. This worked per-
fectly and allowed me to refine the detec-
tion, decoding and display logic with solid
binary input. To see one Arduino sending
random text and another one displaying it
a second later (look for the ‘HHQ’ series in
Fig. 1) was quite spooky, actually. Why the
delay? ARD070 displays text in five-char-
acter groups before it sends it whereas
ARD071 has to wait until each character is
finished before decoding can begin.
A digital-feed only Morse reader was
not the objective, so I reconfigured for an Fig. 1: The completed project in breadboard form.
analogue waveform.
To test, I used ARD070 again, taking
the pulse-width modulated (PWM) audio Dash Dot Dot Dot
output (pin 11) to ARD071’s pin A0 and
found that incoming Morse, regardless of
Dot gap
I look forward to doing more testing. go back to using a digital input. But that is Conclusion
another project. That’s it for ARD071. It works really well
The Hardware Isolation for such simple code and is a joy to watch
I used an Arduino Mega2560 board this ARD071 has to be connected to the audio- running. Since starting in Arduino develop-
time, again a genuine one. This board has out socket of what’s driving it. It would be ment, I have learned a lot and I have other
four times as much memory as an Uno better, for both pieces of kit, if they were projects in mind, for example, a laser-op-
and over twice as many pins, but my main isolated. Opto-isolators using infra-red erated remote antenna switcher. It is great
reason for using it was simply to show LEDs and phototransistors are available fun combining IT and amateur radio in this
another Arduino variant. An Uno should be and would provide valuable protection. way and I urge you to have a go.
fine for this project. Slave Audio Out
A sixteen (char) by two (row) display If ARD071 is plugged into a headphone
was adequate for ARD070, which only had socket, there is no sound to hear. It would
to display five characters at a time. For be easy to put a sounder in, driven off a Decoding
ARD071 this would have been very limit- PWM output pin. There are even speech Look at point A on Fig. 2. We are at
ing, so I used a Sainsmart 20 character by boards for Arduino, so ARD071 could the end of a character-to-character
four row display I bought on Amazon for speak the message out loud, albeit as a three dot gap. The input has gone
£11.98. This is an I2C type display - see string of letters and numbers. To break it high, so a new character has begun.
Sidebar 3. into words − now that is a challenge! The gone-high time is stored and a
See Fig. 4 for a schematic. The build is Better Character Decoding series of reads return high. No action
very easy. There are three sync-indication Decoding at the moment is done by a is necessary for this character yet but
LEDs. LED1 shows the dots and dashes sequential array search. There is a ‘binary the last character read is stored as
coming in and LED3 echoes them when tree’ method that decodes characters in dots and dashes and still needs to be
the code has ‘locked on’. If LED2 is used, flight, for example, if two dots have al- decoded. For this explanation, let’s
it will be much fainter. ready been detected and the next element ignore that.
is another dot, then the only possibilities At point D the input has flipped
The Code are S, H, V, 4 and 5. This should be faster and the gone-low time is stored.
ARD071 V1.4 uses more advanced C syn- but would be quite complex to code. The time the waveform was high is
tax than ARD070 v3.5 (the version printed ARD071 can only handle A-Z and 0-9. calculated and by comparing this with
in PW) did, and features character pointers Adding punctuation and other procedural a dot’s length we know we just had a
and arrays. Pointers in C are generally characters would also be useful. dash. This becomes the first stored
used to pass values to and from functions Combined Single-Arduino Sender and element for this character.
and while this may seem more complex, it Reader Reads continue, returning lows.
actually simplifies the code. See Sidebar 4 The idea of a combined sender and reader We’re in a gap, either between char-
for a brief explanation. was suggested by a PW reader who acter elements or between charac-
e-mailed me. My thanks to all those who ters.
Improvements did contact me after that earlier article; it At point E the waveform goes
The following are possible areas for im- is always nice to get reader feedback and high again. The low gap’s duration is
provement. that particular idea is an excellent one. The calculated and the code finds it was
Ambient Sound Input data structures and variables are compat- a dot. We’re still in this character and
ARD071 does not take a microphone in- ible and some of the code such as the another element is starting.
put. I did try to get this working, using Ar- display logic could be common. The cycle repeats and as we go
duino electret microphone boards and my A rotary encoder would be needed for through F, G and H we piece together
own LM358 microphone preamplifiers. But controls (to free up analogue pins A4 and dash dot dot.
electret microphones are just too sensitive A5 - see Sidebar 3 again) and that would We’re at point K now. This time the
and even in a quiet room the background make the final product smaller and more low gap was three dots long so K is
noise pickup is too much for the beeps to modern. the start of a new character. The dash
stand out enough. A custom board would be nice too. dot dot we have stored is decoded
I think the answer is to make an exter- Sometimes I feel I‘ve unleashed a into N and displayed.
nal CW digitiser, which would allow me to monster...
f = 1 / (2 ×π × R × C) C1
0V
1µ All LEDs are 5V types (with internal resistor)
R is 2.2kΩ and C is 1µF, giving a LED1 LED2 LED3 0V All are optional, though LED3 is highly recommended
cut-off frequency of about 70Hz. This
was a pretty arbitrary decision − it just
needed to be low compared to the Fig. 4: Overall schematic, with Arduino and display.
PWM frequency (around 700Hz).
See Useful Links for an online RC Useful Links:
filter calculator. Lowpass Filter calculator: C-pointers: Dan Gookin’s Beginning
https://tinyurl.com/ya2t7auf Programming with C, chapters 18 and 19,
I2C: https://tinyurl.com/y8j6uwv9 I found very good. If you want more of a
LiquidCrystal_I2C.h library: reference (no pun intended), there is:
https://tinyurl.com/p2uzjw8 http://boredzo.org/pointers
I2C LCD Displays
I2C, short for ‘Inter-Integrated Circuit’
was developed by Philips in the 1970s C Pointers p1 = &x
as a way to network boards under Explaining pointers is not easy. I shall do p2 = &y
central control, each of them able to my best. This sets p1 to the location of x and
send and receive data via a ‘bus’. Every variable has its own memory p2 to y’s location.
An I2C display connects to Arduino location. In C parlance, p1 ‘points to’ x.
using four standard connections: 5V, Say there are three integer variables p1 has a value of 100.
ground, SDA (data) and SCL (clock). x, y and z at locations 100, 200 and 300. *p1 has a value of 10.
On an Arduino Uno, SDA and SCL Say there are two integer pointer Do not read on until that makes
also connect to analogue pins A4 and variables p1 and p2. (Tutorials often sense. Conceptually, that is all there is
A5, as a PW reader painfully dis- call these px and py, giving the impres- to pointers.
covered when using one to build his sion that the variable names matter. z = *p1
ARD070. They don’t. Types do but that’s another This sets z to 10.
Boards connected to an I2C bus minefield.) *p1 = *p2
system have unique addresses. My An integer pointer is a pointer that This makes x = y
LCD display’s address is hex 27 − it holds the address of another integer. *p2 = z
was documented in the Amazon list- There are two pointer ‘operators’, This sets y to z, which is what x had
ing! This seems to be standard but it’s which allow programmers to do things before we started. After these instruc-
wise find this out when purchasing a with pointers: tions have taken place x, y and z have
display. • The ampersand ‘address of’ operator values of 20, 10 and 10. Precisely this
Please note the inclusion of the gives access to a variable’s location and code can be found in sort routines.
Wire.h and LiquidCrystal_I2c.h librar- is how pointers are setup. This could have been done far more
ies, which provide support for the • The asterisk ‘value at address’ opera- simply without pointers, of course. But
display. tor gives access to pointed-to variable’s moving data around takes process-
Wire.h is a standard Arduino value and can be used like peek and ing time. Three variables’ values have
library but LiquidCrystal_I2C.h is not. poke in BASIC. changed but only one actual move-
I learned of this by reading the Ama- All clear so far? ment of data − the setting of z − took
zon reviews of the display I bought. Here are some pointers in action. place. The other changes were achieved
Previous purchasers recommended a integers x, y and z exist with values by swapping pointers. If z had had a
library made available by F Malpar- of 10, 20 and 30. pointer too, all of this could have taken
tida and that’s what I used. Two pointers are declared. place with no data moving at all, which
Please look in Useful Links for Int * p1 is why so many C string functions use
more information on I2C and Liquid- Int * p2 pointers all the time.
Crystal_I2C.h (where to get it and how Their contents are indeterminate until Please see Useful Links for a much
to install it). they are initialised. better introduction to use of C pointers.
Sketch Code: Here is the code. It is also available to download from my website.