diff --git a/README.md b/README.md index 9223f76..91f1fc4 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,18 @@ Code for the WSPR protocol Currently only simple callsigns and 4-symbol locators are accepted. Power is in dBm. +## arduino_ad9851.ino + +Arduino program to actually transmit the data generated by `encode.py` using +an AD9851 module. + +**Note**: if you use the square wave output (QOUT1 or its inverse QOUT2), +make sure to tune the comparator voltage to achieve a reasonable duty cycle. +If followed by a class E amplifier this is about 45% for maximum power output +(anywhere near 50% should be OK). I use a DC voltmeter and approximate the +duty cycle with V/5, so that a measured 2V reading translates into a 40% duty +cycle. + +You could of course also take either of the sine wave outputs (ZOUT1, ZOUT2) +and amplify or feed directly into a low-pass filter to the antenna. + diff --git a/arduino_ad9851.ino b/arduino_ad9851.ino new file mode 100644 index 0000000..53adf9d --- /dev/null +++ b/arduino_ad9851.ino @@ -0,0 +1,149 @@ +/* AD9851 module WSPR transmitter + * Robert Östling SM0YSR 2017-08-29 + * + * Use the encode.py script to generate the data to transmit, then paste it + * into msg = { ... } below. + * + * You may also want to tweak the frequency: + */ + +// Set TX frequency +#define F_BASE 3594086.0 +//#define F_BASE 10140186.0 + +byte msg[162] = { /* output of encode.py */ }; + + +byte pin_button = 2; // button that pulls LOW to start transmitting + // internal pull-up is enabled, so just short to GND + // This is just for timing, after the button is + // pressed the system will go into an infinite loop + // transmitting every 10 minutes. + +byte pin_key = 3; // "keyer" output, HIGH = enable TX +byte pin_reset = 4; // DDS reset pin +byte pin_load = 5; // DDS load pin +byte pin_clock = 6; // DDS clock pin +byte pin_data = 7; // DDS data pin +byte pin_led = 13; // Arduino LED + +/* +Left side of module (with LED facing up, at upper right corner): + +VCC +W_CLK (clock) +FU_UD (load) +DATA (data) +RESET (reset) +GND +QOUT1 +QOUT2 +ZOUT1 +ZOUT2 +*/ + +// Encoded frequency table for the 4 FSK tones +// This is pre-computed so that it can be sent directly to the DDS +unsigned long fsk[4] = { + (unsigned long)((F_BASE * 4294967296.0) / 180e6), + (unsigned long)(((F_BASE + 1.0*1.4648) * 4294967296.0) / 180e6), + (unsigned long)(((F_BASE + 2.0*1.4648) * 4294967296.0) / 180e6), + (unsigned long)(((F_BASE + 3.0*1.4648) * 4294967296.0) / 180e6) +}; + +void write_bit(byte x) { + if(x) { + digitalWrite(pin_clock, LOW); + digitalWrite(pin_data, HIGH); + digitalWrite(pin_clock, HIGH); + digitalWrite(pin_data, LOW); + } else { + digitalWrite(pin_clock, LOW); + digitalWrite(pin_data, LOW); + digitalWrite(pin_clock, HIGH); + } +} + +void write_byte(byte x) { + for(byte i=0; i<8; i++) { + write_bit(x&1); + x >>= 1; + } +} + +void set_frequency_word(unsigned long w) { + digitalWrite(pin_load, LOW); + for(byte i=0; i<32; i++) { + write_bit(w&1); + w >>= 1; + } + write_byte(0x09); + digitalWrite(pin_load, HIGH); +} + +void setup() { + pinMode(pin_reset, OUTPUT); + pinMode(pin_load, OUTPUT); + pinMode(pin_clock, OUTPUT); + pinMode(pin_data, OUTPUT); + pinMode(pin_led, OUTPUT); + pinMode(pin_key, OUTPUT); + pinMode(pin_button, INPUT_PULLUP); + + digitalWrite(pin_reset, LOW); + digitalWrite(pin_clock, LOW); + digitalWrite(pin_data, LOW); + digitalWrite(pin_load, LOW); + digitalWrite(pin_led, LOW); + digitalWrite(pin_key, LOW); + + delay(2000); + + digitalWrite(pin_reset, HIGH); + delay(5); + digitalWrite(pin_reset, LOW); + delay(5); + + digitalWrite(pin_clock, HIGH); + delay(5); + digitalWrite(pin_clock, LOW); + delay(5); + + digitalWrite(pin_load, HIGH); + delay(5); + digitalWrite(pin_load, LOW); + delay(5); + + // Arbitrary + set_frequency_word(fsk[0]); +} + +// Infinite transmit loop, one message every 10 minutes +void tx() { + int i; + unsigned long t0 = millis(); + + while(1) { + digitalWrite(pin_key, HIGH); + for (i=0; i<162; i++) { + set_frequency_word(fsk[msg[i]]); + double target = + t0 + (unsigned long)(((double)(i+1))*(1000.0*8192.0/12000.0)); + digitalWrite(pin_led, (i&1)); + while(millis() < target); + } + digitalWrite(pin_key, LOW); + digitalWrite(pin_led, LOW); + t0 += 600000UL; + while(millis() < t0); + } +} + +void loop() { + // Wait for button press, then start infinite loop + if (digitalRead(pin_button) == LOW) { + tx(); + // this will never be reached + } +} +