I have introduced the R909-VFO made by Arduino and Si5351a. To power up it, I changed ATmega328p for ESP32-C3 dev kit on PCB.
I designed the PCB with KiCAD. I uploaded the related data files on the GITHUB.
https://github.com/Nobcha/R909-VFO-ESP
The PCBs' zip are packed by using PCBGOGO plugin.
The reedited sketch of JCR's VFO
ArduinoI reedited JCR's sketch for the new PCB with ESP32-C3 super mini
// 2025.04.02
// Changed to R909-VFO-ESP BAND A1->4, rx_tx A2->D5, AGC A0, TUNE-SW D1
// INT,
// To reduce memory consumption, change code to array reference 20230729
// freq_band[21], bargraph function,
// There are some bugs on startup display and serial message
/**********************************************************************************************************
10kHz to 225MHz VFO / RF Generator with Si5351 and Arduino Nano, with Intermediate
Frequency (IF) offset
(+ or -), RX/TX Selector for QRP Transceivers, Band Presets
and Bargraph S-Meter. See the schematics for
wiring and README.txt for details.
By J. CesarSound - ver 2.0 - Feb/2021.
***********************************************************************************************************/
//Libraries
#include <Wire.h> //IDE Standard
#include <Rotary.h> //Ben Buxton https://github.com/brianlow/Rotary
#include <si5351.h> //Etherkit https://github.com/etherkit/Si5351Arduino
#include <Adafruit_GFX.h> //Adafruit GFX https://github.com/adafruit/Adafruit-GFX-Library
#include <Adafruit_SSD1306.h> //Adafruit SSD1306 https://github.com/adafruit/Adafruit_SSD1306
//User preferences
//------------------------------------------------------------------------------------------------------------
#define IF 0 //Enter your IF frequency, ex: 455 = 455kHz, 10700 = 10.7MHz,
// 0 = to direct convert receiver or RF generator, + will add and - will subtract IF offfset.
#define BAND_INIT 8 //Enter your initial Band (1-21) at startup, 8:10MHz
// ex: 1 = Freq Generator, 2 = 800kHz (MW), 7 = 7.2MHz (40m), 11 = 14.1MHz (20m).
#define XT_CAL_F 147600 //Si5351 calibration factor, adjust to get exatcly 10MHz. Increasing
// this value will decreases the frequency and vice versa.
#define S_GAIN 1010 //Adjust the sensitivity of Signal Meter A/D input: 101 = 500mv; 202 = 1v;
// 303 = 1.5v; 404 = 2v; 505 = 2.5v; 1010 = 5v (max).
#define TUNE_SW 1 // ** The pin used by tune step push button.
#define BAND_SW 4 // ** The pin used by band selector push button. CHANGE A1->A2
#define RXTX_SW 5 // ** The pin used by RX / TX selector switch, RX = switch open, A2->D4
// TX = switch closed to GND. When in TX, the IF value is not considered.
#define AGC A0 // ** The pin used by Signal Meter A/D input.
#define REA 2 //
#define REB 3 //
#define LED_PORT 21
//------------------------------------------------------------------------------------------------------------
// stp = 4; // Frequency step 4:1kHz
Rotary r = Rotary(REA, REB);
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);
Si5351 si5351(0x60); //Si5351 I2C Address 0x60
unsigned long freq, freqold, fstep;
long interfreq = IF, interfreqold = 0;
long cal5351 = XT_CAL_F;
unsigned int smval;
byte encoder = 1; // RE active or inactive
byte fstep_no, tu_ind = 1; // Frequency step 4:1kHz, tu_ind: tune pointer position
unsigned int band_no=1; // band_no: band number
unsigned int s_value, s_value_old;
bool rxtx_sts = 0;
unsigned int period = 100;
unsigned long time_now = 0;
static unsigned long freq_band[21] = {100000, 800000, 1800000, 3650000, 4985000,
6180000, 7200000, 10000000, 11780000, 13630000, 14100000, 15000000, 17655000,
21525000, 27015000, 28400000, 50000000, 100000000, 118000000, 144000000, 220000000} ;
static unsigned long fstep_list[6] = {1,1000,10000,100000,1000000,25000};
static unsigned char fstep_name[6][7] = { " 25kHz"," 1Hz "," 1kHz ", " 10kHz", "100kHz", " 1MHz "};
static unsigned char band_name[21][5] = { "GEN","MW","160m","80m","60m","49m","40m","31m","25m"
,"22m","20m","19m","16m","13m","11m","10m","6m","WFM","AIR","2m","1m"};
void rotary_encoder(){
char re_result = r.process();
if (re_result == DIR_CW) set_frequency(1);
else if (re_result == DIR_CCW) set_frequency(-1);
}
void set_frequency(int dir) {
if (encoder == 1) { //Up/Down frequency
if (dir == 1) freq = freq + fstep;
if (freq >= 225000000) freq = 225000000;
if (dir == -1) freq = freq - fstep;
if (fstep == 1000000 && freq <= 1000000) freq = 1000000;
else if (freq < 10000) freq = 10000;
}
if (encoder == 1) { //Up/Down graph tune pointer
if (dir == 1) tu_ind = tu_ind + 1;
if (tu_ind > 42) tu_ind = 1;
if (dir == -1) tu_ind = tu_ind - 1;
if (tu_ind < 1) tu_ind = 42;
}
}
void setup() {
Wire.begin();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextColor(WHITE);
display.display();
pinMode(REA, INPUT_PULLUP);
pinMode(REB, INPUT_PULLUP);
pinMode(TUNE_SW, INPUT_PULLUP);
pinMode(BAND_SW, INPUT_PULLUP);
pinMode(RXTX_SW, INPUT_PULLUP);
pinMode(LED_PORT, OUTPUT);
digitalWrite(LED_PORT,LOW);
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
si5351.set_correction(cal5351, SI5351_PLL_INPUT_XO);
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
si5351.output_enable(SI5351_CLK0, 1); //1 - Enable / 0 - Disable CLK
si5351.output_enable(SI5351_CLK1, 0);
si5351.output_enable(SI5351_CLK2, 0);
attachInterrupt(REA,rotary_encoder,CHANGE);
attachInterrupt(REB,rotary_encoder,CHANGE);
sei();
band_no = BAND_INIT;
bandpresets(band_no);
fstep_no = 1; // Frequency step 4:1kHz
setstep();
statup_text(); //If you hang on startup, comment
delay(500);
// Serial.begin(9600); //If you hang on startup, comment
// Serial.println(F("\nJA3KPA VFO V1.0")); //If you hang on startup, comment
delay(500);
}
void loop() {
if (freqold != freq) {
time_set(); // time_now = mullis()
tunegen(); // Set 5351 CLK0 as freq
freqold = freq;
}
if (interfreqold != interfreq) {
time_set();
tunegen();
interfreqold = interfreq;
}
if (s_value_old != s_value) {
time_set();
s_value_old = s_value;
}
if (digitalRead(TUNE_SW) == LOW) {
time_delay_set(); // time_now = mullis()+300
setstep();
delay(300);
}
if (digitalRead(BAND_SW) == LOW) {
time_delay_set();
inc_preset();
delay(300);
}
if (digitalRead(RXTX_SW) == LOW){
time_delay_set();
rxtx_sts = 1;
} else rxtx_sts = 0;
if ((time_now + period) > millis()) {
displayfreq();
layout(); // Display edited buffer
}
sgnalread();
}
void time_set(void){
time_now = millis();
}
void time_delay_set(void){
time_now = ( millis()+ 300 );
}
void tunegen() {
si5351.set_freq((freq + (interfreq * 1000ULL)) * 100ULL, SI5351_CLK0);
}
void displayfreq() {
unsigned int m = freq / 1000000;
unsigned int k = (freq % 1000000) / 1000;
unsigned int h = (freq % 1000) / 1;
display.clearDisplay();
display.setTextSize(2);
char buffer[15] = "";
if (m < 1) {
display.setCursor(41, 1);
sprintf(buffer, "%003d.%003d", k, h);
}
else if (m < 100) {
display.setCursor(5, 1);
sprintf(buffer, "%2d.%003d.%003d", m, k, h);
}
else if (m >= 100)
{
unsigned int h = (freq % 1000) / 10;
display.setCursor(5, 1);
sprintf(buffer, "%2d.%003d.%02d", m, k, h);
}
display.print(buffer);
}
void setstep() {
// fstep = fstep_list[fstep_no-1];
switch (fstep_no) {
case 1: fstep = fstep_list[0]; break;
case 2: fstep = fstep_list[1]; break;
case 3: fstep = fstep_list[2]; break;
case 4: fstep = fstep_list[3]; break;
case 5: fstep = fstep_list[4]; break;
case 6: fstep = fstep_list[5]; break;
}
fstep_no++;
if(fstep_no>=7) fstep_no=1;
}
void inc_preset() {
band_no++;
if (band_no > 21) band_no = 1;
bandpresets(band_no);
delay(50);
}
void bandpresets(unsigned int band_count) {
// freq = freq_band[band_count-1];
switch (band_count){
case 1: freq = freq_band[0]; tunegen(); break;
case 2: freq = freq_band[1]; break;
case 3: freq = freq_band[2]; break;
case 4: freq = freq_band[3]; break;
case 5: freq = freq_band[4]; break;
case 6: freq = freq_band[5]; break;
case 7: freq = freq_band[6]; break;
case 8: freq = freq_band[7]; break;
case 9: freq = freq_band[8]; break;
case 10: freq = freq_band[9]; break;
case 11: freq = freq_band[10]; break;
case 12: freq = freq_band[11]; break;
case 13: freq = freq_band[12]; break;
case 14: freq = freq_band[13]; break;
case 15: freq = freq_band[14]; break;
case 16: freq = freq_band[15]; break;
case 17: freq = freq_band[16]; break;
case 18: freq = freq_band[17]; break;
case 19: freq = freq_band[18]; break;
case 20: freq = freq_band[19]; break;
case 21: freq = freq_band[20]; break;
}
si5351.pll_reset(SI5351_PLLA);
fstep_no = 4; // Frequency step 4:1kHz n: tune pointer position
setstep();
}
void layout() {
display.setTextColor(WHITE);
display.drawLine(0, 20, 127, 20, WHITE);
display.drawLine(0, 43, 127, 43, WHITE);
display.drawLine(105, 24, 105, 39, WHITE);
display.drawLine(87, 24, 87, 39, WHITE);
display.drawLine(87, 48, 87, 63, WHITE);
display.drawLine(15, 55, 82, 55, WHITE);
display.setTextSize(1);
display.setCursor(59, 23);
display.print("STEP");
display.setCursor(54, 33);
//char disp_buff[7];
//strcpy(disp_buff,fstep_name[fstep_no-1]);
//display.print(disp_buff);
// /*
if (fstep_no == 2) display.print(" 1Hz");
if (fstep_no == 3) display.print(" 1kHz");
if (fstep_no == 4) display.print(" 10kHz");
if (fstep_no == 5) display.print("100kHz");
if (fstep_no == 6) display.print(" 1MHz");
if (fstep_no == 1) display.print("25kHz");
// */
display.setTextSize(1);
display.setCursor(92, 48);
display.print("IF:");
display.setCursor(92, 57);
display.print(interfreq);
display.print("k");
display.setTextSize(1);
display.setCursor(110, 23);
if (freq < 1000000) display.print("kHz");
if (freq >= 1000000) display.print("MHz");
display.setCursor(110, 33);
if (interfreq == 0) display.print("VFO");
if (interfreq != 0) display.print("L O");
display.setCursor(91, 28);
if (!rxtx_sts) display.print("RX");
if (!rxtx_sts) interfreq = IF;
if (rxtx_sts) display.print("TX");
if (rxtx_sts) interfreq = 0;
bandlist();
drawbargraph();
display.display();
}
void bandlist() {
display.setTextSize(2);
display.setCursor(0, 25);
// char disp_buff[4];
// strcpy(disp_buff,band_name[band_no-1]);
// display.print(disp_buff);
if (band_no == 1) display.print("GEN");
if (band_no == 2) display.print("MW");
if (band_no == 3) display.print("160m");
if (band_no == 4) display.print("80m");
if (band_no == 5) display.print("60m");
if (band_no == 6) display.print("49m");
if (band_no == 7) display.print("40m");
if (band_no == 8) display.print("31m");
if (band_no == 9) display.print("25m");
if (band_no == 10) display.print("22m");
if (band_no == 11) display.print("20m");
if (band_no == 12) display.print("19m");
if (band_no == 13) display.print("16m");
if (band_no == 14) display.print("13m");
if (band_no == 15) display.print("11m");
if (band_no == 16) display.print("10m");
if (band_no == 17) display.print("6m");
if (band_no == 18) display.print("WFM");
if (band_no == 19) display.print("AIR");
if (band_no == 20) display.print("2m");
if (band_no == 21) display.print("1m");
if (band_no == 1) interfreq = 0;
else if (!rxtx_sts) interfreq = IF;
}
void sgnalread() {
smval = analogRead(AGC);
s_value = map(smval, 0, S_GAIN, 1, 14);
if (s_value > 14) s_value = 14;
}
void drawbargraph() {
byte tu_pos = map(tu_ind, 1, 42, 1, 14);
display.setTextSize(1);
//Tune indicator pointer
display.setCursor(0, 48);
display.print("TU");
byte t_pos = 15+5*(tu_pos-1);
display.fillRect(t_pos, 48, 2, 6, WHITE);
// S-meter displaying
display.setCursor(0, 57);
display.print("SM");
for ( int xx = s_value; xx >= 0; xx--){
byte s_pos = 15+5*(xx-1);
display.fillRect(s_pos, 58, 2, 6, WHITE);
}
}
void statup_text() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(13, 18);
display.print(F("Si5351 VFO/RF GEN"));
display.setCursor(13, 40);
display.print(F("KPA lab. V1.1 @JCR"));
display.display();
delay(4000);
}
The diagnostic sketch for R909-VFO-ESP
ArduinoThis one is useful for checking after assembling the PCB. The sketch reports the i2c address chained and the switches status.
// 2025.03.30 i2c scan, RE
// Report the connected i2c address.
// If sw turning on, reporting SW name and ADC value or RE count.
// For R909-VFO ESP32-C3 mini
// To test the OLED display and SW1 responce
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include<Rotary.h> // Mr Ben buxton's INT
#define ENC_A 2 // R909-VFO-ESP Rotary encoder A port
#define ENC_B 3
Rotary r = Rotary(ENC_A,ENC_B);
#define RE_SW 4 // R909-VFO-ESP RE-SW port
#define PIN_SDA 8 // ESP32-C3 mini SDA
#define PIN_SCL 9 // ESP32-C3 mini SCL
#define ADC_port 1 // R909-VFO-ESP SW port
#define led_port 21 // R909-VFO-ESP LED port
int onoff = 0;
byte error, address;
int nDevices;
boolean led_status;
char charbuf[6];
int re_cnt = 0; // RE +/- counter
int cnt = 0;
#define SCREEN_WIDTH 128 // SSD1306 resolution
#define SCREEN_HEIGHT 64 // SSD1306 resolution
#define OLED_RESET -1 // Set -1 for no use
#define SCREEN_ADDRESS 0x3C // 0x3C
Adafruit_SSD1306 display = Adafruit_SSD1306(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //
void setup()
{
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
for(;;); // If no responce , wait for ever
}
r.begin();
attachInterrupt(ENC_A,rotary_encoder,CHANGE);
attachInterrupt(ENC_B,rotary_encoder,CHANGE);
Serial.begin(9600);
display.clearDisplay(); // Display clear at first
display.display(); // To kick displaying
pinMode(led_port, OUTPUT);
pinMode(RE_SW, INPUT);
display.setTextSize(1); // select second size of font
display.setTextColor(SSD1306_WHITE); // default
display.setCursor(5, 0); // the starting point of character of bit position
display.print("R909-VFO"); // the banner
display.print(" i2c TEST");
delay(2000);
}
void loop()
{
Serial.println("i2c Scanning start");
digitalWrite(led_port, led_status);
led_status = !led_status;
delay(1000);
display.setCursor(0, 15);
display.print("i2c scan");
display.display();
display.setCursor(0, 32);
display.print(" AD:");
display.display();
nDevices = 0;
cnt = 0;
for(address = 1; address < 127; address++ )
{
// Check WIRE function return back result
// The value of Write.endTransmisstion
// Is there ACK response (yes:0 or no
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) // Got response
{
Serial.print("i2c device found at address 0x");
if (address<16) Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
sprintf(charbuf, "%02X", address );
cnt++;
display.setCursor(cnt*36, 32);
display.print(charbuf);
display.print(",");
display.display();
nDevices++;
}
else if (error==4)
{
Serial.print("Unknown error at address 0x");
if (address<16) Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
{
Serial.println("No i2c devices found\n");
display.setCursor(0, 49);
display.print("No devices");
display.display();
}
else{
Serial.println("done\n");
display.setCursor(cnt*15, 49);
display.print("Done");
display.display();
}
delay(2000); // Wait 2 sec
display.clearDisplay();
display.display(); // To kick displaying
digitalWrite(led_port, onoff++%2);
delay(500);
int sw_adc;
if ( (sw_adc = analogRead( ADC_port)) < 4000) {
display.clearDisplay();
display.setCursor(0, 0); // the starting point of character of bit position
if(sw_adc < 50) display.print("SW1 on");
else display.print("SW2 on"); // SW2
display.print(sw_adc);
display.display(); // To display
delay(1000);
}
if( digitalRead(RE_SW) == 0){
display.clearDisplay();
display.setCursor(0, 0); // the starting point of character of bit position
display.print("RE SW on ");
display.print(re_cnt);
display.display(); // To display
delay(1000);
}
}
void rotary_encoder(){
unsigned char result = r.process();
if(result){
if(result == DIR_CW){
re_cnt++;
Serial.println("Right");
}
else{
re_cnt--;
Serial.println("Left");
}
}
}
The original functions of R909-VFO
ArduinoR909-VFO is providing 10kHz-220MHz signal with the rotary encoder operation. The 50 channel memories are available.
// 2025.04.06 releases 10kHz-220MHz V3 for ESP-C3 mini dev kit
// Changed INT, EEPROM, RE,and SW for ESP-C3 super mini dev kit
// 2025.03.03 temporary releases 100kHz-200MHz V2
// Initilising as 10MHz for memory channels
// No LO mode, F-COR @ STEP 50ch memories 79%/28%
// Step coverage 1,10,100,1kHz,10kHz,100kHz,1MHz,25kHz
// F_COR step 1,10,100,1kHz for 25MHz OSC
//
// --=----=----=----=----=----=----=----=----=----=----=----=----
// R909-VFO V1.0 20240531
// --=----=----=----=----=----=----=----=----=----=----=----=----
// R909-SDR-OLED Ver3.2 20240204
// Rotary switch:INT(D2,D3), RE-SW:A2, Function switch1,2: A0,
// Si4732: 0x11, Reset: D17, PU2CLR LIB, Si5351a: 0x60, TJ lab
// OLED: 0x3C, ADA fruits, ATmega328P with bootloader
//
// si5351a ARDUINO LO Ver3.0 (LCD&KEY, i2c SSD1306 LCD, Timer
// Rotary switch:INT(D2,D3), Function switch: D4 port, Squelch:A3
// Si5351_ADDR = 0x60, CPU:Arduino PRO mini, LCD: SSD1306:
// --=----=----=----=----=----=----=----=----=----=----=----=----
//Libraries definition
#include <EEPROM.h>
#include <Wire.h>
#include <si5351.h>
// https://github.com/etherkit/Si5351Arduino/tree/master/src/si5351.h
// #define SI5351_FREQ_MULT 100ULL
Si5351 si5351;
//////// OLED SSD1306 ////
// Thanks Adafruit for providing the library of OLED SSD1306
//Adafruit GFX https://github.com/adafruit/Adafruit-GFX-Library
//Adafruit SSD1306 https://github.com/adafruit/Adafruit_SSD1306
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);
// --=----=----=----=----=----=----=----=----=----=----=----=----
// PORTs assign
#define REA 2 // D2 2 Rotary encode A
#define REB 3 // D3 3 B
#define RESW 4 // Rotary encoder push switch 4
#define FUNC_SW 1 // SW1:<80, SW2:<250, (SW3:<430, SW4:<600)
#define AGC_PORT A0
#define SQLMUTE 4 // digital output for SQUELCH
// to mute LM386 AMP when no signal
#define led_pin 21 // Orange LED on panel
// --=----=----=----=----=----=----=----=----=----=----=----=----
unsigned long int startF = 78000000; // Japanese FM starting F
unsigned long int interfreq1 = 21400000; // 21.40Mhz
unsigned long int interfreq = 0; // 0Mhz
unsigned long int interfreq3 = 455000; // 455khz
int freq_correction = 0; // Correction Hz for 25MHz
// Rotary encoder handler for arduino. v1.1
// Copyright 2011 Ben Buxton.
// Licenced under the GNU GPL Version 3. Contact: bb@cactii.net
// http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
// Rotary encoder test debug sketch
// PWM/3: Rotary A --> D2
// PWM/2: Rotary B --> D3
// GND: C
#include <Rotary.h>
#define HALF // better
Rotary r = Rotary(REA, REB);
// --=----=----=----=----=----=----=----=----=----=----=----=----
// Assign function number 1-9 for short pushing at FUNCTION mode
// long pushing at 1:FREQ -> 11:FREQSET, 2:STEP-> 12:STEPSET
// 3:MEMORY-> 13:MMEMORYPUT, 4:SCAN->14:SCANAUTO,
// 5:VOLUME&6:SQUELCH&7:BAND&8:BAND_W&9:F_COR->11:FREQSET
//
// 14 modes defined 0:NONE,1:FREQ,2:STEP,3:MEMORY,4:SCAN,5:VOLUME,
// 6:SQUELCH,7:BAND,8:BAND_W,9:F_COR,10:FUNCTION,11:FREQSET,
// 12:STEPPUT,13:MEMORYPUT,14:SCANAUTO,
// STATE 1:FR,2:ST,3:ME,4:SC,5:vol,6:squ,7:band,8:band_w,9:F_COR,10:func
// STATE+RE -> parameter increase/decrease
#define NONE 0 //
#define FREQ 1
#define STEP 2
#define MEMORY 3
#define SCAN 4
#define VOLUME 5
#define SQUELCH 6
#define BAND 7 // AM/FM SELECTION
#define FUNCTION 10
#define FREQSET 11 // double push for FREQ set
#define STEPPUT 12 // double push for STEP set
#define MEMORYPUT 13 // double push for memory F set
#define SCANAUTO 14 // double push for Automatic SCAN set
#define BAND_W 8 // band width select
#define F_COR 9 // frequency error correction value inc/dec
// EEPROM Address
#define FREQ_AD 0 // EEPROM address for FREQ data as long
#define FSTEP_AD 4 // EEPROM address for FSTEP data as long
#define MCHAN0 8 // MCHAN start ADD, MCHAN0 + 4 * chan chan: 0- 50
#define VOL_AD 400 // EEPROM ADDRESS for stored volume
#define SQU_AD 404 // EEPROM address for squelch setting
#define BAND_AD 408 // EEPROM ADDRESS for band
#define previous_freqAM_AD 412 // EEPROM ADDRESS for previous_freqAM
#define BAND_W_AD 418 // EEPROM ADDRESS for BAND width
#define F_COR_AD 422 // frequency error correction value
// --=----=----=----=----=----=----=----=----=----=----=----=----
//
#define Time_elapsedRSSI 300 // RSSI check period mS
// Band AM or FM at Si4732
// #define AM_FUNCTION 1
// #define FM_FUNCTION 0
// --=----=----=----=----=----=----=----=----=----=----=----=----
// functions
void FUNC_Disp ( char*); // cursor(0,23)
void Step_Disp(void);
void Freq_Disp(void);
void s_meter_Disp(void);
void clearLCDLine (int, int, int);
void layout();
void drawbargraph(void);
void startup_text(void);
void sprintfreq(char*, int, int, int);
void LongToStr(long , char*);
void Fdds_Space(char *);
void send_frequency(long, int);
void set_freq(unsigned long); // Call ETHERKIT ribrary
void setstep();
int function_key(void);
int mode_define(unsigned char) ;
void rotary_event(uint8_t);
void TimerCount(void);
void blink(long, long);
void putFirstSettings(void) ;
void ShowSettings(void);
void getSettings(void);
void freqEEPROMput(int, long*); //EEPROM
void freqEEPROMget(int, long); //EEPROM
// --=----=----=----=----=----=----=----=----=----=----=----=----
// variables
boolean if_mode = 1; // 1LO mode FREQ being LO above
volatile int mode = FUNCTION; // current mode
// When mode is FUNCTION, mode_temp is candidate to be selected
// by click. Blinking FUNC & mode_temp candidate.
volatile char mode_last = FREQ; // last time mode as FREQ
volatile char mode_temp = FREQ; // candidate
volatile int memo_ad = 0; // select memory address
unsigned char set_sw = 1; // set freq on memory, or step to freq
volatile unsigned long int freq1, freq0, freq_0, freq_last;
// volatile unsigned long int previous_freqFM = 80200000; // FM802 in OSAKA
volatile unsigned long int previous_freqAM = 118100000; // ITM TOWER
volatile unsigned long int fstep ;
int fstep_idx=5; // 1-6
int bandAM_idx=0; // 0-6
volatile unsigned long int_time = 0 ;
volatile unsigned long time0 = 0;
volatile unsigned long time1 = 0;
volatile long Last_millis;
int Timer_LED = 1000;
int Timer_mash_i = 500;
int Timer_mash = 0;
int Timer_RESW_i = 50;
int Timer_RESW = -1;
int Timer_scan = -1;
int Timer_DISP_REF = 50;
int Timer_Mem_Write = 500;
int Timer_Mem_Write1 = 500;
volatile boolean Mem_Write1=0;
volatile boolean j, k; // led/LCD blinking status
volatile int ADCdata;
volatile int scan_ad = 0, scan_ad_last=0; // scanning address counter
volatile int i = 0;
volatile unsigned int re_result = 0; // Rotary switch activated
//result 0x10:right,0x20:left
volatile unsigned int result;
// --=----=----=----=----=----=----=----=----=----=----=----=----
// 0:no,1:FR,2:ST,3:ME,4:SC,5:vol,6:squelch,7:band,8:band_w,9:F_cor,10:func
char freqdisp[5] = { 0x46, 0x52, 0x45, 0x51, 0 }; // To display FRQ mode = 1
char stepdisp[5] = {0x53, 0x54, 0x45, 0x50, 0 }; // To display STP mode = 2
char mdisp[6] = {0x4d, 0x45, 0x4d, 0x30, 0x30 ,0}; // To display MEM number as mode = 3
char scandisp[6] = { 0x53, 0x43, 0x4e, 0x30 , 0x30 , 0 };// To display SCA channel mode = 4
char ascandisp[6] = {0x41, 0x53, 0x41, 0x30, 0x30 , 0 }; // To display ASA(Automatic scanning) mode = 14
char voldisp[6] = {0x56, 0x4f, 0x4c, 0x30 ,0x30 , 0}; // To display VOL mode = 5
char squdisp[6] = {0x53, 0x51, 0x55, 0x30 ,0x30 , 0}; // To display SQU SQUELCH LEVEL mode = 6
char banddisp[5] = {0x42, 0x41, 0x4e, 0x44, 0 }; // To display BAND mode = 7
char funcdisp[5] = { 0x46, 0x55, 0x4e, 0x43, 0 }; // To display FUNC mode = 10
char b_wdisp[6] = {0x42, 0x20, 0x57, 0x30 ,0x30 , 0}; // To display band width = 8
char f_erdisp[6] = {"F_COR"}; // To display Si5351a freq error correction = 9
char spdisp[6] = { 0x20, 0x20, 0x20, 0x20, 0x20, 0 }; // SPACE
char eachdisp[8] = { 0, 0, 0, 0, 0, 0,0,0 };
// const char *bandwidthAM[]={"6","4","3","2","1","1.8","2.5"};
boolean RESW_last = 1;
boolean RESW_value_last = 1;
boolean RESW_pending = 0;
int RESW_result_p;
volatile unsigned int SW_result = 0; // no:0, one click:2, double click:3
volatile unsigned int SW_result0 = 0;
volatile unsigned int sw_value, sw_stat;
int func_sw_value;
// int VolumeLevel = 15, last_VolumeLevel = 15; //
// uint8_t vl_pos, vl_ind;
// uint8_t sq_pos, sq_ind;
// int SquelchLevel = 0, last_SquelchLevel = 0; //
boolean BandSelect = true, BandSelect_last= true; // am/fm:false
boolean last_BandSelect = true; // am:true/fm:false
// LCD SECOND LINE DOUBLE USE
boolean valid = false;
unsigned long previousMillis = 0;
const long interval = 5000; //5 seconds
unsigned long elapsedRSSI;
// for squelch audio detection
int val = 0;
int timer = 0;
int maxi = 0;
unsigned int s_value;
boolean s_dot_disp = 0;
unsigned int rssi, snr;
int ascan_hold = 0;
int debug=0,state1=0, state2=0; // Debug counter
void rotary_encoder(){
re_result = r.process();
}
// --=----=----=----=----=----=----=----=----=----=----=----=----
// --------------------------------------------------------------
// Power up setting section
void setup() {
// setup EEPROM handling
EEPROM.begin(430); // For ESP32 EEPROM service
// to configure a mode of the pins
pinMode(led_pin, OUTPUT); // monitor LED
digitalWrite( led_pin, 1 ); // LED on
pinMode(REA, INPUT_PULLUP); // Rotary encoder port
pinMode(REB, INPUT_PULLUP); //
pinMode(RESW, INPUT_PULLUP); // Rotary encoder push SW
delay(200);
// i2c starts up and SSD1306 sets up
Wire.begin();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextColor(WHITE);
attachInterrupt(REA,rotary_encoder,CHANGE);
attachInterrupt(REB,rotary_encoder,CHANGE);
// Opening message
display.setTextSize(2);
display.setCursor(0, 25);
display.print(F("R909-VFOV2"));
display.setCursor(92, 48);
display.print(F("kpa "));
display.display();
delay(200);
/////// Switch sence ////////////////////////////////////////////////////////
SW_result0 = function_key(); // Freq mode set on power start
if (SW_result0 == 0) if_mode = 1; // When no action, set IF_mode for LO
r.begin(true); // rotary encoder initialise
Last_millis = millis();
delay(50);
// EEPROM data recover for clock frequency data
// There are FREQ, FSTEP, and MCHAN0-9
freqEEPROMget( FREQ_AD, freq1); // FREQ data recover from EPROM
freq_0 = freq1;
// *************************************
EEPROM.get( FSTEP_AD, fstep_idx); // fstep data from EEPROM Read EEPROM
setstep();
EEPROM.get( BAND_AD, BandSelect); // band data recover from EPROM EEPROM
EEPROM.get( previous_freqAM_AD, previous_freqAM ); // EEPROM
EEPROM.get( F_COR_AD,freq_correction);
int d = digitalRead(RESW); // If RESW is ON at starting up,
if (d == 0) { // EEPROM initialised
putFirstSettings();
}
// getSettings();
Freq_Disp(); // display freq
freq_0 = freq1 + interfreq;
// si5351_init(); // initialise the si5351
if (freq1 < 100000 || freq1 > 200000000) { //100kHz-200MHz
freq1 = 10000000;
putFirstSettings();
EEPROM.put( FREQ_AD, freq1); // FREQ data 10MHz for EPROM EEPROM
EEPROM.commit(); // Fro ESP32 EEPROM service
freq_0 = 118100000; // changed 118.1MHz AM
for ( memo_ad = 0 ; memo_ad < 50; memo_ad++ ) {
EEPROM.put( FREQ_AD + 8 + memo_ad * 4, freq_0); // FREQ data 118.1MHz for eEPROM EEPROM
EEPROM.commit(); // Fro ESP32 EEPROM service
}
}
delay(500);
// Set CLK0
si5351.set_ms_source(SI5351_CLK1, SI5351_PLLA);
si5351.set_ms_source(SI5351_CLK0, SI5351_PLLB);
si5351.set_ms_source(SI5351_CLK2, SI5351_PLLB);
// correct_si5351a();
si5351.update_status();
// The calibration method is called below:
si5351.set_correction(freq_correction, SI5351_PLL_INPUT_XO);
si5351.set_freq(freq1 * SI5351_FREQ_MULT, SI5351_CLK0);
if(fstep_idx<1 | fstep_idx>8){
display.setTextSize(2);
display.setCursor(0, 0);
display.print(F("STP Err")) ;
display.display();
delay(1000);
fstep = 100000;
EEPROM.put( FSTEP_AD, fstep_idx ); // fstep data 100kHz for EEPROM
EEPROM.commit(); // Fro ESP32 EEPROM service
EEPROM.put( F_COR_AD,0);
EEPROM.commit(); // Fro ESP32 EEPROM service
delay(200);
}
digitalWrite( led_pin,0 ); // off
// Set up INT function for RE
re_result = 0;
layout();
if (if_mode == 1) freq_0 = freq1 + interfreq ; // On IF mode FREQ must be
else freq_0 = freq1; // upper than RX FREQ
// starting VFO
SI_setfreq( freq_0 );
// *************************************
// debug print out
/* Serial.print("j: "); // LCD blinking status
Serial.println(j);
Serial.print("mode: ");
Serial.println(mode);
Serial.print("mode_temp: ");
Serial.println(mode_temp);
Serial.print("SW_result: ");
Serial.println(SW_result);
Serial.print("SW_result0: ");
Serial.println(SW_result0);
Serial.print("freq1: ");
Serial.println(freq1);
*/
// To inform the end of starting up
display.setTextSize(2);
display.setCursor(0, 0);
display.print(F("START"));
display.display();
delay(2000);
// Once erase screen
display.clearDisplay();
}
// End of setup
// --=----=----=----=----=----=----=----=----=----=----=----=----
//==========================MAIN=================================
void loop() {
TimerCount(); // To manage timer counter
// digitalWrite(led_pin, 0); // To turn off LED
// Basic function for timer control led on_off & LCD blink
blink(800, 500); // Blinking for monitor LED and FUNC display on OLED
// Check SW action
SW_result = function_key(); // Get RESW result(on:50mS push) SW_result == 1
SW_result0 = mode_define(SW_result); // Define SW status 0:no, 1:single, 2:double
// RE push switch to FUNC mode, push switch again to each mode
if (SW_result0 == 1) {
if (mode != FUNCTION) { // Go into FUNC mode
mode_last = mode;
mode = FUNCTION; // 0:no,1:FR,2:ST,3:ME,4:SC,5:vol,6:squelch,7:Band,
// 8:band width,9:Frequency correction,
// 10:func,11:FSet,12:STSet,13:MWrite,14:AScan,
// 15:band w set, 16:F COR set
}
else { // If FUNC, every click goes each FUNC defined
mode_last = mode;
mode = mode_temp;
}
}
if ( SW_result0 == 2 ) { // select double click
mode_last = mode_temp; // double push
// To define mode by RE double push switching **********
// long pushing at 1:FREQ -> 11:FREQSET, 2:STEP-> 12:STEPSET
// 3:MEMORY-> 13:MMEMORYPUT, 4:SCAN->14:SCANAUTO,
// 5:VOLUME&6:SQUELCH&7:BAND&8:BAND_W,9:F_COR->11:FREQSET
switch (mode) {
case FREQ:{
mode = FREQSET; // freq, vol, squ and band set
break;
}
case STEP:{
mode = STEPPUT; // STP set
break;
}
case MEMORY:{
mode = MEMORYPUT; // Memory set
break;
}
case SCAN:{
mode = SCANAUTO; // Automatic scanning
break;
}
case VOLUME:{
mode = FREQSET; // freq, vol, squ and band set
break;
}
case SQUELCH:{
mode = FREQSET; // freq, vol, squ and band set
break;
}
case BAND:{
mode = FREQSET; // freq, vol, squ and band set
break;
}
case BAND_W:{
mode = FREQSET; // freq, vol, squ and band set
break;
}
case F_COR:{
mode = FREQSET; // freq, vol, squ and band set
break;
}
default:
mode = FUNCTION; // Go back to FUNC
}
}
// end of sw action
// Rotary encoder service
if (re_result != 0) { // If CW, re_result is 0x10, if CCW, 0x20.
rotary_event(re_result); // To start the concerning process
re_result = 0;
}
// process depended on mode
switch ( mode ) {
case FUNCTION: { // function mode is 12
if (j == 0) { // boolean j led blink state
switch ( mode_temp ) {
case FREQ: { // FREQ determining mode 1
sprintf(eachdisp, freqdisp);
break;
}
case STEP: { // STEP select mode 2
sprintf(eachdisp, stepdisp);
break;
}
case VOLUME: { // volume select mode 9 !corrupsed
sprintf(eachdisp, freqdisp); // voldisp->freqdisp
break;
}
case SQUELCH: { // squelch select mode 10 !corrupsed
sprintf(eachdisp, freqdisp); // squdisp->freqdisp
break;
}
case BAND: { // band select mode 11
sprintf(eachdisp, freqdisp); // squdisp->freqdisp
break;
}
case MEMORY: { // MEMORY ch select mode 3
sprintf(eachdisp, mdisp);
break;
}
case SCAN: { // SCAN select mode 4
sprintf(eachdisp, scandisp) ;
break;
}
case BAND_W: { // BAND width select mode 8
sprintf(eachdisp, freqdisp) ; // b_wdisp->freqdisp
break;
}
case F_COR: { // VFO error correction value 9
sprintf(eachdisp, f_erdisp) ;
break;
}
// next were added later
default: sprintf(eachdisp, funcdisp); // Function select mode 10
}
}
if (j == 1) sprintf(eachdisp, funcdisp); // LCD display alternated
} // end of process for FUNCTION
break;
case FREQ: { // FREQ determining mode 1
sprintf(eachdisp, freqdisp ) ;
break;
}
case STEP: { // STEP select mode 2
sprintf(eachdisp, stepdisp ) ;
break;
}
case VOLUME: { // volume select mode 5
break;
}
case SQUELCH: { // squelch select mode 6
break;
}
// band
case BAND: { // band select mode 7
break;
}
case MEMORY: { // MEMORY ch select mode 3
mdisp[3] = 0x30 | (memo_ad / 10) ;
mdisp[4] = 0x30 | (memo_ad % 10) ;
sprintf(eachdisp, mdisp) ; //
break;
}
case SCAN: { // Manual step SCAN mode 4
// fm mode to be added
scandisp[3] = 0x30 | (scan_ad / 10) ; // display scan chan
scandisp[4] = 0x30 | (scan_ad % 10) ;
sprintf(eachdisp, scandisp ) ;
freqEEPROMget( MCHAN0 + scan_ad * 4, freq1); // read out MEM frequency
if (freq_last == freq1) break;
// Freq_Disp();
freq_0 = freq1 ;
// FREQ is more than IF above IF frequency for RX FREQ
if (if_mode == 1) freq_0 = freq1 + interfreq ;
freq_last = freq1 ;
if(BandSelect == false) { // If FM mode,
}
else {
send_frequency(freq_0, 0); //send it to si5351
}
break;
}
case BAND_W: { // BAND width select mode 8
break;
}
case F_COR: { // VFO error correction value 9
sprintf(eachdisp, "%5d", freq_correction) ;
break;
}
case FREQSET: { // FREQ button long push
sprintf(eachdisp, freqdisp) ; // freq display
freq0 = freq1;
if(BandSelect == false) freq0 = -freq1; // If FM, convert to negative
EEPROM.put( FREQ_AD, freq0 ); // freq data into EEPROM
EEPROM.commit(); // Fro ESP32 EEPROM service
EEPROM.put( F_COR_AD,freq_correction);// Frequency error correction value
EEPROM.commit(); // Fro ESP32 EEPROM service
EEPROM.put( previous_freqAM_AD, previous_freqAM ); //
EEPROM.commit(); // Fro ESP32 EEPROM service
mode = FREQ;
break;
}
case STEPPUT: { // STEP written
sprintf(eachdisp, stepdisp) ;
if(Timer_Mem_Write<=0 && Mem_Write1==0){
sprintf(eachdisp, spdisp) ; //
EEPROM.put( FSTEP_AD, fstep_idx ); // fstep data of 100kHz unit in EEPROM
EEPROM.commit(); // Fro ESP32 EEPROM service
Timer_Mem_Write=800;
Mem_Write1=1;
}
if(Timer_Mem_Write>0 && j==1){
sprintf(eachdisp, spdisp) ; // 2nd line 1st character step display
}
if(Timer_Mem_Write<=0){
mode = FREQ;
Mem_Write1=0;
}
break;
}
case MEMORYPUT: { // MEMORY write
sprintf(eachdisp, mdisp) ; //
freq0 = freq1;
if( BandSelect == false) freq0 = -(freq1);
EEPROM.put( MCHAN0 + memo_ad * 4, freq0); // Write FREQ on defined EEPROM
EEPROM.commit(); // Fro ESP32 EEPROM service
display.clearDisplay();
sprintf(eachdisp, spdisp) ; // line 2 first column is space
layout();
display.clearDisplay();
sprintf(eachdisp, mdisp) ; // line 2 first column is m
layout();
display.clearDisplay();
mode = FREQ;
break;
}
case SCANAUTO: { // AUTO SCAN mode from M-chan
if (Timer_scan <= 0) { // If timer up
scan_ad++;
Timer_scan = 1000;
ascandisp[3] = 0x30 | (scan_ad / 10) ; // display scan chan
ascandisp[4] = 0x30 | (scan_ad % 10) ; // display scan chan
sprintf(eachdisp, ascandisp ) ;
freqEEPROMget( MCHAN0 + scan_ad * 4, freq1); // read out MEM frequency
//Changed 20201013
if (scan_ad > 49) scan_ad = 0;
if(BandSelect == false ){ // If FM, skip FM freq
BandSelect = true;
Timer_scan = 0;
break;
}
Freq_Disp();
// Band_setting();
if (if_mode == 1) freq_0 = freq1 + interfreq ; //
send_frequency(freq_0, 0); //send it to si5351
state2 = s_value;
s_meter_Disp(); // Get AGC voltage & change S-meter
}
break;
}
}
// S METER & squelch
// CHECK TIMER FOR TIMEOUT
if (( millis() - elapsedRSSI ) > Time_elapsedRSSI ){ // 300ms
s_meter_Disp();
elapsedRSSI = millis();
}
// SW1:<320, SW2:<1000, (SW3:<1720, SW4:<2400 )
// actual
// This set keeps 2 keys of SW1 & SW2
func_sw_value = analogRead(FUNC_SW);
if (func_sw_value < 900) {
sw_stat = 1;
if (func_sw_value>320) sw_stat = 2;
switch ( sw_stat){
case 1:
mode = FREQ; // freq mode 0
break;
case 2:
mode = SCAN; // SCAN mode 4
break;
}
}
// display
if(Timer_DISP_REF<=0){ // Periodic display timer expired
digitalWrite(led_pin, k=!k);
Freq_Disp();
layout();
display.clearDisplay();
Timer_DISP_REF = 500; // Display every 500mS
}
}
//end of loop
// --=----=----=----=----=----=----=----=----=----=----=----=----
// **************************************************************
// ************************************
// FUNCTIONs
// ************************************
//
void getSettings() {
freqEEPROMget( FREQ_AD, freq1); // freq1:FREQ data recover from EPROM
// freq0:as AM:+, FM:- freq1:absolute
// When freq0 is minus, Bandselect becomes false:FM
EEPROM.get( FSTEP_AD, fstep_idx); // fstep data from EEPROM Read
setstep();
// EEPROM.get( VOL_AD, VolumeLevel); // volume data recover from EPROM
// EEPROM.get( SQU_AD, SquelchLevel);// squelch data from EEPROM Read
EEPROM.get( BAND_AD, BandSelect); // band data recover from EPROM
EEPROM.get( F_COR_AD,freq_correction);
// EEPROM.get( BAND_W_AD, bandAM_idx); // band with index recover from EPROM
// EEPROM.get( previous_freqFM_AD, previous_freqFM ); //
EEPROM.get( previous_freqAM_AD, previous_freqAM ); //
}
//
void putFirstSettings() {
freq0 = freq1;
if( BandSelect == false) freq0 = -(freq1);
EEPROM.put( FREQ_AD, freq0); // FREQ data 100MHz for EPROM
EEPROM.commit(); // Fro ESP32 EEPROM service
// freqEEPROMput(FREQ_AD, freq1); // Put freq1 + BAND on EEPROM
EEPROM.put( FSTEP_AD, fstep_idx); // fstep data from EEPROM Read
EEPROM.commit(); // Fro ESP32 EEPROM service
// EEPROM.put( VOL_AD, VolumeLevel); // volume data recover from EPROM
// EEPROM.put( SQU_AD, SquelchLevel); // squelch data from EEPROM Read
EEPROM.put( BAND_AD, BandSelect); // band data recover from EPROM
EEPROM.commit(); // Fro ESP32 EEPROM service
EEPROM.put( F_COR_AD,freq_correction);
EEPROM.commit(); // Fro ESP32 EEPROM service
// EEPROM.put( BAND_W_AD, bandAM_idx); // band with index recover from EPROM
// EEPROM.put( previous_freqFM_AD, previous_freqFM ); //
EEPROM.put( previous_freqAM_AD, previous_freqAM ); //
EEPROM.commit(); // Fro ESP32 EEPROM service
freq_0 = 10000000;
for ( memo_ad = 0 ; memo_ad < 50; memo_ad++ ) {
EEPROM.put( FREQ_AD + 8 + memo_ad * 4, freq_0); // FREQ data AM 10MHz for EEPROM
EEPROM.commit(); // Fro ESP32 EEPROM service
}
freq_0 = 10000000;
EEPROM.put( FREQ_AD + 8 , freq_0); // FREQ data AM 10MHz for EEPROM #0
EEPROM.commit(); // Fro ESP32 EEPROM service
// freq_0 = -80200000;
// EEPROM.put( FREQ_AD + 8 + 49 * 4, freq_0); // FREQ data FM 80.2MHz for EEPROM #49
// freq_0 = -85100000;
// EEPROM.put( FREQ_AD + 8 + 48 * 4, freq_0); // FREQ data FM 85.1MHz for EEPROM #48
}
// Long FREQ data changes to 10 digit numerics
void LongToStr(long dat, char *fm) {
long fmdat;
int i;
fmdat = dat;
for (i = 0; i < 11; i++) {
fm[10 - i] = ( fmdat % 10 ) | 0x30;
fmdat = fmdat / 10;
}
}
// Reducing preceding zero into space
void Fdds_Space(char *fm) {
int i;
for (i = 0; i < 10; i++) {
if ( fm[i] == 0x30) {
fm[i] = 0x20;
}
else i = 11;
}
}
// Function SEL determining A4 port: RE push SW
// result 0:no key, 1:off-> on
int function_key() {
result = 0;
// SW sensing to avoid chattering
if (Timer_RESW <= 0) {
boolean RESW_value = digitalRead(RESW);
if ((RESW_value == 0) && (RESW_value_last == 1)) {
Timer_RESW = Timer_RESW_i;
RESW_value_last = 0;
result = 1;
} if ((RESW_value == 1) && (RESW_value_last == 0)) {
Timer_RESW = Timer_RESW_i;
RESW_value_last = 1;
result = 0;
}
RESW_value_last = RESW_value;
}
return result ; // Switch not settled
}
// After key result(RESW_click), wait timer_mash. Then decide single/double
// result 0:no key, off-> on pending, 1:single click, 2:double click
int mode_define(unsigned char keyresult) {
char result = 0;
// To detect double click Detect double within a cirtain second
// After keyresult = 1;
// waiting double click (Timer_mash > 0): mash pending
if ((Timer_mash > 0) && (keyresult == 1)) { // Double RESW pushed
RESW_result_p = 2;
}
else if ((Timer_mash <= 0) && (keyresult == 1)) { // Firstly RESW pushed
Timer_mash = Timer_mash_i; // Mash timer set
RESW_result_p = 1; // Once set single click
}
// waiting timer end
else if (( Timer_mash <= 0 ) && (RESW_result_p >= 1)) {
result = RESW_result_p; // Stop to wait & report result
RESW_result_p = 0;
}
return result;
}
// Timing managing function: When Time_value <= 0, timer expired
void TimerCount(void) {
long Current_millis = millis();
long time_dif = Current_millis - Last_millis; // Calculate how many millis after last call
Last_millis = Current_millis; // Remember current time
if (Timer_mash > 0) Timer_mash = Timer_mash - time_dif; // To wait double click timing
if (Timer_RESW > 0) Timer_RESW = Timer_RESW - time_dif; // To avoid chattering
if (Timer_LED > 0) Timer_LED = Timer_LED - time_dif; // To turn on/off for #13 LED
if (Timer_scan > 0) Timer_scan = Timer_scan - time_dif;
if (Timer_DISP_REF > 0) Timer_DISP_REF = Timer_DISP_REF - time_dif; // Display refresh timing
if (Timer_Mem_Write > 0) Timer_Mem_Write = Timer_Mem_Write - time_dif; // EEPROM put blink timing
}
// LED on/off & OLED FUNCTION blink:j
void blink(long on_time, long off_time) { // LED on_off, j effects FUNC on/off
if ((Timer_LED <= 0) && (j == 1)) {
digitalWrite(led_pin, 0 ); // Monitor Led off
j = 0; // bit j off j:LCD blink
Timer_LED = off_time;
}
else if ((Timer_LED <= 0) && (j == 0)) {
digitalWrite(led_pin, 1 ); // Mon Led on
j = 1; // bit j off j:LCD blink
Timer_LED = on_time;
}
}
void FUNC_Disp ( char* func){ // Display FUNC of #2 size on X:0,Y:25
display.setTextSize(2);
display.setCursor(0, 25);
display.print(func);
display.print("TEST");
}
//********* display frequency *********
// Assemble the format of frequency value and display it on the OLED
void Freq_Disp() { // Format freq data for display & display
unsigned int m = freq1 / 1000000;
unsigned int k = (freq1 % 1000000) / 1000;
unsigned int h = (freq1 % 1000) / 1;
display.clearDisplay();
display.setTextSize(2);
char buffer[15] = "";
if (m < 1) { // In he case of less than MHz, kkk.hhh kHz
display.setCursor(5, 24);
sprintf(buffer, "%003d.%003d", k, h);
}
else if (m < 100) { // In the case of more than MHz and
// less than 100MHz, mm.kkk hhh MHz
display.setCursor(5, 24);
sprintf(buffer, "%2d.%003d,%003d", m, k, h);
}
else if (m >= 100){ // In the case of more than 100MHz, mmm.kkk hh MHz
unsigned int h = (freq1 % 1000) / 10;
display.setCursor(5, 24);
sprintf(buffer, "%3d.%003d,%002d", m, k, h);
}
display.print(buffer);
}
// Serial.ino
// show in serial the eeprom settings
void ShowSettings() {
/*
Serial.println("Stored EEPROM Settings");
Serial.print("\nFreq = ");
Serial.println(freq1);
Serial.print("\nFstep = ");
Serial.println(fstep);
Serial.print("\nVolume = ");
Serial.println(VolumeLevel);
Serial.print("\nSquelch = ");
Serial.println( SquelchLevel);
Serial.print("\nBand = ");
Serial.println(BandSelect);
Serial.println("----------------------");
Serial.print("\nfreq_0 = ");
Serial.println(freq_0);
Serial.print("\nSfreq1= ");
Serial.println( freq1);
Serial.print("\nif_mode = ");
Serial.println(if_mode);
*/
}
// CHANGE! No change no setting
int32_t last_ffrequency0 = 0;
int32_t last_ffrequency1 = 0;
int32_t last_ffrequency2 = 0;
// calculate and send frequency code to Si5351...
// si5351.set_freq(freq1 * SI5351_FREQ_MULT, SI5351_CLK0);
void send_frequency(int32_t ffrequency, int fcontext) {
ffrequency = ffrequency * 100 ;
switch (fcontext) { // no use fcontext only CLK0
case 0: // Port 1
if ( ffrequency != last_ffrequency0 ){
si5351.set_freq((uint64_t)ffrequency, SI5351_CLK0 ); // Set the frequency on the Si5351a.
last_ffrequency0 = ffrequency;
}
break;
case 1: // Port 2
if ( ffrequency != last_ffrequency1 ){
si5351.set_freq((uint64_t)ffrequency, SI5351_CLK1 );
last_ffrequency1 = ffrequency;
}
break;
case 2: // Port 3
if ( ffrequency != last_ffrequency2 ){
si5351.set_freq((uint64_t)ffrequency, SI5351_CLK2 );
last_ffrequency2 = ffrequency;
}
break;
}
}
//
unsigned long int last_freq = 0;
unsigned long int last_ifclk = 0;
//
void SI_setfreq( unsigned long int freq) {
...
This file has been truncated, please download it to see its full contents.
Comments