The Shield has four outputs, VFO, BFO, I & Q from the Si5351 DDS CLk0, CLK1 & CLK2.
It covers 40, 30 & 20m with tuning in 100Hz steps.
It connects to an LCD and ROtary Encoder with Button.
Transmit is enabled by a LOW signal on D9 (KEY) input, this controls D31 & D12 (Tx & Rx) outputs.
Code
// Universal_VFO outputs for 40-30-20m
// V1.0 M6KWH ganymedeham.blogspot.com
// "Universal SDR|VFO" shield uses CLK0 for VFO output
// Frequency changes in STEPS by rotary encoder. Button changes band for 40-30-20m
// Start frequency on each band is selected on startup or band change
// LCD displays frequency in kHz, band and RX/TX
// note: freq variable is in cHz
// ----- 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)
// -----
// Control bus definition
// D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
// RX TX Band * Key NMEA 1PPS Btn EncB EncA PC PC
// out out out in in in in in in
// * for future Band switch control, e.g. transverter
// RX | TX out enable LOW
// Band 40 LOW, 30 & 20 HIGH
// Key in LOW TX, HIGH or O/C RX
// I2C, Si5351, LCD and rotary Encoder libraries
#include "Wire.h"
#include "si5351.h"
#include "LiquidCrystal_I2C.h"
#include "Rotary.h"
// LCD
#define LCDADDR 0x27
#define LCDCOLS 16
#define LCDROWS 2
// rotary Encoder pins 2 & 3 (DT & CLK), band change pin 4 (SW)
#define DT 2
#define CLK 3
#define SW 4
// RX & TX (enable = LOW), band relay and XMIT (LOW = TX)
#define RX 13
#define TX 12
#define BAND 11
#define XMIT 9
// tuning freq STEPS (cHz), 100Hz
#define STEPS 10000
// dds object
Si5351 dds;
// LCD object
LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS);
// rotary Encoder object
Rotary rot = Rotary(DT, CLK);
// start frequencies (cHz), band names
uint32_t freqStart[3] = {
710000000, 1014000000, 1410000000};
char bandName[][4] = {
"40m", "30m", "20m"};
// band, freq, RXTX flag init
byte band = 0;
uint32_t freq = freqStart[band];
void setup()
{
// init LCD & backlight on
lcd.init();
lcd.backlight();
// init dds si5351 module, "0" = default 25MHz XTAL
dds.init(SI5351_CRYSTAL_LOAD_8PF, 0);
// enable VFO output CLK0, disable CLK1 & 2
dds.output_enable(SI5351_CLK0, 1);
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);
pinMode(RX, OUTPUT); // SDR RX enable
pinMode(TX, OUTPUT); // SDR TX enable
pinMode(BAND, OUTPUT); // PA band relay 40/30&20m
pinMode(XMIT, INPUT_PULLUP); // key default HIGH
// init RX
digitalWrite(RX, LOW); // RX enable
digitalWrite(TX, HIGH); // TX disable
bandRly(band); // switch PA band relays
freqOut(freq); // output freq
dispMsg(0, 0, "VFO "); // display VFO col 0 row 0
dispFreq(5, 0, freq, 1); // display freq col 5 row 0
dispMsg(0, 1, "Band "); // display Band col 0 row 1
dispMsg(5, 1, bandName[band]); // display band col 5 row 1
RxTx(digitalRead(XMIT)); // set RX
}
void loop()
{
tune(); // rotary encoder tuing
bandChg(); // button pushed for band change
RxTx(digitalRead(XMIT)); // PTT/KEY for transmit, 1 = RX, 0 = TX
}
void tune()
{
unsigned char dir; // tuning direction CW/CCW
// tune?
dir = rot.process(); // read encoder
if(dir != DIR_NONE) // turned?
{
if(dir == DIR_CW) freq += STEPS; // increment freq +/- STEPS
if(dir == DIR_CCW) freq -= STEPS;
freqOut(freq); // output freq
dispFreq(5, 0, freq, 1); // update freq display
}
}
void bandChg()
{
// change band?
if(digitalRead(SW) == LOW) // button pressed?
{
while(!digitalRead(SW)); // wait for release
if(band == 2) band = 0; // loop
else band++;
freq = freqStart[band]; // set centre freq of new band
bandRly(band); // switch PA band relays
freqOut(freq); // output freq
dispFreq(5, 0, freq, 1); // update freq & band display
dispMsg(5, 1, bandName[band]);
}
}
// frequency (in cHz) for VFO, on CLK0
void freqOut(uint32_t f)
{
dds.set_freq(f, 0ULL, SI5351_CLK0); // converted to cHz
}
// switch band relay
void bandRly(byte b)
{
switch(b)
{
case 0: // 40m
digitalWrite(BAND, LOW);
break;
case 1: // 30 & 20m
case 2:
digitalWrite(BAND, HIGH);
break;
}
}
// change RX TX, x = HIGH RX, x = LOW TX
void RxTx(bool x)
{
if(x == LOW) // TX
{
dispMsg(13, 1, "TX");
digitalWrite(RX, HIGH); // RX off
digitalWrite(TX, LOW); // TX on
}
else
{
dispMsg(13, 1, "RX");
digitalWrite(RX, LOW); // RX on
digitalWrite(TX, HIGH); // TX off
}
}
// 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 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