ARDUINO ICOM Auto Keyer

Project presentation

Most ICOM transceivers have a voice / message memory  on board, able to 'play' 1 ... 4 pre defined messages - very handy to run contests or pile-ups !   The playback of the messages can be initiated by depressing a multi function key on the front panel (however in this mode you are losing the scope view - this is a disadvantage) , or by the F1 ... F4 keys on a USB keyboard connected (some additional clutter on the desktop) , or by providing a small external homebrew keypad with 4 pushbuttons - connected to the MIC key.

Here is the schematic diagram of such keypad :

However, there is no possibility to provide automatic repetition of messages - and this is a pity indeed ...

The project hereby presented will ensure the interactive control of playback of the 4 messages, either in 'single-shot' mode or with a possibility to have them automatically repeated after an adjustable pause in between.

A small ARDUINO controller will handle all the logic, and can be integrated in the external key pad box;  which - if fitted with a mating MIC plug, can simply be inserted in-line with the microphone!

The total project cost is estimated around 20, EUR, and probably the most expensive single component will be microphone plug !

ARDUINO ICOM auto keyer ON7EQ

Functional description

Schematic diagram

The project was realized with an ARDUINO Nano board, offering the advantage of being flashable by USB port. But smaller versions can be used if desired !  Click on the image below to download the full sized digram. During realization, take care  not short-circuiting the +8v supply or the voltage regulator in your transceiver will be SK !

Click to download full size PDF

Arduino sketch

Below is the sketch  or download it here.   It was compiled with IDE version 1.0.6 - IMPORTANT : Should you get errors when compiling, use the same version of IDE !  You still can download previous versions from ARDUINO website .  

IMPORTANT: Please note that the software & device concept is presented 'as is' with no guarantees whatsoever and can be used free of license cost by individual  HAMs, but not  used for any commercial purpose, as the intellectual property remains entirely by the author.  




///////////////////////////////////////////////////////
//                                                   //
//                 ICOM AUTO KEYER                   //
//                by ON7EQ 03/2016                   //
//                                                   //
///////////////////////////////////////////////////////

// compiled with IDE v 1.0.6


#define input1  (2)                   // pushbutton 1 input pin  (pushbutton depressed = LOW)
#define input2  (3)                   // pushbutton 2 input pin
#define input3  (4)                   // pushbutton 3 input pin
#define input4  (5)                   // pushbutton 4 input pin


#define output1  (6)                   // output 1 pin - to open collector NPN - output active = HIGH
#define output2  (7)                   // output 2 pin - to open collector NPN 
#define output3  (8)                   // output 3 pin - to open collector NPN 
#define output4  (9)                   // output 4 pin - to open collector NPN 

#define LED_output  (13)               // output pin - to LED - if only one LED

#define LED_output1 (A2)               // output pin - to LED corresponding with button 1 (optional)
#define LED_output2 (A3)               // output pin - to LED corresponding with button 2 (optional)
#define LED_output3 (A4)               // output pin - to LED corresponding with button 3 (optional)
#define LED_output4 (A5)               // output pin - to LED corresponding with button 4 (optional)
 

#define PTT_read      (A1)             // input for reading PTT (to define RX/TX status)

#define Delay_pot_pin  (A0)             // input for reading potentiometer for delay

byte mode = 0;
byte button = 0;
byte longpress = 0;
byte OneShot = 0;                       // one shot flag
byte Repeat = 0;
byte arm = 0;                          // arm for repress detect in repeat mode
byte stop_by_PTT = 0;
byte EOM_flag = 0;                     // end of message flag

byte button_pressed = 0;

int unsigned long RX_time = 0;
int unsigned long RepeatInterval = 0;
int unsigned long Button_time_pressed = 0;
int unsigned long EOM_time = 0;


////////////////////////////////////////////////////////////
////////////////////   S E T U P  //////////////////////////
////////////////////////////////////////////////////////////


void setup() {

  pinMode (input1, INPUT);
  pinMode (input2, INPUT);
  pinMode (input3, INPUT);
  pinMode (input4, INPUT);

  //Activate pull-ups
  digitalWrite(input1, HIGH);
  digitalWrite(input2, HIGH);
  digitalWrite(input3, HIGH);
  digitalWrite(input4, HIGH);
  
  digitalWrite(PTT_read, HIGH);

  pinMode (output1, OUTPUT);
  pinMode (output2, OUTPUT);
  pinMode (output3, OUTPUT);
  pinMode (output4, OUTPUT);

  digitalWrite(output1, LOW);
  digitalWrite(output2, LOW);
  digitalWrite(output3, LOW);
  digitalWrite(output4, LOW);

  pinMode (LED_output, OUTPUT);
  pinMode (LED_output1, OUTPUT);
  pinMode (LED_output2, OUTPUT);  
  pinMode (LED_output3, OUTPUT);
  pinMode (LED_output4, OUTPUT);
  
  digitalWrite(LED_output, LOW);
  digitalWrite(LED_output1, LOW);
  digitalWrite(LED_output2, LOW);
  digitalWrite(LED_output3, LOW);
  digitalWrite(LED_output4, LOW);
  
}

///////////////////////////////////////////
////////////  L   O   O  P  ///////////////
///////////////////////////////////////////


void loop() {

  if (Repeat == 0) {      // single shot mode button actions
  
  
  // check if any button depressed, and define mode
  
    if      (digitalRead(input1) == LOW) button = 1;  // any of 4 buttons pressed
    else if (digitalRead(input2) == LOW) button = 1;
    else if (digitalRead(input3) == LOW) button = 1;
    else if (digitalRead(input4) == LOW) button = 1;
    
    else    {            // no button pressed
      
               button = 0;                                       // no button pressed
               if (button_pressed == 1) button_pressed = 0;      // button was released
               OneShot = 0;                                      // be ready for new pulse
               longpress = 0;                                    // long press released
             }


  if ((button == 1) and (mode < 20)) {
    
    //  if ((button == 1)) {
    
                  delay (30);                                        //Crude debounce
                  if      (digitalRead(input1) == LOW) button = 11;  // Button 1 effectively pressed
                  else if (digitalRead(input2) == LOW) button = 12;  // Button 1 effectively pressed
                  else if (digitalRead(input3) == LOW) button = 13;  // Button 1 effectively pressed
                  else if (digitalRead(input4) == LOW) button = 14;  // Button 1 effectively pressed
                  else    {
                          button = 0;                                // it was bounce or button was released
                          button_pressed = 0;
                          longpress = 0;
                          OneShot = 0;                               // be ready for new pulse
                           }
                           
                      
                  if ((button_pressed == 0) and (button > 10) and (button < 20)) {
                          button_pressed = 1;                        //  a button was depressed !
                          Button_time_pressed = millis();            // time stamp a button pressed
                          }
                }


  if ((button_pressed == 1) and (millis() - Button_time_pressed > 300)  ) { // check if long press on button > 0.5 sec
    
              if (longpress == 0) {   // going into repeat mode
                            longpress = 1;                          // button pressed for repeat mode !
           
                            if      (digitalRead(input1) == LOW) mode = 21;  // Button 1
                            else if (digitalRead(input2) == LOW) mode = 22;  // Button 2
                            else if (digitalRead(input3) == LOW) mode = 23;  // Button 3
                            else if (digitalRead(input4) == LOW) mode = 24;  // Button 4
                            
                            digitalWrite(LED_output, HIGH);                  // Repeat mode
                            
                            RX_time = millis () + 60000;                     // set repeat timer
                            
                           }    
              
                }
 
         } // end single shot mode
 
   if (Repeat == 1) {      // repeat mode button actions
          
          // Wait for button released = arm condition !
          
            if ((digitalRead(input1) == LOW)                                // any of 4 buttons pressed ?
            or (digitalRead(input2) == LOW)
            or (digitalRead(input3) == LOW)
            or (digitalRead(input4) == LOW)) {
                             delay (0) ; // do nothing
                             }
            else (arm = 1);                                                // button released, arm for repress => force stop
         
         
         // Wait for button pressed = exit mode !
         
            if (((digitalRead(input1) == LOW)                              // any of 4 buttons pressed ?
            or   (digitalRead(input2) == LOW)
            or   (digitalRead(input3) == LOW)
            or   (digitalRead(input4) == LOW)) and (arm == 1)) {
                                           
                             arm =0;
                             mode = 99;      // Exit repeat mode
                            }
 
          } // end repeat mode button actions
 
 
 
   
  ////////////////////////////////////////////////////////////
  /////////////// Take actions according to mode   ///////////
  ////////////////////////////////////////////////////////////
  
  
  /////////////////// Single press  ////////////////

  if ((button_pressed == 1) and  (OneShot == 0) ) {

              digitalWrite(LED_output, HIGH);
             
            
              if (button == 11) {
                        digitalWrite(output1, HIGH);
                        digitalWrite(LED_output1, HIGH);
                        }
              if (button == 12) {
                        digitalWrite(output2, HIGH);
                        digitalWrite(LED_output2, HIGH);
                        }
              if (button == 13) {
                        digitalWrite(output3, HIGH);
                        digitalWrite(LED_output3, HIGH);                        
                        }
              if (button == 14) {
                        digitalWrite(output4, HIGH);
                        digitalWrite(LED_output4, HIGH);     
                        }
              delay (100);                                                    // pulse keyer
                            digitalWrite(output1, LOW);
                            digitalWrite(output2, LOW);
                            digitalWrite(output3, LOW);
                            digitalWrite(output4, LOW);
                      
                            digitalWrite(LED_output, LOW);
                            digitalWrite(LED_output1, LOW);
                            digitalWrite(LED_output2, LOW);
                            digitalWrite(LED_output3, LOW);                             
                            digitalWrite(LED_output4, LOW);            
                OneShot = 1;
                }
      
 
    
    
  ///////////////// Long press //////////////


  if ((mode > 20) and (mode < 30)) {
    
             Repeat = 1;
        
             RepeatInterval = map(analogRead(Delay_pot_pin), 0, 1023, 1000, 20000);   // 1 to 20 sec interval
             
             
          
             
        
            // Generate repeat pulse after interval, only in in RX
             
             if ((millis() - RX_time >  RepeatInterval) and (EOM_flag == 1) and (analogRead(PTT_read) > 500)) {  
                
                          RX_time = millis ();
                          EOM_flag = 0;
                          
                          if (mode == 21) digitalWrite(output1, HIGH);
                          if (mode == 22) digitalWrite(output2, HIGH);
                          if (mode == 23) digitalWrite(output3, HIGH);
                          if (mode == 24) digitalWrite(output4, HIGH);

                          digitalWrite(LED_output, LOW);
                          
                          digitalWrite(LED_output1, LOW);
                          digitalWrite(LED_output2, LOW);
                          digitalWrite(LED_output3, LOW);                             
                          digitalWrite(LED_output4, LOW);  
                          
                          delay (100);                          // Pulse output   
                          
                          digitalWrite(LED_output, HIGH);
                          
                          if (mode == 21) digitalWrite(LED_output1, HIGH);
                          if (mode == 22) digitalWrite(LED_output2, HIGH);
                          if (mode == 23) digitalWrite(LED_output3, HIGH);
                          if (mode == 24) digitalWrite(LED_output4, HIGH);
                           
                          
                          digitalWrite(output1, LOW);
                          digitalWrite(output2, LOW);
                          digitalWrite(output3, LOW);
                          digitalWrite(output4, LOW);
                          }

                          delay(50);                                     // extra delay - allow TRX to go into TX mode and bring PTT line down
                          
                    if (analogRead(PTT_read) < 500)  RX_time = millis () ;   
                                                                      
                    if ((analogRead(PTT_read) < 500) and (EOM_flag == 0))  {  // Higher than 2,5 V on PTT line = RX   //    
                          // RX_time = millis ();                          // timestamp going into RX mode. as long as in TX, RX_time is reset to millis()
                          EOM_time = millis();                          // timestamp end of message
                          }
 
             
                   if (analogRead(PTT_read) > 500) EOM_flag = 1;             // PTT line becomes HIGH, message has been played. Required to detect subsequent stop by PTT
              
                                     
           ///   STOP BY PTT during pause interval        
  
              if (((millis( )- EOM_time > 50)) and (millis() < (EOM_time + RepeatInterval - 50)) and (analogRead(PTT_read) < 500) and (arm == 1)) {  // PTT depressed during pause between messages --> stop keyer!
                           stop_by_PTT = 1;
                           arm = 0;
                           mode = 99;
                           EOM_flag = 0;
                           }         
                        
              
          } // end of repeat mode
 
 // EXIT REPEAT MODE
 
  if (mode == 99) {
 
          Repeat = 0;
          digitalWrite(LED_output,  LOW);
          digitalWrite(LED_output1, LOW);
          digitalWrite(LED_output2, LOW);
          digitalWrite(LED_output3, LOW);                             
          digitalWrite(LED_output4, LOW);  
          
          mode = 0;
          
              // check if message playing, issue a pulse to stop
              
              if ((analogRead(PTT_read) < 500) and (stop_by_PTT == 0))  {  // Yes, PTT is low, and was not forced stop by keying     
                         digitalWrite(output1, HIGH);
                          delay (100);                                    // Pulse output
                          digitalWrite(output1, LOW);    
                          }
              
              stop_by_PTT = 0;
              
              //wait till buttons released before looping again
              
              while ((digitalRead(input1) == LOW)                        // if any of 4 buttons pressed, wait till released !
              or (digitalRead(input2) == LOW)
              or (digitalRead(input3) == LOW)
              or (digitalRead(input4) == LOW)) {}
              
              delay (100);
              }

} // End of loop