Here's the code for 30m WSPR transmissions, it has my new call sign embedded. Reminder: the code runs on my Arduino shield using a Si5351 modules and a DS3231 RTC module for timing. The time has to be set to the nearest 1sec using special sketch.
Code
// WSPR_30M-Basic
// Uses WsprMessage library of John Newcombe
// reads time from RTC, must be set accurately by spearate program
// Si5351 I2C bus
// SDA = A4
// SCL = A5
// LCD I2C bus (16x2)
// SDA = A4
// SCL = A5
// rotary encoder pins
// DT = 2
// CLK = 3
// SW = 4
#include "WsprMessage.h"
#include "si5351.h"
#include "LiquidCrystal_I2C.h"
// LCD 0x27 or 0x3F
#define LCDADDR 0x27
//#define LCDADDR 0x3F
#define LCDCOLS 16
#define LCDROWS 2
// RTC address
#define RTCADDR 0x68
// RTC time
byte sec, mns, hrs;
// repeat TX interval (sec)
uint8_t repeat;
// WSPR data
char callsign[] = " M0IFA"; // your callsign
char loc_short[] = "IO92"; // your short locator
int power = 20; // transmit power in dBm
char msgtxt[] = {" M0IFA IO92 20 "}; // msg displayed on lcd
// WSPR Frequency
uint64_t WSPRFreq = 1014020000; // WSPR frequency (cHz)
// WSPR Delta Freq for symbols 0, 1, 2, 3. = 145.48 x 0, 1, 2 and 3 to nearest cHz
uint64_t delta[] = {0, 145, 291, 436};
// Data from WsprMessage
unsigned char *sym; // ptr to symbol vector from WsprMessage
// blank MSG_ZISE (= 162) char array for WSPR message, will be populated (0, 1, 2 or 3) in setup() by WsprMessage
char WSPR_Message[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// create SI5351 object
Si5351 dds;
// create LCD object
LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS);
//=======SETUP========
void setup() {
// init I2C
Wire.begin();
// init lcd
lcd.begin();
lcd.backlight();
// init dds
dds.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
// set 8mA output drive (max possible)
dds.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
// init transmit frequency, set freq 1st as turns outputs on
dds.set_freq(WSPRFreq, SI5351_CLK0);
// disable outputs (CLK0 enabled on TX)
dds.output_enable(SI5351_CLK0, 0);
dds.output_enable(SI5351_CLK1, 0);
dds.output_enable(SI5351_CLK2, 0);
// build WSPR message, get size and pointer to symbols
WsprMessage WsprMessage(callsign, loc_short, power);
sym = WsprMessage.symbols; // get address ptr to symbols
for(int i = 0; i < 162; i++) { // copy sym array to WSPR_Message array
WSPR_Message[i] = sym[i]; // both are char arrays, same as bytes
}
repeat = 2; // defalt repeat WSPR TX every 2 minutes
// initial display
dispMsg(0, 0, "WSPR ");
dispFreq(5, 0, WSPRFreq, 2); // display freq b
dispNum(0, 1, repeat);
dispMsg(1, 1, " min ");
}
// ========MAIN LOOP=========
void loop() {
// get time & display
getRTC();
dispTime(8, 1);
// send WSPR?
if (mns % repeat == 0 && sec == 0)
{
// display message
dispMsg(0, 0, msgtxt);
dispMsg(8, 1, " TX "); // show transmit
sendWspr(682); // transmit on freq. 682ms per suymbol 162 * 682 = 110.48 sec total frame
// restore display
dispMsg(0, 0, "WSPR ");
dispFreq(5, 0, WSPRFreq, 2); // display freq
dispMsg(1, 1, " min ");
dispNum(0, 1, repeat);
}
}
//========WSPR send routine
void sendWspr(int SymbolLength) {
// Send WSPR Message
dds.output_enable(SI5351_CLK0, 1); // enable CLK0 output
for (int s = 0; s < MSG_SIZE; s++) { // For all symbols, MSG_SIZE in WsprMessage.h
dds.set_freq(WSPRFreq + delta[WSPR_Message[s]], SI5351_CLK0); // transmit frequency
delay(SymbolLength); // symbol timing
}
dds.output_enable(SI5351_CLK0, 0); // disable CLK0 output
}
// get time from RTC, convert bcd to decimal
void getRTC()
{
// Reset the register pointer
Wire.beginTransmission(RTCADDR);
byte zero = 0x00;
Wire.write(zero);
Wire.endTransmission();
// request 1st 3 bytes from the RTC address
Wire.requestFrom(RTCADDR, 3);
// get the s/m/h time data
sec = bcdToDec(Wire.read());
mns = bcdToDec(Wire.read());
hrs = bcdToDec(Wire.read() & 0b111111); // mask 24 hour time bit
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return ( (val / 16 * 10) + (val % 16) );
}
//=======Display routines
// display freq in kHz,col c, row r, d decimal places
void dispFreq(uint8_t c, uint8_t r, uint64_t f, uint8_t d)
{
lcd.setCursor(c, r); // clear last freq display
lcd.print((float)f / 100000, d); // convert to float for print function
lcd.print("kHz "); // + trailing spaces to clear previous display
}
// 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 time at col, row
void dispTime(byte c, byte r) {
lcd.setCursor(c, r);
if (hrs < 10)
lcd.print("0");
lcd.print(hrs);
lcd.print(":");
if (mns < 10)
lcd.print("0");
lcd.print(mns);
lcd.print(":");
if (sec < 10)
lcd.print("0");
lcd.print(sec);
}
No comments:
Post a Comment