WSPR centre frequencies are 7040 000 00, 10140 100 00 & 14090 000 00 cHZ. Turn the Rotary Encoder to chose one of five presets are given per band at 50Hz intervals.
// Universal_WSPR transmits WSPR // use WSPR_Symbol_Generator sketch to make symbol tone table // here it is hard coded for _M6KWH IO92 20 (100mW) // then edit code to insert symbols and msg displays, line 73, 136 & 137 // step in 50Hz steps, giving 5 frequencies per band // output on CLK0 VFO // ----- CONNECTIONS // DDS I2C SI5351 // SCL = A5 // SDA = A4 // I2C address 0x60 // ------ // display I2C LCD 16 * 2 // o A5 SCL (y) // o A4 SDA (or) // o +5 (r) // o GND (bwn) // I2C address 0x27 // ----- // encoder KY-040 // o D2 DT (y) // o D3 CLK (g) // o D4 SW (or) // o +5 (r) // o GND (bwn) // ----- #include "Wire.h" #include "si5351.h" #include "LiquidCrystal_I2C.h" #include "Rotary.h" #include "TimerOne.h" // LCD #define LCDADDR 0x27 #define LCDCOLS 16 #define LCDROWS 2 // rotary Encoder pins 2 & 3 (DT & CLK), button 4 (SW) #define DT 2 #define CLK 3 #define SW 4 // transmit pin #define TX 12 // dds object Si5351 dds; // LCD object LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS); Rotary rot = Rotary(DT, CLK); uint32_t freq; uint8_t tone_ptr = 0; // Pointer to the current symbol volatile uint8_t next_tone = 0; // Incremented by the ISR uint8_t next_tone2 = 0; // Local store, to compare against. uint8_t step_tone = 0; // Flag used to signify we need to move to the next symbol uint8_t b; // band 0 - 26 // band frequencies (cHz) uint32_t band[15] = {704000000, 704005000, 704010000, 704015000, 704020000, 1014010000, 1014015000, 1014020000, 1014025000, 1014030000, 1409700000, 1409705000, 1409710000, 1409715000, 1409720000 }; // 40, 30, 20m // msg _M6KWH IO92 20 - use WSSPR Symbol Generator program to create uint8_t msg[162] = { 3, 1, 2, 0, 0, 0, 2, 2, 1, 2, 0, 2, 3, 1, 3, 0, 2, 2, 1, 2, 0, 3, 0, 1, 3, 1, 1, 0, 2, 0, 0, 2, 0, 0, 1, 0, 0, 1, 0, 1, 2, 0, 0, 0, 0, 2, 1, 2, 1, 3, 0, 0, 1, 3, 0, 1, 2, 0, 0, 1, 3, 2, 1, 0, 2, 2, 0, 3, 3, 2, 3, 2, 3, 0, 3, 0, 3, 2, 0, 3, 2, 0, 1, 2, 1, 3, 0, 0, 0, 3, 1, 0, 1, 0, 1, 0, 2, 2, 3, 0, 0, 0, 0, 0, 1, 0, 2, 1, 0, 2, 1, 3, 1, 2, 1, 1, 0, 0, 3, 3, 2, 1, 2, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 3, 0, 3, 2, 0, 3, 1, 2, 2, 2, 0, 2, 0, 2, 3, 1, 0, 1, 0, 1, 1, 2, 0, 0, 3, 1, 0, 2, 0 }; // tone out at FREQ uint32_t tones[4] = {0, 146, 293, 440}; void setup() { // init LCD & backlight on lcd.init(); lcd.backlight(); dds.init(SI5351_CRYSTAL_LOAD_8PF, 0); // default 25MHz XTAL // all CLK disabled dds.output_enable(SI5351_CLK0, 0); dds.output_enable(SI5351_CLK1, 0); dds.output_enable(SI5351_CLK2, 0); // encoder, button, RX, TX, band and XMIT pins pinMode(DT, INPUT_PULLUP); pinMode(CLK, INPUT_PULLUP); pinMode(SW, INPUT_PULLUP); digitalWrite(TX, HIGH); // no TX b = 7; // band, middle 30m // init display dispMsg(0, 0, "WSPR "); dispFreq(5, 0, band[b], 2); // display freq b } void loop() { tune(); tx(); // await button push } // tune void tune() { unsigned char dir; // tuning direction CW/CCW dir = rot.process(); // read encoder if(dir != DIR_NONE) // turned? { if(dir == DIR_CW && b > 0) b += 1; // increment band freq +/- 1 if(dir == DIR_CCW && b < 15) b -= 1; dispFreq(5, 0, band[b], 2); // display freq } } // transmit void tx() { if (digitalRead(SW) == LOW) { while (!digitalRead(SW)); // wait for release dispMsg(0, 0, " M6KWH IO92 20 "); dispMsg(0, 1, "Syb 100mW TX"); // show transmit txWspr(b); // transmit on freq b // restor display dispMsg(0, 0, "WSPR "); dispFreq(5, 0, band[b], 2); // display freq dispMsg(0, 1, " "); // clear row 1 } } // transmit msg at freq fTable[b] void txWspr(uint8_t b) { // Start Transmitter digitalWrite(TX, LOW); // Start the timer interrupt, is called every 8192/12000 seconds. Timer1.initialize(682666UL); Timer1.attachInterrupt(wspr_isr); // Transmit! while (1) { // do the increment checking without the interrupts, in case it gets // modified while we are checking. noInterrupts(); if (next_tone > next_tone2) { step_tone = 1; // next_tone has incremented, raise flag next_tone2 = next_tone; } interrupts(); if (step_tone) { // Got a call from the ISR to increment the tone step_tone = 0; // We enable the clock here to avoid having it be active before the first tone // is due to be transmitted. dds.output_enable(SI5351_CLK0, 1); // output freq freq = band[b] + tones[msg[tone_ptr]]; freqOut(freq); dispNum(4, 1, tone_ptr); // display symbol number tone_ptr++; // next tone // If we're at the end of the symbol array, disable the timer and break. if (tone_ptr == 162) { Timer1.detachInterrupt(); next_tone = 0; next_tone2 = 0; tone_ptr = 0; break; } } } // Disable clock, re-write display dds.output_enable(SI5351_CLK0, 0); digitalWrite(TX, HIGH); } // Timer ISR. void wspr_isr(void) { next_tone += 1; } // frequency (in cHz) for VFO, on CLK0 void freqOut(uint32_t f) { dds.set_freq(f, 0ULL, SI5351_CLK0); // f cHz } // display char msg at col c, row r void dispMsg(uint8_t c, uint8_t r, char *m) { lcd.setCursor(c, r); lcd.print(m); } // display a number at col c, row r void dispNum(uint8_t c, uint8_t r, uint16_t n) { lcd.setCursor(c, r); lcd.print(n); } // display freq in kHz,col c, row r, d decimal places void dispFreq(uint8_t c, uint8_t r, uint32_t f, uint8_t d) { lcd.setCursor(c, r); // clear last freq display lcd.print(" "); lcd.setCursor(c, r); // clear last freq display lcd.print((float)f / 100000, d); // convert to float for print function lcd.print("kHz"); }
No comments:
Post a Comment