Iambic keyer with Arduino, in 5 minutes.

In this small article I will present a quick and dirty hack to build an electronic CW iambic keyer in 5 minutes.  For those not familiar with the terminology, CW is a mode used by ham radio amateurs. In this mode, morse code is used to communicate.  To produce the dots and the dashes of the morse code you may use a ‘straight key’ or dual paddle keys. With the straight keys, the operator must produce all the dots and dashes by pressing the single paddle on the key.  Dual paddle keys are usually used together with keyer circuits to produce dots and dashes.  They way a dual paddle key works is simple.  One paddle produces dots (dit..dit..ditt) and the other dashes (dah..dah..dah).  In this project, touch input paddles were made to allow for fast operation of the key.

See for yourself in the quick demonstration video.

 

The keyer presented here is a generic circuit that can be used with any homebrew transceiver to operate in CW mode, for practicing the code etc.

You will need the following parts

  • 1x Arduino board. Any model will do. The application is not resource hungry
  • 1x 8 Ohm speaker for listening to the circuit’s output
  • 2x fast-on pins for PCB
  • 1x small 15x20mm piece of prototyping PCB
  • 2x 470K resistors .SMD or through-hole. It doesn’t matter

The most interesting part of the project is to build the dual paddle control.  In the images below I present my version. Feel free to improvise.  The ideal behind this control is to have 2 metal paddles, connected to 2 digital inputs on the arduino.  These paddles should also have a pull-up resistor of 470K value.  Thats it.  Thats all you need to build from the hardware design point for view.

pins

I have used a 3pin header to allow for the dual paddle to be connected to the arduino board.

The bottom side of the dual paddle control pcb is shown below.  Note the 2 SMD pullup resistors I’ve used. I decided that for my application, it was easier to use the middle pin for common pullup and the 2 adjacent pins for paddle inputs. Note also that the common pullup pin is NOT +5V. It is connected to

another IO pin which is set as output in the code, whenever it is necessary.

pins2

You may be wondering how do we detect the touch action on the paddles.  The technique is really simple.  Have a look at the schematic of the system.

keyer-schem

When the software needs to read a paddle pin, it sets the pin9 output from low to high.  The voltage on pin8 or pin10 begins to rise.  The voltage will reach the logic high level, but it will take some time, because of the relatively large pullup resistor and the given capacitance of the input pin.  If no finger is touching the input pin, the voltage will rise as fast as possible for the given circuit.  If we touch the pin, the capacitance of the input is increased and the voltage rise will be slower.  Also, the voltage level may not even reach logic high.  This trick is used to create two touch inputs.  Once the pullup pin9 is set to high, the software will wait for a fixed set of time and then it will check the levels of the input pins.  The time to wait before checking the levels is configurable in the software and I have set it to 10 microsecond at the moment.  Below you can see the waveform of a touch input, first without touching it, and then with a finger touching the metal plate. There are two peaks, as the software polls for two paddles, one after the other.  The cursors on the waveform show a fixed period of 15uS, starting after pin9 is set to high.  the highlighted value of cursor 2, shows the voltage lever on the cursor. In the first case, the level is found 3.6 which corresponds to logiv level high, and in the second case, the level is 1.2v  (Low).

osc1

osc2

The arduino firmware is quite short in length and I believe an easy one to follow.

 
 
 
 * If you are using CW and SDR (software defined radios) don’t forget to visit our my new blog and e-shop 
http://www.jel.gr/store/
 

 

/* Iambic keyer for arduino by Dimitris Sapountzakis (01/12/2011) */

#define DIT_PIN  8
#define DAH_PIN  10
#define EXC_PIN  9
#define LED      13
#define BAUD_DURATION          80              //mSec
#define INTERBAUD_DURATION     BAUD_DURATION*1
#define INTERLETTER_DURATION   BAUD_DURATION*2    //extra time after a baud
#define DIT_DURATION           BAUD_DURATION
#define DAH_DURATION           BAUD_DURATION*3
#define TOUCH_THRESHOLD        10        //how long to wait in uSec, before sampling the touch pin.

enum{
  IDLE,
  DIT,  
  DAH,
  PAUSE,
};

int dit,dah; 
int state;

void readDit()
{
  digitalWrite(EXC_PIN,HIGH);
  delayMicroseconds(TOUCH_THRESHOLD);
  if(digitalRead(DIT_PIN)) dit=0; else dit=1;
  digitalWrite(EXC_PIN,LOW);  
}

void readDah()
{
  digitalWrite(EXC_PIN,HIGH);
  delayMicroseconds(TOUCH_THRESHOLD);
  if(digitalRead(DAH_PIN)) dah=0; else dah=1;
  digitalWrite(EXC_PIN,LOW);  
}

void setup()
{
  pinMode(EXC_PIN,OUTPUT);
  digitalWrite(EXC_PIN,LOW);
  pinMode(LED,OUTPUT);
  digitalWrite(LED,LOW);   //turn off led
  state = 0;
}

//handles the output of the ciruit. if state is 1 then the contact is closed or led is turned on
void contact(unsigned char state)
{
  if(state) {
    digitalWrite(LED,HIGH);
    analogWrite(3,127);  //pin 3 drives an 8 Ohm speaker
  }
  else{
    digitalWrite(LED,LOW);  
    analogWrite(3,0);
  }
}

void loop()
{
  switch(state){
    case IDLE:
      readDit();
      if(dit) {
        state = DIT;              
      }
      else{
        delayMicroseconds(30);
        readDah();
        if(dah) {
          state = DAH;              
        }
      }      
    break;

    case DIT:
      contact(1);
      delay(DIT_DURATION);
      contact(0);
      delay(INTERBAUD_DURATION);
      //now, if dah is pressed go there, else check for dit
      readDah();
      if(dah){
        state = DAH;        
      }
      else{
        //read dit now
        readDit();
        if(dit) {
          state = DIT;              
        } 
        else {
          delay(INTERLETTER_DURATION);
          state = IDLE;
        }
      }        
    break;
   
    case DAH:
      contact(1);
      delay(DAH_DURATION);
      contact(0);
      delay(INTERBAUD_DURATION);
      //now, if dit is pressed go there, else check for dah
      readDit();
      if(dit){
        state = DIT;        
      }
      else{
        //read dit now
        readDah();
        if(dah) {
          state = DAH;              
        }
        else {
          delay(INTERLETTER_DURATION);
          state = IDLE;
        }
      }        
    break;
  }//switch   
  delay(1);
}

 
Thats all folks. I hope you enjoyed it. Until the next mini project, 73s de SV1OBT.

One thought on “Iambic keyer with Arduino, in 5 minutes.

  1. Pingback:An iambic keyer in 5 minutes | Hackaday

Leave a Reply

Your email address will not be published. Required fields are marked *