Monday 3 April 2017

BASIC Tech Group - MyNews 35 - OLED display for Elektor SDR

This is a version of the simple Arduino sketch which displays a single coded SDR centre frequency on an OLED 1.3" display. To use it install the library "u8g2" using the Arduino Library Manager (Sketch > Include Library > Manage Libraries ... and search for “u8g2", then select the latest version and Install).



Screen Shot 2017 04 10 at 10 16 33



Code

// SDR_ELEKTOR_OLED_TUNE
// V4.5 9-4-17 update to U8g2lib
// Output 80, 40, 20m in 50kHz steps x4 CLK1
// Si5351 I2C bus
// SDA = A4
// SCL = A5
// OLED 128x64
// SDA = A4
// SCL = A5

// Si5351 V2, LCD libraries
#include "si5351.h"
#include "U8g2lib.h"
#include "Rotary.h"

// chose pin 2,3 or 3,2 for encoder
#define DT 2
//#define DT 3
#define CLK 3
//#define CLK 2
#define SW 4

// xtal correction for Elektor DDS
#define CORRE 180000

// dds object
Si5351 dds;

// oled object
U8G2_SH1106_128X64_NONAME_1_HW_I2C oled(U8G2_R0, U8X8_PIN_NONE, SCL, SDA);

// Encoder object
Rotary enc = Rotary(DT, CLK);

// table of tuning frequencies
uint64_t freqTable[] = {
350000000, 355000000, 360000000, 365000000, 370000000, 375000000,
705000000, 710000000, 715000000,
1405000000, 1410000000, 1415000000, 1420000000, 1425000000
};

// index into freq table, startup freq
byte ndx = 7;

// initial frequency
uint64_t freq = freqTable[ndx];

// freq change flag
volatile bool freqChange;

void setup() {
// encoder, button pins
pinMode(DT, INPUT_PULLUP);
pinMode(CLK, INPUT_PULLUP);
pinMode(SW, INPUT_PULLUP);

// setup interrupts from DT or CLK for tuning
attachInterrupt(digitalPinToInterrupt(DT), freqTune, CHANGE);
attachInterrupt(digitalPinToInterrupt(CLK), freqTune, CHANGE);

// enable interrupts
interrupts();

// oled init, sets I2C addr to 0x3C
oled.begin();

// init dds si5351 module, "0" = default 25MHz XTAL, correction
dds.init(SI5351_CRYSTAL_LOAD_8PF, 0, CORRE);

// set 8mA output drive
dds.drive_strength(SI5351_CLK1, SI5351_DRIVE_8MA);

// enable VFO output CLK1, disable CLK0 & 2
dds.output_enable(SI5351_CLK0, 0);
dds.output_enable(SI5351_CLK1, 1);
dds.output_enable(SI5351_CLK2, 0);

freqOut(freq); // cHz, output freq
freqChange = false;

dispUpdate();
}

void loop() {
if (freqChange) {
freqOut(freq);
freqChange = false;
dispUpdate();
}
}

// ISR - encoder interrupt service routine
void freqTune() {
unsigned char result;

result = enc.process();
if (result == DIR_CW && ndx < 13) {
freq = freqTable[++ndx];
freqChange = true;
}
else if (result == DIR_CCW && ndx > 0) {
freq = freqTable[--ndx];;
freqChange = true;
}
}

// picture loop, display init data
void dispUpdate() {
oled.firstPage();
do {
dispMsg(25, 0, "SDR_ELEKTOR");
dispFreq(25, 25, 0, freq, 0); // freq is in cHz
dispMsg(20, 50, "<-- Freq -->");
} while ( oled.nextPage() );
}

// Output Freq for Elektor SDR, f (cHz) x 4 on CLK1
void freqOut(uint64_t f) {
dds.set_freq(f * 4ULL, SI5351_CLK1);
}

// display freq at x, y, f (Hz), cf (cHz), d)ecimal places
void dispFreq(u8g2_uint_t x, u8g2_uint_t y, double f, double cf, uint8_t d) {
double fd;
char buf[100];

// sets font, cursor position and displays freq
oled.setFont(u8g2_font_10x20_tf); // font
oled.setFontPosTop(); // origin top

fd = f + cf / 100; // calc freq

oled.setCursor(x, y);
oled.print(fd / 1000, d);
oled.print("kHz");
}

// display message at at x), y), *m)essage
void dispMsg(u8g2_uint_t x, u8g2_uint_t y, char *m) {
// sets font, cursor position and displays message
oled.setFont(u8g2_font_7x13_tf); // font
oled.setFontPosTop();
oled.setCursor(x, y);
oled.print(m);
}

No comments: