Skip to content

Instantly share code, notes, and snippets.

@zoonman
Created October 22, 2018 20:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zoonman/c774ef71581b1efa468ffdccc9d961a5 to your computer and use it in GitHub Desktop.
Save zoonman/c774ef71581b1efa468ffdccc9d961a5 to your computer and use it in GitHub Desktop.
#define ENCODER_OPTIMIZE_INTERRUPTS
#include <Encoder.h>
#include <Wire.h>
#include <si5351.h>
#include <Adafruit_ST7735.h>
#include <Fonts/FreeSansBold15pt7b.h>
// For the breakout, you can use any 2 or 3 pins
// These pins will also work for the 1.8" TFT shield
#define TFT_CS 10
#define TFT_RST 8
#define TFT_DC 9
// encoder pins setup
#define ENC_PIN_A INT0
#define ENC_PIN_B INT1
#define START_F (uint32_t)21150000
#define STR_BUFFER_SIZE 12
#define BANDS 8
// colors
#define COLOR_BRIGHT_GREEN 0x96C0
#define COLOR_DARK_GREEN 0x29C0
#define COLOR_DARK_RED 0x6800
#define COLOR_MEDIUM_RED 0x9041
#define COLOR_BRIGHT_RED 0xE800
#define COLOR_BRIGHT_BLUE 0x1473
#define COLOR_BAND_BACKGROUND 0x0208
#define COLOR_GRAY_MEDIUM 0x9CD3
// display
#define TFT_HEIGHT 128
#define TFT_WIDTH 160
#define TFT_QUOTER_WIDTH TFT_WIDTH/4
// positions
#define FREQUENCY_X 10
#define FREQUENCY_Y TFT_HEIGHT / 2
#define FREQUENCY_FAKE_SPACE '/'
#define BAR_WIDTH 14
#define SCALE_Y TFT_HEIGHT / 4 * 3
#define SCALE_T 3
int d,pd;
char b[STR_BUFFER_SIZE];
volatile uint8_t pl = 1;
uint8_t freqMultiplier = 5;
// volatile keyword must be used for global variables used inside interrupt handlers
// @see https://barrgroup.com/Embedded-Systems/How-To/C-Volatile-Keyword
volatile uint32_t cFrequency = 0; // Hz 4294967296
volatile uint32_t oFrequency = 0; // Hz
long positionLeft = 0;
// RX or TX
volatile bool tx = false; // rx
volatile uint16_t scalePosX = 0;
//
enum Mode {CW = 0, LSB, USB, AM, FM};
const char* ModeNames[] = {"CW", "LSB", "USB", "AM", "FM"};
volatile Mode currentMode = LSB;
// Bands
struct BandRecord {
uint8_t id; // meters
uint16_t start; // kHZ
uint16_t width; // kHz
};
BandRecord BandsBounds[BANDS] = {
{160, 1800, 200},
{80, 3500, 500},
{40, 7000, 300},
{30, 10100, 150},
{20, 14000, 350},
{17, 18068, 100},
{15, 21000, 450},
{10, 28000, 1700}
};
volatile int8_t currentBandIndex = -1;
Encoder myEnc(2, 3); // pin (2 = D2, 3 = D3)
// Init Display
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
//
Si5351 si5351;
void drawLevel(uint8_t l) {
tft.drawRect(0, TFT_HEIGHT - 10, TFT_WIDTH, 10, COLOR_BAND_BACKGROUND);
if (l == pl) return;
if (l > 12) l = 12;
if (l < 1) l = 1;
uint8_t i;
if (l > pl) {
for (i = pl; i < l; i++) {
drawLevelBar(i);
}
pl = l;
}
if (l < pl) {
for (i = pl; i > l; i--) {
tft.fillRect((i - 1) * BAR_WIDTH + 2, TFT_HEIGHT - 8, BAR_WIDTH + (i > 9) ? 2 : 0, 6, ST77XX_BLACK);
}
pl = l;
}
}
void drawLevelBar(uint8_t l) {
uint16_t color;
uint8_t wOffset = (l > 9) ? 2 : 0, sOffset = 0;
uint8_t lxp = (l - 1) * BAR_WIDTH + 2;
switch (l) {
case 10: color = ST77XX_YELLOW; break;
case 11: color = ST77XX_ORANGE; sOffset = 2; break;
case 12: color = ST77XX_RED; break;
default:
color = ST77XX_GREEN;
}
tft.fillRect(lxp + sOffset, TFT_HEIGHT - 8, BAR_WIDTH - 1 + wOffset, 6, color);
if (l > 9) {
itoa(l+1, b, 10);
b[0] = '+';
b[2] = '0';
b[3] = 0;
lxp -= 7;
if (l > 10) {
lxp += 3;
}
} else {
itoa(l, b, 10);
}
textxy(lxp + 4, TFT_HEIGHT - 18, b, color);
}
void wipe(char *buf) {
for (int8_t i = 0;i < STR_BUFFER_SIZE;i++) {
buf[i] = 0;
}
}
void setFrequency() {
uint8_t hiBit = 0;
char st[STR_BUFFER_SIZE];
char f[STR_BUFFER_SIZE];
wipe(st);
wipe(f);
ultoa(cFrequency, st, 10);
int8_t j = STR_BUFFER_SIZE-2;
for (int8_t i = STR_BUFFER_SIZE-2;i >= 0;i--) {
while (st[j] == 0 && j > 0) {
j--;
};
if (i == 7) {
f[i] = FREQUENCY_FAKE_SPACE;
goto fend;
}
if (i == 3) {
f[i] = '.';
goto fend;
}
if (j >= 0) {
f[i] = st[j];
j--;
} else {
f[i] = FREQUENCY_FAKE_SPACE;
}
fend:
;
}
int16_t x1, y1;
uint16_t w, h;
tft.setTextSize(1);
tft.setFont(&FreeSansBold15pt7b);
tft.setTextColor(COLOR_BRIGHT_GREEN);
tft.getTextBounds(f, FREQUENCY_X, FREQUENCY_Y, &x1, &y1, &w, &h);
tft.fillRect(x1, y1, w+10, h, ST77XX_BLACK);
tft.setCursor(FREQUENCY_X, FREQUENCY_Y);
tft.print(f);
tft.setFont();
//tft.drawRect(x1, y1, w+10, h, COLOR_BRIGHT_BLUE);
oFrequency = cFrequency;
//
si5351.set_freq(cFrequency * 100ULL, SI5351_CLK0);
updateBand();
displayScale();
}
void displayMode() {
if (tx) {
drawRoundTextBox(0, 0, TFT_QUOTER_WIDTH, 15, "TX", COLOR_BRIGHT_RED, COLOR_MEDIUM_RED);
} else {
drawRoundTextBox(0, 0, TFT_QUOTER_WIDTH, 15, "RX", COLOR_BRIGHT_GREEN, COLOR_DARK_GREEN);
}
}
void displayBand() {
if (currentBandIndex == BANDS) {
drawRoundTextBox(TFT_WIDTH - TFT_QUOTER_WIDTH, 0, TFT_QUOTER_WIDTH, 15, "AIR", COLOR_BRIGHT_RED, COLOR_DARK_RED);
} else {
itoa(BandsBounds[currentBandIndex].id, b, 10);
drawRoundTextBox(TFT_WIDTH - TFT_QUOTER_WIDTH, 0, TFT_QUOTER_WIDTH, 15, b, COLOR_BRIGHT_GREEN, COLOR_DARK_GREEN);
}
tft.fillRect(0, SCALE_Y - 2, TFT_WIDTH-1, SCALE_T * 2, ST77XX_BLACK);
}
void drawRoundTextBox(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const char *text, uint16_t c, uint16_t bg) {
tft.fillRoundRect(x, y, w, h, 2, bg);
tft.drawRoundRect(x, y, w, h, 2, c);
int16_t tx, ty; uint16_t tw, th;
tft.getTextBounds(text, x, y, &tx, &ty, &tw, &th);
textxy(x + (w - tw)/2, y + (h - th) / 2 + 1, text, c, bg);
}
void updateBand() {
int i;
for (i = 0; i < BANDS; i++) {
if (cFrequency/1000 >= BandsBounds[i].start && cFrequency/1000 <= BandsBounds[i].start + BandsBounds[i].width) {
if (currentBandIndex != i) {
currentBandIndex = i;
displayBand();
}
break;
}
}
if (i == BANDS && currentBandIndex != i) {
currentBandIndex = i;
displayBand();
}
}
void displayScale() {
tft.drawFastHLine(0, SCALE_Y, TFT_WIDTH-1, COLOR_GRAY_MEDIUM);
tft.drawFastVLine(0, SCALE_Y - 2, 5, COLOR_GRAY_MEDIUM);
tft.drawFastVLine(TFT_WIDTH-1, SCALE_Y - 2, 5, COLOR_GRAY_MEDIUM);
uint16_t fStep = 500; // kHz
uint16_t fStart = 1000; // kHz
uint16_t fWidth = 30000; // kHz
if (currentBandIndex != BANDS) {
fStep = 50;
fStart = BandsBounds[currentBandIndex].start;
fWidth = BandsBounds[currentBandIndex].width;
}
// draw ticks
for (uint32_t f = 0; f < fWidth; f += fStep) {
tft.drawFastVLine( (f * TFT_WIDTH) / fWidth, SCALE_Y, f % (fStep *2) == 0 ? 4 : 2, COLOR_GRAY_MEDIUM);
}
uint16_t newScalePosX = (cFrequency/1000 - fStart) * TFT_WIDTH / fWidth;
if (scalePosX != newScalePosX) {
scaleTriangle(ST77XX_BLACK);
scalePosX = newScalePosX;
scaleTriangle(COLOR_BRIGHT_BLUE);
}
}
void scaleTriangle(uint16_t c) {
tft.fillTriangle(scalePosX, SCALE_Y - 1, scalePosX - SCALE_T, SCALE_Y - SCALE_T - 1, scalePosX + SCALE_T, SCALE_Y - 1 - SCALE_T, c);
}
void textxy(uint8_t x, uint8_t y, const char *text) {
tft.setCursor(x, y);
tft.print(text);
}
void textxy(uint8_t x, uint8_t y, const char *text, uint16_t c) {
tft.setTextColor(c);
textxy(x, y, text);
}
void textxy(uint8_t x, uint8_t y, const char *text, uint16_t c, uint16_t b) {
tft.setTextColor(c, b);
textxy(x, y, text);
}
void displayModulation() {
drawRoundTextBox(TFT_WIDTH - TFT_QUOTER_WIDTH*2, 0, TFT_QUOTER_WIDTH-1, 15, ModeNames[currentMode], COLOR_BRIGHT_BLUE, COLOR_BAND_BACKGROUND);
}
uint32_t p10(uint8_t i) {
if (i < 1) return 1;
return 10 * p10(i - 1);
}
// SETUP -----------------------------------------------------------------------
void setup() {
// put your setup code here, to run once:
pinMode(LED_BUILTIN, OUTPUT);
tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab
tft.fillScreen(ST77XX_BLACK);
tft.setRotation(1);
d = 1;
drawLevel(12);
Serial.begin(9600);
int i2c_found = si5351.init(SI5351_CRYSTAL_LOAD_0PF, 0, 0);
cFrequency = START_F;
setFrequency();
myEnc.write(positionLeft);
setFrequency();
displayModulation();
displayMode();
updateBand();
textxy(0, TFT_HEIGHT / 4, "Frequency:", COLOR_GRAY_MEDIUM, ST77XX_BLACK);
textxy(0, TFT_HEIGHT / 3 * 2 , "Step: ", COLOR_GRAY_MEDIUM, ST77XX_BLACK);
itoa(p10(freqMultiplier-1), b, 10);
textxy(30, TFT_HEIGHT / 3 * 2, b, COLOR_GRAY_MEDIUM, ST77XX_BLACK);
}
// MAIN LOOP ===================================================================
void loop() {
d = analogRead(A0);
if (pd != d) {
itoa(d, b, 10);
tft.setTextColor(COLOR_BRIGHT_BLUE);
textxy(TFT_WIDTH - 30, TFT_HEIGHT-30, b, COLOR_BRIGHT_BLUE, ST77XX_BLACK);
pd = d;
}
long newLeft = myEnc.read();
if (newLeft > positionLeft+2) {
cFrequency-= p10(freqMultiplier-1);
positionLeft = newLeft;
} else if (newLeft < positionLeft-2) {
cFrequency+= p10(freqMultiplier-1);
positionLeft = newLeft;
}
if (oFrequency != cFrequency) {
setFrequency();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment