SKETCH ARDUINO IAMBIC KEYER 4 MEMORY



/*

* Arduino iambic CW keyer v2.0

* for Ham radio usage

* Richard Chapman

* KC4IFB

* February, 2009

* Richard Chapman KC4IFB published an article in the Sep/Oct 2009 QEX magazine */ 

// ******************************************************* 

//  Iambic Morse Code Keyer Sketch with added Side-Tone 

//  added Message keyer and enable poteniometer speed control  

//  Copyright (c) Bob Anding 2017

//

//  This library is free software; you can redistribute it and/or

//  modify it under the terms of the GNU Lesser General Public

//  License as published by the Free Software Foundation; either

//  version 2.1 of the License, or (at your option) any later version.

//

//  This library is distributed in the hope that it will be useful,

//  but WITHOUT ANY WARRANTY; without even the implied warranty of

//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

//  Lesser General Public License for more details:

//

//  Free Software Foundation, Inc., 59 Temple Place, Suite 330,

//  Boston, MA  02111-1307  USA


//  PROGRAMMA MODIFICATO DA IK1RLW (ALESSANDRO): AGGIUNTE MEMORIE AL KEYER E PERFEZIONATO IL PESO MANIPOLAZIONE (GENNAIO 2021)

//****************************************************************************************************************************  

 

      // I/O pin numbers

      #define SPEEDIN 0                      // analog pin to read the speed value 

      #define DOTIN 11                     // high -> dot paddle closed

      #define DASHIN 12                    // high -> dash paddle closed 

      #define KEYOUT 13                    // drives the 2N2222 that closes the key connection

              

      // state of the machine

      #define IDLE 0   // doing nothing

      #define DASH 1   // playing a dash

      #define DOT  2   // playing a dot

      #define DELAY 3  // in the dot-length delay between two dot/dashes

        

      // Analog pin for WPM

      int   sensorPin = A0;     // set input pin for the potentiometer  

      int dotLength;   // length of a dot in milliseconds

      int dotVal;    // value of the dot paddle this sycle of main loop

      int dashVal;   // value of the dash paddle this cycle of main loop

      int oldDotVal;  // value of dot paddle last cycle 

      int oldDashVal; // value of dash paddle last dial 

      int speedDial; // raw value read from the potentiometer for speed 

      int currEltEndTime; // what time did the current element start    sounding (in milliseconds since powerup)

      int currElt; // sate of what the keyer output is sending right now

      int nextElt; // state the keyer will go into when current element ends 

      int lastElt;        // previous state of the keyer

      int time; 

      int tonePin =4;

      

      //// BLOCCO MESSAGGI

      int   msgPin2   = 2;       // messaggio 1 pin arduino 2

      int   msgPin3   = 3;       // messaggio 2 """"""""""" 3

      int   msgPin5   = 5;       // messaggio 3 """"""""""" 5

      int   msgPin6   = 6;       // messaggio 4 input"""""" 6

      char message2 []={0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x09, 0x02, 0x04, 0x0d, 0x3e, 0x12, 0x11, 0x0e, 0x0d}; //messaggio 1 = "CQ CQ CQ DE IK1LBW K"

      char message3 []={0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x09, 0x02, 0x04, 0x0d, 0x3e, 0x12, 0x11, 0x0e, 0x0d}; //messaggio 2 = "CQ CQ CQ DE IK1LBW K"

      char message5 []={0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x09, 0x02, 0x04, 0x0d, 0x3e, 0x12, 0x11, 0x0e, 0X29, 0X11}; //messaggio 3 = "VVV VVV DE IK1LBW/B"      

      char message6 []={0x15, 0x1b, 0x15, 0x1b, 0x15, 0x1b, 0x09, 0x02, 0x04, 0x0d, 0x3e, 0x12, 0x11, 0x0e, 0x0d}; //messaggio 4 = "CQ CQ CQ DE IK1LBW K"


      ///////// LISTA CARATTERI X MESSAGGIO CW.....ESPRESSI IN ESADECIMALE  //////

/**

 * LISTA CARATTER ESADECIMALI (separare ogni carattere da una virgola):    

 * 

    0x06 = a    0x11 = b   0x15 = c   0x09 = d   0x02 = e   0x14 = f   0x0b = g   0x10 = h   0x04 = i   0x1e = j   0x0d = k   0x12 = l   0x07 = m   0x05 = n   0x0f = o

    

    0x16 = p    0x1b = q   0x0a = r   0x08 = s   0x03 = t   0x0c = u   0x18 = v   0x0e = w   0x19 = x   0x1d = y   0x13 = z

    

    

    0x3e = 1    0x3c = 2   0x38 = 3   0x30 = 4   0x20 = 5   0x21 = 6   0x23 = 7   0x27 = 8   0x2f = 9   0x3f = 0


    

    

    0x29  = /   0x4c = ?    0x00 = word space    0xff = eom   0x6a = '.'   0x73 = ','   0x56 = '@'

    

   * ULTERIORI SIMBOLOGIE DI CARATTERI POSSONO ESSERE INSERITE.... 

   * 

   * 0x68 = '*'  SK    0xd1 = '^'  BK    0x2a = '+'  AR    0x31 =  '$'   BT 

 */



      

      int msglength2 = sizeof(message2) / sizeof(message2[0]); // 

      int msglength3 = sizeof(message3) / sizeof(message3[0]); //

      int msglength5 = sizeof(message5) / sizeof(message5[0]); //

      int msglength6 = sizeof(message6) / sizeof(message6[0]); //

      

      //////////////////////////////////

      void setup()                    // run once, when the sketch starts

      {

        pinMode(KEYOUT, OUTPUT);      // sets modes on the i/o pins

        pinMode(DOTIN, INPUT);         

        pinMode(DASHIN, INPUT); 

        pinMode(tonePin,OUTPUT); // AUDIO OUTPUT pin

        pinMode(13,OUTPUT); // PTT OUTPUT pin

        pinMode(msgPin2, INPUT_PULLUP); 

        pinMode(msgPin3, INPUT_PULLUP);

        pinMode(msgPin5, INPUT_PULLUP);

        pinMode(msgPin6, INPUT_PULLUP);

        // no need to set SPEED pin as input since it is analog

        digitalWrite(KEYOUT, LOW);     // initially the key is open

        

        // activate internal pullup resistors 

        digitalWrite(DOTIN,HIGH); 

        digitalWrite(DASHIN,HIGH);

        

        // initialize the state variables 

        lastElt = IDLE; 

        currElt = IDLE;

        nextElt = IDLE; 

        time = millis();

        currEltEndTime = time; 

        

      }

        

      void loop()      // run over and over again

      {

      loadWPM( (int)(analogRead(sensorPin) * (20./1023.) + .5));

      //loadWPM(15); // Fix speed at 15 WPM

      dotLength = ((analogRead(sensorPin) * (65./1023.) + 35) ); //load CW message WPM

      if ((digitalRead(msgPin2) == LOW)) Msg2(); // if message is low play message 2

      if ((digitalRead(msgPin3) == LOW)) Msg3(); // if message is low play message 3

      if ((digitalRead(msgPin5) == LOW)) Msg5(); // if message is low play message 5

      if ((digitalRead(msgPin6) == LOW)) Msg6(); // if message is low play message 6

        // get the speed (need to do this every iteration)

        //speedDial = analogRead(SPEEDIN);

        //dotLenght = 1200 / ( 5 + (speedDial/64));

        // read the paddles

        oldDotVal = dotVal; // save the old values to detect a transition, so you can debounce 

        oldDashVal = dashVal;

        dotVal = digitalRead(DOTIN);  // read the current values of the paddles

        dashVal = digitalRead(DASHIN); 

      

        // short delay for a debounce  -- turns out not needed 

        //if ((oldDotVal != dotVal) || oldDashVal != dashVal) { 

        //    delay(5); 

        //}    

      

        //get the current time

        time = millis(); 

     

        switch(currElt) {  // cases based on what current state is 

        case DASH:

            if ((dotVal == LOW) && (nextElt == IDLE)) {  // going from dash to iambic mode 

                nextElt = DOT;

            } 

            if (time >= currEltEndTime) {  // at end of current dash

                lastElt = DASH;  // a delay will follow the dash 

                currElt = DELAY; 

                currEltEndTime = time+dotLength;

            } 

            digitalWrite(KEYOUT,HIGH);  // close the keyer output while the dash is being sent

            tone(4,800);

            break;  

        case DOT: 

            if ((dashVal == LOW) && (nextElt = IDLE)) {  // going from dot to iambic mode

                nextElt = DASH;

            } 

            if (time >= currEltEndTime) {  // at end of current dot 

                lastElt = DOT;  // a delay will follow the dot 

                currElt = DELAY; 

                currEltEndTime = time+dotLength;

            } 

            digitalWrite(KEYOUT,HIGH); // close the keyer outout while the dot is being sent

            tone(4,800);

            break;  

      

        case IDLE:   // not sending, nor finishing the delay after a dot or dash

            if ((dotVal == LOW) && (dashVal == HIGH)) { // only dot paddle pressed, go to DOT mode 

                lastElt = IDLE; 

                currElt = DOT; 

                currEltEndTime = time + dotLength; 

            } else if ((dotVal == HIGH) && (dashVal == LOW)) { // only dash paddle pressed, go to DASH mode

                lastElt = IDLE; 

                currElt = DASH; 

                currEltEndTime = time + 3*dotLength;  

            } else if ((dotVal == LOW) && (dashVal == LOW) && (nextElt == IDLE)) {  

             // if both paddles hit at same time (rare, but happens)

                lastElt = IDLE; 

                currElt = DOT; 

                nextElt = DASH; 

                currEltEndTime = time + 3*dotLength; // it is an iambic keyer, not a trochaic keyer

            } 

            digitalWrite(KEYOUT,LOW);  // keyer output is open in IDLE mode

            noTone(4);

            break; 

       

        case DELAY:  // waiting for a dot-length delay after sending a dot or dash 

            if (time >= currEltEndTime) {  // check to see if there is a next element to play

                currElt = nextElt; 

                if (currElt == DOT) { 

                    currEltEndTime = time+dotLength; 

                } else if ( currElt == DASH) { 

                    currEltEndTime = time+3*dotLength;

                }

                lastElt = DELAY; 

                nextElt = IDLE;   

            }

            // during the delay, if either paddle is pressed, save it to play after the delay

            if ((lastElt == DOT) && (dashVal == LOW) && (nextElt == NULL)) { 

                nextElt = DASH;

            } else if ((lastElt == DASH) && (dotVal == LOW) &&(nextElt == NULL)) { 

                nextElt = DOT; 

            } 

            // key output is open during the delay

            digitalWrite(KEYOUT,LOW);

            noTone(4);

            break; 

        default:  

            break; 

        }

    

        

      }

void loadWPM (int wpm)

{

    dotLength  = 1200/wpm;

}


void Msg2() {


//pinMode(tonePin,OUTPUT); // AUDIO OUTPUT pin

//pinMode(13,OUTPUT); // PTT OUTPUT pin

int  element = 0; // letter of message

char temp; 

int LSB =0;

int dit = dotLength ;  // use pot to reset WPM of messgae

int dah = 3*dit;

//digitalWrite(PTT, HIGH); // turn on PTT

delay(500); // 


for (element =0; element < msglength2 ; element ++) //  read cw message

  {


 temp =  message2[element];

 

    for(int x = 0;  temp > 1 ; x++) // read cw message and check for EOM = 0xff// while(temp !=1) //  End of Character = 1 

      {

   

      LSB = bitRead(temp, 0); //LSB of temp, each loop shifts right one 

      delay(dit);//delay(dah * 1.3); //add element space

  

      if(LSB == 1)

      {

      digitalWrite(KEYOUT, HIGH); // turn on PTT

      tone(tonePin,800);//tone(A5,800,dah); //send dah, tone(pin, frequency, duration)  

      delay(dah); //delay(dah); //add element space

      noTone(tonePin);

      }

      else  

      {

        digitalWrite(KEYOUT, HIGH); // turn on PTT

        tone(tonePin,800);//tone(A5,800,dit); //send dit, tone(pin, frequency, duration) 

        delay(dit); //add element space

        noTone(tonePin);

      }

      //}

      

      temp = temp >> 1;  // shift right one, when temp = 1 quit loop

      digitalWrite(KEYOUT, LOW); // turn off PTT

      }

  delay(dah); //add dah space 

   

  }

delay(500); // wait 


}


void Msg3() {


//pinMode(tonePin,OUTPUT); // AUDIO OUTPUT pin

//pinMode(13,OUTPUT); // PTT OUTPUT pin

int  element = 0; // letter of message

char temp; 

int LSB =0;

int dit = dotLength ;  // use pot to reset WPM of messgae

int dah = 3*dit;

//digitalWrite(PTT, HIGH); // turn on PTT

delay(500); // 


for (element =0; element < msglength3 ; element ++) //  read cw message

  {


 temp =  message3[element];

 

    for(int x = 0;  temp > 1 ; x++) // read cw message and check for EOM = 0xff// while(temp !=1) //  End of Character = 1 

      {

   

      LSB = bitRead(temp, 0); //LSB of temp, each loop shifts right one 

      delay(dit);//delay(dah * 1.3); //add element space

  

      if(LSB == 1)

      {

      digitalWrite(KEYOUT, HIGH); // turn on PTT

      tone(tonePin,800);//tone(A5,800,dah); //send dah, tone(pin, frequency, duration)  

      delay(dah); //delay(dah); //add element space

      noTone(tonePin);

      }

      else  

      {

        digitalWrite(KEYOUT, HIGH); // turn on PTT

        tone(tonePin,800);//tone(A5,800,dit); //send dit, tone(pin, frequency, duration) 

        delay(dit); //add element space

        noTone(tonePin);

      }

      //}

      

      temp = temp >> 1;  // shift right one, when temp = 1 quit loop

      digitalWrite(KEYOUT, LOW); // turn off PTT

      }

  delay(dah); //add dah space 

   

  }

delay(500); // wait 


}


void Msg5() {


//pinMode(tonePin,OUTPUT); // AUDIO OUTPUT pin

//pinMode(13,OUTPUT); // PTT OUTPUT pin

int  element = 0; // letter of message

char temp; 

int LSB =0;

int dit = dotLength ;  // use pot to reset WPM of messgae

int dah = 3*dit;

//digitalWrite(PTT, HIGH); // turn on PTT

delay(500); // 


for (element =0; element < msglength5 ; element ++) //  read cw message

  {


 temp =  message5[element];

 

    for(int x = 0;  temp > 1 ; x++) // read cw message and check for EOM = 0xff// while(temp !=1) //  End of Character = 1 

      {

   

      LSB = bitRead(temp, 0); //LSB of temp, each loop shifts right one 

      delay(dit);//delay(dah * 1.3); //add element space

  

      if(LSB == 1)

      {

      digitalWrite(KEYOUT, HIGH); // turn on PTT

      tone(tonePin,800);//tone(A5,800,dah); //send dah, tone(pin, frequency, duration)  

      delay(dah); //delay(dah); //add element space

      noTone(tonePin);

      }

      else  

      {

        digitalWrite(KEYOUT, HIGH); // turn on PTT

        tone(tonePin,800);//tone(A5,800,dit); //send dit, tone(pin, frequency, duration) 

        delay(dit); //add element space

        noTone(tonePin);

      }

      //}

      

      temp = temp >> 1;  // shift right one, when temp = 1 quit loop

      digitalWrite(KEYOUT, LOW); // turn off PTT

      }

  delay(dah); //add dah space 

   

  }

delay(500); // wait 


}


void Msg6() {


//pinMode(tonePin,OUTPUT); // AUDIO OUTPUT pin

//pinMode(13,OUTPUT); // PTT OUTPUT pin

int  element = 0; // letter of message

char temp; 

int LSB =0;

int dit = dotLength ;  // use pot to reset WPM of messgae

int dah = 3*dit;

//digitalWrite(PTT, HIGH); // turn on PTT

delay(500); // 


for (element =0; element < msglength6 ; element ++) //  read cw message

  {


 temp =  message6[element];

 

    for(int x = 0;  temp > 1 ; x++) // read cw message and check for EOM = 0xff// while(temp !=1) //  End of Character = 1 

      {

   

      LSB = bitRead(temp, 0); //LSB of temp, each loop shifts right one 

      delay(dit);//delay(dah * 1.3); //add element space

  

      if(LSB == 1)

      {

      digitalWrite(KEYOUT, HIGH); // turn on PTT

      tone(tonePin,800);//tone(A5,800,dah); //send dah, tone(pin, frequency, duration)  

      delay(dah); //delay(dah); //add element space

      noTone(tonePin);

      }

      else  

      {

        digitalWrite(KEYOUT, HIGH); // turn on PTT

        tone(tonePin,800);//tone(A5,800,dit); //send dit, tone(pin, frequency, duration) 

        delay(dit); //add element space

        noTone(tonePin);

      }

      //}

      

      temp = temp >> 1;  // shift right one, when temp = 1 quit loop

      digitalWrite(KEYOUT, LOW); // turn off PTT

      }

  delay(dah); //add dah space 

   

  }

delay(500); // wait 

}








                                  HOME-MADE                                                                                                                Home page by  IK1LBW