Wren'sTech

Projects and Technical Ramblings

Morse Code Input On An AVR

Leave a comment

After doing 11 12 hour night shifts back to back, I needed to stay up for 12 hours to get myself back onto a day cycle. What do you do during that time? Science! Well, nothing really scientific going on here, but at least vaguely technical.

My “neat little demo” was hampered by the fact that I am truly terrible at Morse code. The technical side of this is fairly interesting though – here’s the source code:

char letters[] =
{
  0,  0,  'E',  'T',  'I',  'A',  'N',  'M',  'S',  'U',  'R',  'W',  'D',  'K',  'G',  'O',  'H',  'V',  'F',  '-',  'L',
  '#',  'P',  'J',  'B',  'X',  'C',  'Y',  'Z',  'Q',  '.',  '-',  '5',  '4',  '3',  '2',  '1',  '6',  '7',  '8',  '9',  '0'
};

#define COUNTER_STOPPED 0x00
#define COUNTER_RUNNING 0x05 // ck / 1024 => 64us per tick

// Letter format: all zeroes, then a 1 to mark the start of the letter, then 0 for dot and 1 for dash
// for the remainder of the letter.
void printletter(uint8_t letter)
{
  uint8_t count = 8;
  if (!letter)
    return;
  Serial.print(letters[letter]);
  while(!(letter & 0x80))
  {
    letter <<= 1;
    --count;
  }
  letter <<= 1;

  while (--count)
  {
    if (letter & 0x80)
      Serial.print("-");
    else
      Serial.print(".");
    letter <<= 1;
  }
  Serial.print(" ");
}

void setup()
{
  Serial.begin(9600);

  DDRB = 0x08;
  PORTB = 0x10;
  TCCR2A = 0x41;  // Toggle OC2A (PB3), don't touch OC2B, CTC mode
  TCCR2B = 0x06;  // CTC, ck/256, WGM22 = 1 (for toggle).
  OCR2A = 61;
  TCNT2 = 0;
  ASSR = 0;

  TCCR1A = 0x00;  // Normal operation, no wavegen
  TCCR1B = COUNTER_STOPPED;
}

void loop()
{
  uint16_t dotlength = 1500;
  uint16_t lastspace = 0;
  uint8_t currentletter = 0x01;
  while (true)
  {
    TCNT1 = 0;
    TCCR1B = COUNTER_RUNNING;
    bool newword = false;
    while (PINB & 0x10)
    {
      lastspace = TCNT1;
      if (lastspace > dotlength * 7)
      {
        newword = true;
        break;
      }
    }

    if (lastspace > dotlength * 5 / 2)
    {
      printletter(currentletter);
      currentletter = 0x01;
      if (newword)
      {
        Serial.println(" ");
        while (PINB & 0x10);
      }
    }
    TCNT1 = 0;
    TCCR1B = COUNTER_RUNNING;
    TCCR2B |= 0x08;
    while (!(PINB & 0x10));
    TCCR1B = COUNTER_STOPPED;
    TCCR2B &= ~0x08;
    //Serial.println(TCNT1);
    if (TCNT1 < dotlength * 5 / 3)  // dot
    {
      currentletter = currentletter &lt;&lt; 1;
      dotlength = (dotlength * 2 + TCNT1) / 3;
    }
    else                        // dash
    {
      currentletter = (currentletter << 1) | 0x01;
      dotlength = (dotlength * 2 + TCNT1 / 3) / 3;
    }
  }
}

It does unfortunately show all the hallmarks of being written at a time when I should really have been asleep. However, it does function rather well! My morse code ability is regrettably not up to scratch.

One feature to note is that the speed (dot length) is adaptive – the faster you enter code, the faster it will expect the code to be. Using the AVR’s TIMER1 hardware, I can obtain a time resolution of 64 microseconds, meaning the AVR can input Morse code pretty damn fast. Think >100 characters per second, or Marty McFly on a hoverboard sort of fast.

When this baby hits 88 CPS, you’re going to see some serious shit.

TIMER2 in CTC (Clear Timer on Compare match) mode generates the 1kHz beep tone without CPU supervision, so all the CPU does is sit in a loop and wait for the button input to change.

My real reason for doing this is to learn how to use the timer/counter hardware – it should be handy for carrying out capacitance and frequency measurements on the multimeter.

The character encoding is fairly neat – taking advantage of the fact that morse code is essentially a binary tree structure, symbols can be packed into a rather compact array. I’m glad that I typed out that array correctly the first time, because a mistake in that would have been a pain.

iTead Studio tells me that the PCBs have been shipped, so hopefully I can show an assembled multimeter within the next couple of weeks!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s