01/05/2019

KX3/KX2 Memory Commander


The KX3 has 6 memories that can be programmed with messages for CW or DATA (RTTY/PSK), and 2 voice memories for SSB/AM/FM.

For playing back one has to press 2 keys on the rig each time : first the MSG button, then followed by the number key for the message that you want to be transmitted (1-6).

I looked for a simpler way with just one key press, and at the same time I wanted to spare the KX3 buttons for wear and tear, especially since I use the memories a lot during my SOTA activations.

So it was again time for a little Arduino project ... and this is the result.

I explained the use of the KX3 serial port in previous posts (see here), so I won't go into that anymore. Only one line of code needs to be changed to make it work for the KX2 as well, see note just before the code.

The Hardware

Here is the simple circuit, and as always ... anyone can build it !
Click on the picture for a larger image.



In my junkbox, I found a rather small laptop adapter, from which I removed all the electronics, and this made a perfect case for this project. It measures 11 x 6 x 2.5 cm.
I started with the 6 buttons, which were put in a more or less straight line ...




Inside then came an Arduino Nano, a flat model Li-Ion cell from a laptop battery pack, a Chinese single cell charger and protection board, and a power switch.
A cut-off stereo audio cable was connected to the Arduino, following the circuit above.



For the charger board, search eBay or your favourite Chinese vendor for  "TP4056 Lithium Battery Charger Module", and you will quickly find offers for one, two or even five boards for a very low price.
Alternatively, you could of course power the Arduino from an external powerbank.

All items were fixed with liberal amounts of hot melt glue, and the existing holes were adapted for the Arduino mini-USB connector and the cable to the KX3, and at the other end of the box, the micro-USB connector is used for charging the battery.

It may look ugly on the inside, but when the lid is closed, it looked neat.

Now, how to remember what message is in what memory ... ?

At first, I thought to just scribble what each message was meant for on a post-it, and stick that to the box, like this.



This didn't look too neat, and I guessed that it wouldn't last long either.

So I found a "badge holder" from a conference, and cut off a piece that fitted the empty space on the box, and fixed that with superglue.
Then I made a text document with a textbox of the correct size (3.8 x 9 cm), and copied the contents of the memories from the KX3 Utility program to the textbox.
Before each SOTA trip, I use the KX3 Utility anyway, to program the rig, so I can easily copy and paste, and print a label to slide into this plastic holder.
And like this, I got a "professional" looking device ... what do you think ?



[ NOTE : I have to edit my document a little, because not all messages were lined up correctly, hi]


The Software

The code is quite simple, and the comments should help you understand how it works.

ToDo : add code for a long button push, to make the message repeating (sending the SWH command , rather than the SWT command).

Copy the following code to the Arduino IDE, save it under an appropriate name and upload to the Nano, and you're good to go !

Have fun, and I'm always interested to hear your comments on, or experiences with my projects.

73,

Luc - ON7DQ

UPDATE 7/5/2019

I changed the code, so that you have only to uncomment the line with the KX2 keycodes, and comment out the line with the KX3 keycodes.
I also removed the switch/case statement, making the code a lot shorter.

//------------------------------------------------------------------------------
// KX3(KX2) Memory Keyer Commander
// 6 buttons control the 6 transmit memories
// serial in from KX3 is pin 6 (not used now)
// serial out is pin 7 >> to TIP of ACC1 connector
//----------------------------------------------------

#include <SoftwareSerial.h>  // for comms to KX3

// map button names to pins
int m1  =   2;
int m2  =   3;
int m3  =   4;
int m4  =   5;
int m5  =   8;
int m6  =   9;

// Objects
SoftwareSerial mySerial(6, 7, true); // true = invert logic, because no MAX232 is used

// primitive variables
int key = 0;
int d = 10;
const int debounceDelay = 25; // milliseconds to wait until stable

// KX3 keycodes, comment the following line for KX2
String keyCodes[] = {"SWT19;", "SWT27;", "SWT20;", "SWT28;", "SWT21;", "SWT29;"};

//uncomment the following line for KX2
//String keyCodes[] = {"SWT19;", "SWT27;", "SWT20;", "SWT16;", "SWT35;", "SWT44;"};

void setup()
{
  Serial.begin(9600); // for debugging

  pinMode(m1, INPUT);
  digitalWrite(m1, HIGH); // turn on internal pull-up on the inputPin
  pinMode(m2, INPUT);
  digitalWrite(m2, HIGH); // turn on internal pull-up on the inputPin
  pinMode(m3, INPUT);
  digitalWrite(m3, HIGH); // turn on internal pull-up on the inputPin
  pinMode(m4, INPUT);
  digitalWrite(m4, HIGH); // turn on internal pull-up on the inputPin
  pinMode(m5, INPUT);
  digitalWrite(m5, HIGH); // turn on internal pull-up on the inputPin
  pinMode(m6, INPUT);
  digitalWrite(m6, HIGH); // turn on internal pull-up on the inputPin

  // connect to KX3
  mySerial.begin(9600);
  mySerial.println("AI0;"); // disable auto info on the KX3
  Serial.println ("Setup READY !");

}

void loop()
{
  if (debounce(m1)) key = 1;
  if (debounce(m2)) key = 2;
  if (debounce(m3)) key = 3;
  if (debounce(m4)) key = 4;
  if (debounce(m5)) key = 5;
  if (debounce(m6)) key = 6;

  if (key > 0) {
    Serial.print ("Sending Message " ); Serial.println (key);
    mySerial.println("SWT11;");          // the MSG key
    delay(d);
    mySerial.println(keyCodes[key - 1]); // the appropriate number key
  }
  key = 0 ;
  delay(50);
}

boolean debounce(int pin)
{
  boolean state;
  boolean previousState;
  previousState = digitalRead(pin); // store switch state
  for (int counter = 0; counter < debounceDelay; counter++)
  {
    delay(1); // wait for 1 millisecond
    state = digitalRead(pin); // read the pin
    if ( state != previousState)
    {
      counter = 0; // reset the counter if the state changes
      previousState = state; // and save the current state
    }
  }
  // here when the switch state has been stable longer than the debounce period
  if (state == LOW) // LOW means pressed (because pull-ups are used)
    return true;
  else
    return false;
}

1 comment:

  1. Nice project and very nice write up! There may be something similar for my KX2 in the future.

    ReplyDelete