The DDS has two modes, SDR & VFO. It is tuned in programable steps (at the moment 10kHz for SDR & 100Hz for VFO) . The shield RF Bus outputs VFO and I & Q which are derived like this:
freq = indicated frequency on display D5 HIGH SDR mode freq x4 clk0 = VFO x4 output freq x4 clk1 = Johnson /4 = I & Q x1 outputs D5 LOW VFO mode freq x1 clk0 = VFO output
The input for tuning is a rotary encoder. An LCD display shows the band and the tuned frequency.
Three bands are generated, 40, 30, & 20m. These are selected in turn by the rotary encoder push button. Selecting a new band tunes a preset band frequency.
The 5 connections across the left are for the Rotary Encoder and its Button and 4 for the I2C LCD display. This is documented in the source code.
The schematic diagram is:
Software
The software is a "Universal VFO" this software uses the new "Si5351.h" library from NT7S and implements a VFO switchable to 40, 30, & 20m bands. At the top of the code are defined constants, SDR & VFO, which determine the output frequency, x4 or x1. This value is set to SDR if you want an output x4 the indicated frequency on the VFO output, and a x4 drive to the onboard CD74ACT74 Johnson counter to generate I & Q signals. The VFO output in SDR mode can be used, for example, for the Softrock Lite SDR board. In VFO mode it changes to a single x1 output on the VFO RF bus pin.
The mode, SDR or VFO, is selected by a High or Low on pin D5, selected at start-up by the red jumper link. The constant STEP4 or STEP1 determine the step of the tuning, which can be, for example, 10kHz for driving an SDR, or 100Hz for a direct tuned radio.
The board thus has a VFO output which can be x1 or x4 the indicated frequency. When the hardware /4 Johnson counter is implemented and used, then two further outputs I & Q, provide outputs with the Si5351 running at x4 the frequency displayed. The VFO output is from CLK0, the IQ drive is from CLK1. Board outputs VFO, I & Q are on the RF bus (see previous post below).
Thus this design, with small changes in the software can satisfy diverse applications. Here's the code:
// Universal VFO, outputs for 40-30-20m // V0.9 // Function // Generates VHF & IQ outputs. // Si 5351 output is x1 or x4 displayed frequency. // Frequency selected in programmable steps by rotary encoder. Button changes bands 40-30-20m // Change of band sets new frequency to band // LCD displays frequency in kHz and band // ----- // Shield has RF bus with VFO, I & Q outputs // Two modes, set by link (pin D5): // SDR (D5 HIGH) outputs x4 from clk0 to VFO, & x1 quadrature to I & Q. 10kHz steps // VFO (D5 LOW) outputs x1 on clk0 to VFO out, 100Hz steps // ----- // 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) //----- // D12-D13 TX-RX enable // D10-D11 band switch relays 40-30-20 // ----- // I2C, Si5351, LCD and Rotary Encoder libraries #include "Wire.h" #include "si5351.h" #include "LiquidCrystal_I2C.h" #include "Rotary.h" // XTAL freq, PLL multiplier, outputs 0-2, IQ Mult, steps (Hz) #define XTAL 25 #define MULT 36 #define SDR 4 #define VFO 1 #define STEP4 10000 #define STEP1 100 // SDR/VFO link pin 5, button pin 4, Rotary Encoder pins 2 & 3 (A & B) #define LINK 5 #define BUTTON 4 #define ROTA 2 #define ROTB 3 // dds object Si5351 dds; // lcd object LiquidCrystal_I2C lcd(0x27, 16, 2); // Rotary Encoder object Rotary rot = Rotary(ROTA, ROTB); // start frequencies (Hz) float bandStart[3] = { 7000000, 10050000, 14000000}; char bandName[3][4] = { "40m", "30m", "20m"}; // band 0 = 40m, 1 = 30m, 2 = 20m // band & freq, freq steps, mode byte band; float freq; float steps; byte mode; void setup() { // encoder, button, link, relays & TXRX pin config pinMode(ROTA, INPUT_PULLUP); pinMode(ROTB, INPUT_PULLUP); pinMode(BUTTON, INPUT_PULLUP); pinMode(LINK, INPUT_PULLUP); // default input = HIGH mode = digitalRead(LINK); // HIGH (default) = SDR, LOW = VFO if(mode == HIGH) steps = STEP4; // set steps STEP4 (SDR) or STEP1 (VFO) else steps = STEP1; dds.init(SI5351_CRYSTAL_LOAD_8PF); // init si5351 lcd.init(); // init LCD & backlight lcd.backlight(); // startup band & frequency band = 0; // 40m freq = bandStart[band]; freqOut(freq); dispMenu(); // display menu dispFreq(freq); // display freq dispBand(bandName[band]); // display band } void loop() { unsigned char dir; // tuning direction CW/CCW byte step; if(digitalRead(BUTTON) == LOW) // button pressed? { while(!digitalRead(BUTTON)); // wait for release if(band == 2) band = 0; // go around else band++; freq = bandStart[band]; // set centre freq of new band freqOut(freq); dispFreq(freq); // update freq & band display dispBand(bandName[band]); } dir = rot.process(); // read encoder if(dir != DIR_NONE) // turned? { if(dir == DIR_CW) freq += steps; // increment +/- STEP if(dir == DIR_CCW) freq -= steps; freqOut(freq); dispFreq(freq); // update freq display } } // freq out x IQ void freqOut(float freq) { if(mode == HIGH) // SDR mode { dds.set_freq(freq * SDR, 0, SI5351_CLK0); // VFO out, x4 dds.set_freq(freq * SDR, 1, SI5351_CLK1); // CD74AC74 quadrature to I & Q } else { dds.set_freq(freq * VFO, 0, SI5351_CLK0); // direct VFO out, x1 } } // display menu void dispMenu() { lcd.setCursor(1, 0); // display caption if(mode == HIGH) lcd.print("SDR"); else lcd.print("VFO"); lcd.setCursor(1, 1); lcd.print("Band"); } // display freq void dispFreq(float f) { float pf; pf = f /1000; // kHz lcd.setCursor(5, 0); lcd.print(" "); // clear last freq display if(pf < 9999.9) lcd.setCursor(6, 0); else lcd.setCursor(5, 0); lcd.print(pf, 1); lcd.setCursor(13, 0); lcd.print("kHz"); } // display band void dispBand(char b[]) { lcd.setCursor(5, 1); lcd.print(" "); // clear last band display lcd.print(b); }
No comments:
Post a Comment