Project tutorial
Morse Keyboard

Morse Keyboard © GPL3+

A novel input device implemented with a binary tree.

  • 1 comment
  • 3 respects

Components and supplies

Resistor 82K
Reistor 18K
Mfr 25frf52 1k sml
Resistor 1k ohm
Capacitor 1uf Non-Electrolytic
Panasonic eca1hm2r2
Capacitor 10 µF
Kemet c320c104k5r5ta image
Capacitor 100 nF
74HCT14 (Hex Schmitt trigger NOT)
Pushbutton 6mm
Adafruit industries ada239 image 75px
Solderless Breadboard Full Size
Breadboard Mini Modular 170 tiepoints
11026 02
Jumper wires (generic)
Ph a000053 iso (1) pnkpri8a6q
Arduino Micro

Apps and online services

About this project


Some years ago I saw a neat little device(1) which used 3 keys (dot, space, dash) to record Morse code onto tape for high speed transmission; I was quite taken by the idea of using this as a computer keyboard but, at the time, had no idea how to do the hardware or software.

The hardware problem was solved by the advent of chips with built in USB human interface device (HID) support.

The software problem was solved when I noticed the similarity between a binary tree and a Morse code dichotomic search table.

The dichotomic search table is one way of learning Morse, part of such a table is shown in Figure 1. You start with either a dot or dash and keep adding until you have spelt out the letter you want. For example, if you want the letter a, you send a dot then a dash.

Figure 2 shows a binary tree, it looks, structurally, remarkably similar to our dichotomic search table.

Binary tree

A binary tree is implemented as an array; we ignore array position 0 and use the numbers on each node as the index for the data (Figure 3).

We can traverse the indexes of a binary tree using simple math either forward, as in our case, or backwards.

  • To traverse forward to a left hand node we multiply the current index by 2.
  • To traverse forward to a right hand node we multiply the current index by 2 and then add 1.

So my thinking was that I copy the dichotomic search table into the binary tree as its data then use each press of a dot or dash button to advance through the tree index numbers, left for dot, right for dash and when the space button is pressed send the appropriate character out via the USB port.

Additional detail:

We make node 0 a null value, node 1 the space character and start filling in the letters from node 2 (Figure 4).

We must also add in null values at the positions where there are no letters; you cannot compact a binary tree by removing the empty spaces and still have it work correctly.

I added 2 extra buttons to the design to directly output the backspace and return characters.


We should not exceed the array limit.

Design decision:

If a button push would take us over the array limit we print out the character at the last legal array position.

The circuit:

5 switches with capacitor resistor debounce circuit feeding to a Schmitt trigger NOT gate of a 74HCT14 chip.

Each gate output is connected to an Arduino external interrupt pin.

Starting from the right the buttons are space/enter, dot, dash, backspace and return.

The software:


  • We set up the required port pins as input and attach the interrupt handlers.


Check do_new_line flag, if true

  • Send return character
  • Reset do_new_line flag to false

Check do_bk_space flag, if true

  • Send delete character
  • Reset do_bk_space flag to false

Check do_character flag, if true

  • Send character at the current character array index
  • Reset character array index to 1
  • Reset do_character flag to false

Check increment_dot flag, if true

  • Compute and check the next array position against the array limit, if we exceed the limit set do_character flag to print the last legal character else update the character array index.
  • Either way reset increment_dot flag to false

Check increment_dash flag, if true

  • Compute and check the next array position against the array limit, if we exceed the limit set do_character flag to print the last legal character else update the character array index.
  • Either way reset increment_dash flag to false


An interrupt occurs each time a button is pressed, there is a separate interrupt service routine for each button which sets a flag for the loop code to recognize then exits.


I have tried to encode the special characters into the array but I have had no success outputting them. I did read a comment on the Arduino help pages “Note: Not every possible ASCII character, particularly the non-printing ones, can be sent with the Keyboard library.”(3)

I initially failed to get the debounce circuit working with the stated resistor, capacitor values because I was using the 74LS14 version of the Schmitt NOT gate chip.

The 74HCT14 chip could support 6 buttons but the Atmel 32U4 chip will only support 5 external interrupts (these are easier to code up than the pin change interrupt).

Mark 2 version:

I have subsequently redesigned this project using a "Pro Micro" board. I eliminated the debounce hardware doing it with software instead and designed and built a small circuit board for the project. I also added in keyboard modifiers such as shift and incorporated some LED indicators. (I used 5 Volt LED's, so no resistors required)

The project, including PCB and code files can be found at:


(1) I later found that this device is a US Dot-dash coder (CO-3B, MX-4495). Source - (retrieved 27/Feb/2017)

(2) Source - (retrieved 27/Feb/-2017)

(3) Source – (retrieved 30/May/2017)


Morse keyboard codeC/C++
#include "Keyboard.h"
//left handed -- checked
const int delete_buttonPin = 0;          // input pin for delete pushbutton
const int dash_buttonPin = 3;            // input pin for dash pushbutton
const int dot_buttonPin = 2;             // input pin for dot pushbutton
const int space_buttonPin = 7;           // input pin for space pushbutton
const int new_line_buttonPin = 1;          // input pin for new line pushbutton

//right handed
const int delete_buttonPin = 2;          // input pin for delete pushbutton
const int dash_buttonPin = 3;            // input pin for dash pushbutton
const int dot_buttonPin = 0;             // input pin for dot pushbutton
const int space_buttonPin = 1;           // input pin for space pushbutton
const int new_line_buttonPin=7 ;          // input pin for new line pushbutton

volatile static bool do_new_line=false;
volatile static bool do_bk_space=false;
volatile static bool do_character=false;
volatile static bool increment_dot=false;
volatile static bool increment_dash=false;

const unsigned char characters_array[]={
0x00,' ',//positions 0 not used position 1 returns space character
0x00,0x00,0x00,0x00,'$',0x00,0x00,0x00,0x00,0x00,0x00,0x00,'?','_',0x00,0x00,0x00,0x00,'"',0x00,0x00,'.',0x00,0x00,0x00,0x00,'@',0x00,0x00,0x00,39,0x00,//64 part 1
0x00,'-',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,';','!',0x00,')',0x00,0x00,0x00,0x00,0x00,',',0x00,0x00,0x00,0x00,':',0x00,0x00,0x00,0x00,0x00,0x00,0x00,//64 part 2
const int characters_array_limit=127;//128 characters so 0-127

void setup() {
// make the button pins input:
pinMode(delete_buttonPin, INPUT);
pinMode(dash_buttonPin, INPUT);
pinMode(dot_buttonPin, INPUT);
pinMode(space_buttonPin, INPUT);
//assign interrupt handlers
attachInterrupt(digitalPinToInterrupt(delete_buttonPin), bk_space,RISING );
attachInterrupt(digitalPinToInterrupt(dash_buttonPin), dash, RISING);
attachInterrupt(digitalPinToInterrupt(dot_buttonPin), dot, RISING);
attachInterrupt(digitalPinToInterrupt(space_buttonPin), space, RISING);
attachInterrupt(digitalPinToInterrupt(new_line_buttonPin), new_line, RISING);        
// initialize control over the keyboard:

void loop() {

static int characters_array_index=1;

if (do_new_line){Keyboard.write('\n');do_new_line=false;}//new line character

if (do_bk_space){Keyboard.write('\b');do_bk_space=false;}//backspace character (for deletion)

if (do_character){Keyboard.write((unsigned char)characters_array[characters_array_index]);characters_array_index=1;do_character=false; }

if(increment_dot){if ((characters_array_index*2)>characters_array_limit){increment_dot=false;do_character=true;} 
                        else {characters_array_index=characters_array_index*2;increment_dot=false;} }

if(increment_dash){if (((characters_array_index*2)+1)>characters_array_limit){increment_dash=false;do_character=true;} 
                        else {characters_array_index=(characters_array_index*2)+1;increment_dash=false;} }

void dot(void) {increment_dot=true;}
void dash(void) {increment_dash=true;}
void space(void) {do_character=true;}
void bk_space(void) {do_bk_space=true;}
void new_line(void) {do_new_line=true;}


Breadboard layout morse keyboard
Morse keypad 5 button bb vmmhjm3uws
Debounce circuit schematic


Similar projects you might like

Ternary Chord Keyboard

Project tutorial by glennedi

  • 10 respects

Keyboard Melodies

Project tutorial by Ava Baker -21 and Natalie Clark -20

  • 13 respects

Wireless Keyboard from TV Remote

Project tutorial by Amal Mathew

  • 17 respects

A Pocket-Sized Touch Keyboard

Project tutorial by Amal Mathew

  • 20 respects

How to Make a Customizable Punchable Keyboard Button

Project tutorial by Amal Mathew

  • 9 respects

Morse Code Transmitter - Light Signal

Project showcase by Alireza Karkon

  • 1 comment
  • 7 respects
Add projectSign up / Login