     1	/*
     2	 * Arduino iambic CW keyer v2.0
     3	 * for Ham radio usage
     4	 * Richard Chapman
     5	 * KC4IFB
     6	 * February, 2009
     7	 */ 
     8	 
     9	 
    10	// I/O pin numbers
    11	#define SPEEDIN 0                      // analog pin to read the speed value 
    12	#define DOTIN 11                     // high -> dot paddle closed
    13	#define DASHIN 12                    // high -> dash paddle closed 
    14	#define KEYOUT 13                    // drives the 2N2222 that closes the key connection
      	
    15	// state of the machine
    16	#define IDLE 0   // doing nothing
    17	#define DASH 1   // playing a dash
    18	#define DOT  2   // playing a dot
    19	#define DELAY 3  // in the dot-length delay between two dot/dashes
      	
      	
    20	int dotLength;      // length of a dot in milliseconds
    21	int dotVal;         // value of the dot paddle this sycle of main loop
    22	int dashVal;        // value of the dash paddle this cycle of main loop
    23	int oldDotVal;      // value of dot paddle last cycle 
    24	int oldDashVal;     // value of dash paddle last dial 
    25	int speedDial;      // raw value read from the potentiometer for speed 
    26	int currEltEndTime; // what time did the current element start sounding (in milliseconds since powerup)
    27	int currElt;        // sate of what the keyer output is sending right now
    28	int nextElt;        // state the keyer will go into when current element ends 
    29	int lastElt;        // previous state of the keyer
    30	int time; 
      	
    31	void setup()                    // run once, when the sketch starts
    32	{
    33	  pinMode(KEYOUT, OUTPUT);      // sets modes on the i/o pins
    34	  pinMode(DOTIN, INPUT);         
    35	  pinMode(DASHIN, INPUT); 
    36	  // no need to set SPEED pin as input since it is analog
    37	  digitalWrite(KEYOUT, LOW);     // initially the key is open
    38	  
    39	  // activate internal pullup resistors 
    40	  digitalWrite(DOTIN,HIGH); 
    41	  digitalWrite(DASHIN,HIGH);
    42	  
    43	  // initialize the state variables 
    44	  lastElt = IDLE; 
    45	  currElt = IDLE;
    46	  nextElt = IDLE; 
    47	  time = millis();
    48	  currEltEndTime = time; 
      	
    49	}
      	
    50	void loop()                     // run over and over again
    51	{
    52	   
    53	   // get the speed (need to do this every iteration)
    54	   speedDial = analogRead(SPEEDIN); 
    55	   dotLength = 1200 / ( 5 + (speedDial/64)); 
    56	   
    57	   // read the paddles
    58	   oldDotVal = dotVal; // save the old values to detect a transition, so you can debounce 
    59	   oldDashVal = dashVal;
    60	   dotVal = digitalRead(DOTIN);  // read the current values of the paddles
    61	   dashVal = digitalRead(DASHIN); 
    62	   
    63	   // short delay for a debounce  -- turns out not needed 
    64	   //if ((oldDotVal != dotVal) || oldDashVal != dashVal) { 
    65	   //    delay(5); 
    66	   //}    
    67	   
    68	   //get the current time
    69	   time = millis(); 
    70	   
    71	   switch(currElt) {  // cases based on what current state is 
    72	   case DASH:
    73	      if ((dotVal == LOW) && (nextElt == IDLE)) {  // going from dash to iambic mode 
    74	           nextElt = DOT;
    75	      } 
    76	     if (time >= currEltEndTime) {  // at end of current dash
    77	       lastElt = DASH;  // a delay will follow the dash 
    78	       currElt = DELAY; 
    79	       currEltEndTime = time+dotLength;
    80	     } 
    81	     digitalWrite(KEYOUT,HIGH);  // close the keyer output while the dash is being sent
    82	     break;  
    83	   case DOT: 
    84	     if ((dashVal == LOW) && (nextElt = IDLE)) {  // going from dot to iambic mode
    85	           nextElt = DASH;
    86	     } 
    87	     if (time >= currEltEndTime) {  // at end of current dot 
    88	       lastElt = DOT;  // a delay will follow the dot 
    89	       currElt = DELAY; 
    90	       currEltEndTime = time+dotLength;
    91	     } 
    92	     digitalWrite(KEYOUT,HIGH); // close the keyer outout while the dot is being sent
    93	     break;  
    94	   case IDLE:   // not sending, nor finishing the delay after a dot or dash
    95	     if ((dotVal == LOW) && (dashVal == HIGH)) { // only dot paddle pressed, go to DOT mode 
    96	          lastElt = IDLE; 
    97	          currElt = DOT; 
    98	          currEltEndTime = time + dotLength; 
    99	     } else if ((dotVal == HIGH) && (dashVal == LOW)) { // only dash paddle pressed, go to DASH mode
   100	          lastElt = IDLE; 
   101	          currElt = DASH; 
   102	          currEltEndTime = time + 3*dotLength;  
   103	     } else if ((dotVal == LOW) && (dashVal == LOW) && (nextElt == IDLE)) {  
   104	          // if both paddles hit at same time (rare, but happens)
   105	          lastElt = IDLE; 
   106	          currElt = DOT; 
   107	          nextElt = DASH; 
   108	          currEltEndTime = time + 3*dotLength; // it is an iambic keyer, not a trochaic keyer
   109	     } 
   110	     digitalWrite(KEYOUT,LOW);  // keyer output is open in IDLE mode
   111	     break; 
   112	   case DELAY:  // waiting for a dot-length delay after sending a dot or dash 
   113	     if (time >= currEltEndTime) {  // check to see if there is a next element to play
   114	       currElt = nextElt; 
   115	       if (currElt == DOT) { 
   116	            currEltEndTime = time+dotLength; 
   117	       } else if ( currElt == DASH) { 
   118	            currEltEndTime = time+3*dotLength;
   119	       }
   120	       lastElt = DELAY; 
   121	       nextElt = IDLE;   
   122	     }
   123	     // during the delay, if either paddle is pressed, save it to play after the delay
   124	     if ((lastElt == DOT) && (dashVal == LOW) && (nextElt == NULL)) { 
   125	        nextElt = DASH;
   126	     } else if ((lastElt == DASH) && (dotVal == LOW) &&(nextElt == NULL)) { 
   127	        nextElt = DOT; 
   128	     } 
   129	     // key output is open during the delay
   130	     digitalWrite(KEYOUT,LOW);
   131	     break; 
   132	   default:  
   133	     break; 
   134	   }
   135	 
      	
   136	}
      	
