ubitx-upr/ubitx_20/ubitx_keyer.ino
Ashhar Farhan e481ea2a24
The ubitx production sktech, wireup and circuit
This is the snap of the circuit, wiring instructions for the ubitx pcb. the sketch may change slightly for factory alignment but the rest will remain the same.
2017-12-07 10:18:43 +05:30

156 lines
4.7 KiB
C++

/**
* CW Keyer
*
* The CW keyer handles either a straight key or an iambic / paddle key.
* They all use just one analog input line. This is how it works.
* The analog line has the internal pull-up resistor enabled.
* When a straight key is connected, it shorts the pull-up resistor, analog input is 0 volts
* When a paddle is connected, the dot and the dash are connected to the analog pin through
* a 10K and a 2.2K resistors. These produce a 4v and a 2v input to the analog pins.
* So, the readings are as follows :
* 0v - straight key
* 1-2.5 v - paddle dot
* 2.5 to 4.5 v - paddle dash
* 2.0 to 0.5 v - dot and dash pressed
*
* The keyer is written to transparently handle all these cases
*
* Generating CW
* The CW is cleanly generated by unbalancing the front-end mixer
* and putting the local oscillator directly at the CW transmit frequency.
* The sidetone, generated by the Arduino is injected into the volume control
*/
// in milliseconds, this is the parameter that determines how long the tx will hold between cw key downs
#define CW_TIMEOUT (600l)
#define PADDLE_DOT 1
#define PADDLE_DASH 2
#define PADDLE_BOTH 3
#define PADDLE_STRAIGHT 4
//we store the last padde's character
//to alternatively send dots and dashes
//when both are simultaneously pressed
char lastPaddle = 0;
//reads the analog keyer pin and reports the paddle
byte getPaddle(){
int paddle = analogRead(ANALOG_KEYER);
if (paddle > 800) // above 4v is up
return 0;
if (paddle > 600) // 4-3v is dot
return PADDLE_DASH;
else if (paddle > 300) //1-2v is dash
return PADDLE_DOT;
else if (paddle > 50)
return PADDLE_BOTH; //both are between 1 and 2v
else
return PADDLE_STRAIGHT; //less than 1v is the straight key
}
/**
* Starts transmitting the carrier with the sidetone
* It assumes that we have called cwTxStart and not called cwTxStop
* each time it is called, the cwTimeOut is pushed further into the future
*/
void cwKeydown(){
keyDown = 1; //tracks the CW_KEY
tone(CW_TONE, (int)sideTone);
digitalWrite(CW_KEY, 1);
cwTimeout = millis() + CW_TIMEOUT;
}
/**
* Stops the cw carrier transmission along with the sidetone
* Pushes the cwTimeout further into the future
*/
void cwKeyUp(){
keyDown = 0; //tracks the CW_KEY
noTone(CW_TONE);
digitalWrite(CW_KEY, 0);
cwTimeout = millis() + CW_TIMEOUT;
}
/**
* The keyer handles the straight key as well as the iambic key
* This module keeps looping until the user stops sending cw
* if the cwTimeout is set to 0, then it means, we have to exit the keyer loop
* Each time the key is hit the cwTimeout is pushed to a time in the future by cwKeyDown()
*/
void cwKeyer(){
byte paddle;
lastPaddle = 0;
while(1){
paddle = getPaddle();
// do nothing if the paddle has not been touched, unless
// we are in the cw mode and we have timed out
if (!paddle){
if (0 < cwTimeout && cwTimeout < millis()){
cwTimeout = 0;
keyDown = 0;
stopTx();
}
if (!cwTimeout)
return;
//if a paddle was used (not a straight key) we should extend the space to be a full dash
//by adding two more dots long space (one has already been added at the end of the dot or dash)
if (cwTimeout > 0 && lastPaddle != PADDLE_STRAIGHT)
delay(cwSpeed * 2);
// got back to the begining of the loop, if no further activity happens on the paddle or the straight key
// we will time out, and return out of this routine
delay(5);
continue;
}
Serial.print("paddle:");Serial.println(paddle);
// if we are here, it is only because the key or the paddle is pressed
if (!inTx){
keyDown = 0;
cwTimeout = millis() + CW_TIMEOUT;
startTx(TX_CW);
updateDisplay();
}
// star the transmission)
// we store the transmitted character in the lastPaddle
cwKeydown();
if (paddle == PADDLE_DOT){
delay(cwSpeed);
lastPaddle = PADDLE_DOT;
}
else if (paddle == PADDLE_DASH){
delay(cwSpeed * 3);
lastPaddle = PADDLE_DASH;
}
else if (paddle == PADDLE_BOTH){ //both paddles down
//depending upon what was sent last, send the other
if (lastPaddle == PADDLE_DOT) {
delay(cwSpeed * 3);
lastPaddle = PADDLE_DASH;
}else{
delay(cwSpeed);
lastPaddle = PADDLE_DOT;
}
}
else if (paddle == PADDLE_STRAIGHT){
while (getPaddle() == PADDLE_STRAIGHT)
delay(1);
lastPaddle = PADDLE_STRAIGHT;
}
cwKeyUp();
//introduce a dot long gap between characters if the keyer was used
if (lastPaddle != PADDLE_STRAIGHT)
delay(cwSpeed);
}
}