Close

State (Machine) of the Union...

A project log for 1Keyer

An iambic paddle controller for sending Morse code.

mark-vandewetteringMark VandeWettering 12/08/2016 at 19:520 Comments

I thought I'd write down these notes quickly do demonstrate how the keyer works in an abstract sense, minus any details of implementation. I'm going to ignore the serial interface aspect of it for now, and concentrate just on how the part that reads the state of the iambic paddles and schedules the dits and dahs will work.

It will be implemented as a Finite State Machine. The idea is very simple. The machine has an internal state (which you can think of as just being an identifier) and depending on particular conditions or events. When it is in a particular state, it might do some action, then attempt to read an event or condition. Depending on what state you are in, and what condition you read, you may either remain in the current state (and do the action again and then read actions again...) or you might hop to a different state.

If we represent states as circles and conditions as labelled arcs, you can map out how the keyer will work like this:

This might be a little bit confusing, so I'll explain. States are represented by circles, with names in all capital letters. Conditions are labels on arcs, and if the condition is satisfied, then the machine moves into the next state. For instance, we begin in the START state. Basically, this state is just waiting for something to happen. If we see a dit condition satisfied (somebody closed the dit switch) then we move into the state DIT. Similarly, if the dah condition is satisfied, then we move to the DAH state. If neither of those conditions is satisfied, we simply remain in the START state by taking the default arc.

So, what happens when we are in the DIT state? First, we send a dit! That basically works by setting a particular pin high for a given amount of time and then setting it low for a given time. You might implement this in Arduino-ish code like this:

void
do_dit()
{
    digitalWrite(output_pin, HIGH) ;
    delay(ditlen) ;
    digitalWrite(output_pin, LOW) ;
    delay(ditlen) ;
}
We will ignore how we compute ditlen for now, let's just say we know how to compute ditlen for a given desired speed. While we are at it, we could go ahead and show you how we do dahs:
void
do_dah() // insert joke about Camptown ladies here...
{
    digitalWrite(output_pin, HIGH) ;
    delay(3*ditlen) ;
    digitalWrite(output_pin, LOW) ;
    delay(ditlen) ;
}
Same code, except that we hold the key down (write a high value to the output pin) for three times as long.

So, when we are in state DIT, we call do_dit(), and then scan to see what conditions are satisfied. Perhaps we are continuing to hold down the dit switch closed. In that case, we can just stay in our current state. On the next iteration, we'll resend a dit by calling do_dit(), and keep doing that until we stop holding that key down. If however we hold dah switch close, we can skip over to sending by entering the DAH state. If after sending a dit we don't see either key on, then we are done with the character, and will go to the ECHAR state.

There is one subtlety. We want the situation to be such that if we hold both switches closed, we alternate with dits and dahs. We can do this by checking this condition first: if you re in the DIT state, first check to see if the dah switch is closed. If it is, then go to DAH. It doesn't matter if dit continues to be closed. Similarly, if you are in the DAH state, first check to see if the dit switch is closed, and switch to DIT if is.

Let's walk through how the character C might be sent. C is dah dit dah dit.

And that's pretty much it! The rest is just implementation details, which will be part of my first real code posting coming soon. Stay tuned!

Discussions