/* * Application: General purpose digital BFO oscillator board for CW and SSB. * * The arduino code uses the pull-up resistors within the arduino Uno chip, to select a data pin, hold Low. * * To determine the use of usb or lsb, hold down to ground either pin 4 for usb or pin 5 for lsb. * The use of pins 6 and 7 would be for cw use. In cw mode, on rx pin 6 is held low and pin 7 held * high, but in CW Tx mode, both pins 6 and 7 are held low, it is pin7 that is connected to the morse key. * * Any data pin not used or selected, is left to hang high or tied to the Arduino +ve supply. * * General purpose BFO arduino code: written by Alastair GW0AJU * * date: 31st May 2016 */ long bfo_freq = 0; long last_set = 0; int usb = 4; // Uno data pin 4 int lsb = 5; // Uno data pin 5 int cw_rx = 6; // Uno data pin 6 int cw_tx = 7; // Uno data pin 7 int cw_select = HIGH; int cw_tx_select = HIGH; int lsb_select = HIGH; int usb_select = HIGH; //*********** dds vfo setup ************** #define DDS_CLOCK 125E6 #define CLOCK 9 // DDS W_CLK = Uno data Pin 9 - connect to AD9850 word load clock pin (CLK) #define LOAD 10 // DDS FQ_UD = Uno data Pin 10 - connect to AD9850 freq update pin (FQ_UD) #define DATA 11 // DDS DATA = Uno data Pin 11 - connect to AD9850 serial data load pin (AD9850 D7 = DATA) #define RESET 12 // DDS RESET = Uno data Pin 12 - connect to AD9850 reset line void setup() { Serial.begin(9600); // error correction in program code use only pinMode(usb, INPUT_PULLUP); // data pin input pull_up resistor activated for usb select pinMode(lsb, INPUT_PULLUP); // data pin input pull_up resistor activated for lsb select pinMode(cw_rx, INPUT_PULLUP); // data pin input pull_up resistor activated for cw select pinMode(cw_tx, INPUT_PULLUP); // data pin input pull_up resistor activated for cw_tx select pinMode(CLOCK, OUTPUT); // pin 9 W_CLK = connect to AD9850 module word load clock pin (CLK) pinMode(LOAD, OUTPUT); // pin 10 FQ_UD = connect to freq update pin (FQ_UD) pinMode(DATA, OUTPUT); // pin 11 DATA = connect to serial data load pin (AD9850 D7 = DATA) pinMode(RESET, OUTPUT); // pin 12 RESET = connect to DDS reset line AD9850_reset(); AD9850_init(); } void loop() { radio_panel_change(); } //***************** radio panel change ************** void radio_panel_change() { cw_select = digitalRead(cw_rx); lsb_select = digitalRead(lsb); usb_select = digitalRead(usb); cw_tx_select = digitalRead(cw_tx); //********************************** CW full break in *************************** if ( cw_select == LOW && lsb_select == HIGH && usb_select == HIGH && cw_tx_select == HIGH) { bfo_freq = (9E6 + 600); // 600Hz audio tone for CW receive, to change AF tone alter the +600 if (last_set != bfo_freq) { sendFrequency(bfo_freq); last_set = bfo_freq; Serial.println("cw reception with 600Hz audio tone"); // error correction message with ide monitor } } if ( cw_select == LOW && lsb_select == HIGH && usb_select == HIGH && cw_tx_select == LOW) { bfo_freq = ( 9E6 ); // BFO carrier on 9MHz for CW transmit mode if (last_set != bfo_freq) { sendFrequency(bfo_freq); last_set = bfo_freq; Serial.println("cw tx mode"); // error correction message with ide monitor } } //******************************* Lsb Tx/Rx mode *********************************** if (cw_select == HIGH && lsb_select == LOW && usb_select == HIGH && cw_tx_select == HIGH) { bfo_freq = (9E6 + 1500); // use +1500Hz for lsb reception if (last_set != bfo_freq) { sendFrequency(bfo_freq); last_set = bfo_freq; Serial.println("lsb reception"); // error correction message with ide monitor } } //******************************* Usb Tx/Rx mode ************************************ if ( cw_select == HIGH && lsb_select == HIGH && usb_select == LOW && cw_tx_select == HIGH) { bfo_freq = (9E6 - 1500); // use -1500Hz for usb reception if (last_set != bfo_freq) { sendFrequency(bfo_freq); last_set = bfo_freq; Serial.println("usb reception"); // error correction message with ide monitor } } } // ************* frequency VFO control from dial change ***************** void AD9850_reset() { //reset sequence is: // CLOCK & LOAD = LOW // Pulse RESET high for a few uS (use 5 uS here) // Pulse CLOCK high for a few uS (use 5 uS here) // Set DATA to ZERO and pulse LOAD for a few uS (use 5 uS here) // data sheet diagrams show only RESET and CLOCK being used to reset the device, but I see no output unless I also // toggle the LOAD line here. digitalWrite(CLOCK, LOW); digitalWrite(LOAD, LOW); digitalWrite(RESET, LOW); delayMicroseconds(5); digitalWrite(RESET, HIGH); //pulse RESET delayMicroseconds(5); digitalWrite(RESET, LOW); delayMicroseconds(5); digitalWrite(CLOCK, LOW); delayMicroseconds(5); digitalWrite(CLOCK, HIGH); //pulse CLOCK delayMicroseconds(5); digitalWrite(CLOCK, LOW); delayMicroseconds(5); digitalWrite(DATA, LOW); //make sure DATA pin is LOW digitalWrite(LOAD, LOW); delayMicroseconds(5); digitalWrite(LOAD, HIGH); //pulse LOAD delayMicroseconds(5); digitalWrite(LOAD, LOW); // Chip is RESET now } void AD9850_init() { digitalWrite(RESET, LOW); digitalWrite(CLOCK, LOW); digitalWrite(LOAD, LOW); digitalWrite(DATA, LOW); } // *********** frequency control of the AD9850 DDS device for TX / Rx vfo ********* void sendFrequency(unsigned long frequency) { unsigned long tuning_word = (frequency * pow(2, 32)) / DDS_CLOCK; digitalWrite (LOAD, LOW); shiftOut(DATA, CLOCK, LSBFIRST, tuning_word); shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 8); shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 16); shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 24); shiftOut(DATA, CLOCK, LSBFIRST, 0x00); digitalWrite(LOAD, HIGH); }