robotmotion.gr
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.

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.

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.

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).


The arduino firmware is quite short in length and I believe an easy one to follow.
/* 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.
1/12/11
Iambic keyer with Arduino, in 5 minutes.