Components and supplies
Toggle Switch, Toggle
Arduino Nano R3
Breadboard (generic)
Capacitor 10 nF
SSD1306 128X64 OLED DISPLAY
SI5351 CLOCK GEN MODULE
Capacitor 100 nF
Capacitor 10 µF
RCA JACK FOR RF OUTPUT CONECTION
Rotary Encoder with Push-Button
Apps and platforms
Arduino IDE
Project description
Code
Sketch SI5351_VFO_RF_GEN_OLED_JCR
c_cpp
VFO work. Load it to the Arduino using the IDE.
1/******************************************************************************************************** 2 10kHz to 120MHz VFO / RF Generator with Si5351 and Arduino Nano, with Intermediate Frequency (IF) 3 offset (+ or -). See the schematics for wiring details. By J. CesarSound - ver 1.0 - Dec/2020. 4*********************************************************************************************************/ 5 6//Libraries 7#include <Wire.h> //IDE Standard 8#include <Rotary.h> //Ben Buxton https://github.com/brianlow/Rotary 9#include <si5351.h> //Etherkit https://github.com/etherkit/Si5351Arduino 10#include <Adafruit_GFX.h> //Adafruit GFX https://github.com/adafruit/Adafruit-GFX-Library 11#include <Adafruit_SSD1306.h> //Adafruit SSD1306 https://github.com/adafruit/Adafruit_SSD1306 12 13//User preferences 14//------------------------------------------------------------------------------------------------------------ 15#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. 16#define FREQ_INIT 7000000 //Enter your initial frequency at startup, ex: 7000000 = 7MHz, 10000000 = 10MHz, 840000 = 840kHz. 17#define XT_CAL_F 33000 //Si5351 calibration factor, adjust to get exatcly 10MHz. Increasing this value will decreases the frequency and vice versa. 18#define tunestep A0 //Change the pin used by encoder push button if you want. 19//------------------------------------------------------------------------------------------------------------ 20 21Rotary r = Rotary(2, 3); 22Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire); 23Si5351 si5351; 24 25unsigned long freq = FREQ_INIT; 26unsigned long freqold, fstep; 27long interfreq = IF; 28long cal = XT_CAL_F; 29unsigned long long pll_freq = 90000000000ULL; 30byte encoder = 1; 31byte stp; 32unsigned int period = 100; //millis display active 33unsigned long time_now = 0; //millis display active 34 35ISR(PCINT2_vect) { 36 char result = r.process(); 37 if (result == DIR_CW) set_frequency(1); 38 else if (result == DIR_CCW) set_frequency(-1); 39} 40 41void set_frequency(short dir) { 42 if (encoder == 1) { //Up/Down frequency 43 if (dir == 1) freq = freq + fstep; 44 if (freq >= 120000000) freq = 120000000; 45 if (dir == -1) freq = freq - fstep; 46 if (fstep == 1000000 && freq <= 1000000) freq = 1000000; 47 else if (freq < 10000) freq = 10000; 48 } 49} 50 51void setup() { 52 Wire.begin(); 53 display.begin(SSD1306_SWITCHCAPVCC, 0x3C); 54 display.clearDisplay(); 55 display.setTextColor(WHITE); 56 display.display(); 57 58 pinMode(2, INPUT_PULLUP); 59 pinMode(3, INPUT_PULLUP); 60 pinMode(tunestep, INPUT_PULLUP); 61 62 statup_text(); 63 64 si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, cal); 65 si5351.output_enable(SI5351_CLK0, 1); //1 - Enable / 0 - Disable CLK 66 si5351.output_enable(SI5351_CLK1, 0); 67 si5351.output_enable(SI5351_CLK2, 0); 68 si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_2MA); //Output current 2MA, 4MA, 6MA or 8MA 69 70 PCICR |= (1 << PCIE2); 71 PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); 72 sei(); 73 74 stp = 3; 75 setstep(); 76 layout(); 77 displayfreq(); 78} 79 80void loop() { 81 if (freqold != freq) { 82 time_now = millis(); 83 tunegen(); 84 freqold = freq; 85 } 86 87 if (digitalRead(tunestep) == LOW) { 88 time_now = (millis() + 300); 89 setstep(); 90 delay(300); 91 } 92 93 if ((time_now + period) > millis()) { 94 displayfreq(); 95 layout(); 96 } 97} 98 99void tunegen() { 100 si5351.set_freq_manual((freq + (interfreq * 1000ULL)) * 100ULL, pll_freq, SI5351_CLK0); 101} 102 103void displayfreq() { 104 unsigned int m = freq / 1000000; 105 unsigned int k = (freq % 1000000) / 1000; 106 unsigned int h = (freq % 1000) / 1; 107 108 display.clearDisplay(); 109 display.setTextSize(2); 110 111 char buffer[15] = ""; 112 if (m < 1) { 113 display.setCursor(41, 1); sprintf(buffer, "%003d.%003d", k, h); 114 } 115 else if (m < 100) { 116 display.setCursor(5, 1); sprintf(buffer, "%2d.%003d.%003d", m, k, h); 117 } 118 else if (m >= 100) { 119 unsigned int h = (freq % 1000) / 10; 120 display.setCursor(5, 1); sprintf(buffer, "%2d.%003d.%02d", m, k, h); 121 } 122 display.print(buffer); 123} 124 125void setstep() { 126 switch (stp) { 127 case 1: 128 stp = 2; 129 fstep = 1; 130 break; 131 case 2: 132 stp = 3; 133 fstep = 10; 134 break; 135 case 3: 136 stp = 4; 137 fstep = 1000; 138 break; 139 case 4: 140 stp = 5; 141 fstep = 5000; 142 break; 143 case 5: 144 stp = 6; 145 fstep = 10000; 146 break; 147 case 6: 148 stp = 1; 149 fstep = 1000000; 150 break; 151 } 152} 153 154void layout() { 155 display.setTextColor(WHITE); 156 display.drawLine(0, 20, 127, 20, WHITE); 157 display.drawLine(0, 43, 127, 43, WHITE); 158 display.drawLine(105, 24, 105, 39, WHITE); 159 display.setTextSize(2); 160 display.setCursor(2, 25); 161 display.print("TS:"); 162 if (stp == 2) display.print("1Hz"); if (stp == 3) display.print("10Hz"); if (stp == 4) display.print("1k"); 163 if (stp == 5) display.print("5k"); if (stp == 6) display.print("10k"); if (stp == 1) display.print("1M"); 164 display.setCursor(2, 48); 165 display.print("IF:"); 166 display.print(interfreq); 167 display.print("k"); 168 display.setTextSize(1); 169 display.setCursor(110, 23); 170 if (freq < 1000000) display.print("kHz"); 171 if (freq >= 1000000) display.print("MHz"); 172 display.setCursor(110, 33); 173 if (interfreq == 0) display.print("VFO"); 174 if (interfreq != 0) display.print("L O"); 175 display.display(); 176} 177 178void statup_text() { 179 display.setTextSize(1); 180 display.setCursor(4, 5); 181 display.print("Si5351"); 182 display.setCursor(4, 20); 183 display.print("VFO / RF Generator"); 184 display.setCursor(4, 35); 185 display.print("Version 1.0"); 186 display.setCursor(4, 50); 187 display.print(">> JCR RADIO <<"); 188 display.display(); 189 delay(3000); 190 display.clearDisplay(); 191}
Sketch SI5351_VFO_RF_GEN_OLED_JCR
c_cpp
VFO work. Load it to the Arduino using the IDE.
1/******************************************************************************************************** 2 3 10kHz to 120MHz VFO / RF Generator with Si5351 and Arduino Nano, with Intermediate 4 Frequency (IF) 5 offset (+ or -). See the schematics for wiring details. By J. 6 CesarSound - ver 1.0 - Dec/2020. 7*********************************************************************************************************/ 8 9//Libraries 10#include 11 <Wire.h> //IDE Standard 12#include <Rotary.h> //Ben 13 Buxton https://github.com/brianlow/Rotary 14#include <si5351.h> //Etherkit 15 https://github.com/etherkit/Si5351Arduino 16#include <Adafruit_GFX.h> //Adafruit 17 GFX https://github.com/adafruit/Adafruit-GFX-Library 18#include <Adafruit_SSD1306.h> 19 //Adafruit SSD1306 https://github.com/adafruit/Adafruit_SSD1306 20 21//User 22 preferences 23//------------------------------------------------------------------------------------------------------------ 24#define 25 IF 0 //Enter your IF frequency, ex: 455 = 455kHz, 10700 = 10.7MHz, 26 0 = to direct convert receiver or RF generator, + will add and - will subtract IF 27 offfset. 28#define FREQ_INIT 7000000 //Enter your initial frequency at startup, 29 ex: 7000000 = 7MHz, 10000000 = 10MHz, 840000 = 840kHz. 30#define XT_CAL_F 33000 31 //Si5351 calibration factor, adjust to get exatcly 10MHz. Increasing this value 32 will decreases the frequency and vice versa. 33#define tunestep A0 //Change 34 the pin used by encoder push button if you want. 35//------------------------------------------------------------------------------------------------------------ 36 37Rotary 38 r = Rotary(2, 3); 39Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire); 40Si5351 41 si5351; 42 43unsigned long freq = FREQ_INIT; 44unsigned long freqold, fstep; 45long 46 interfreq = IF; 47long cal = XT_CAL_F; 48unsigned long long pll_freq = 90000000000ULL; 49byte 50 encoder = 1; 51byte stp; 52unsigned int period = 100; //millis display active 53unsigned 54 long time_now = 0; //millis display active 55 56ISR(PCINT2_vect) { 57 char 58 result = r.process(); 59 if (result == DIR_CW) set_frequency(1); 60 else if 61 (result == DIR_CCW) set_frequency(-1); 62} 63 64void set_frequency(short dir) 65 { 66 if (encoder == 1) { //Up/Down frequency 67 if 68 (dir == 1) freq = freq + fstep; 69 if (freq >= 120000000) freq = 120000000; 70 71 if (dir == -1) freq = freq - fstep; 72 if (fstep == 1000000 && freq <= 1000000) 73 freq = 1000000; 74 else if (freq < 10000) freq = 10000; 75 } 76} 77 78void 79 setup() { 80 Wire.begin(); 81 display.begin(SSD1306_SWITCHCAPVCC, 0x3C); 82 83 display.clearDisplay(); 84 display.setTextColor(WHITE); 85 display.display(); 86 87 88 pinMode(2, INPUT_PULLUP); 89 pinMode(3, INPUT_PULLUP); 90 pinMode(tunestep, 91 INPUT_PULLUP); 92 93 statup_text(); 94 95 si5351.init(SI5351_CRYSTAL_LOAD_8PF, 96 0, cal); 97 si5351.output_enable(SI5351_CLK0, 1); //1 - Enable 98 / 0 - Disable CLK 99 si5351.output_enable(SI5351_CLK1, 0); 100 si5351.output_enable(SI5351_CLK2, 101 0); 102 si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_2MA); //Output current 103 2MA, 4MA, 6MA or 8MA 104 105 PCICR |= (1 << PCIE2); 106 PCMSK2 |= (1 << PCINT18) 107 | (1 << PCINT19); 108 sei(); 109 110 stp = 3; 111 setstep(); 112 layout(); 113 114 displayfreq(); 115} 116 117void loop() { 118 if (freqold != freq) { 119 time_now 120 = millis(); 121 tunegen(); 122 freqold = freq; 123 } 124 125 if (digitalRead(tunestep) 126 == LOW) { 127 time_now = (millis() + 300); 128 setstep(); 129 delay(300); 130 131 } 132 133 if ((time_now + period) > millis()) { 134 displayfreq(); 135 layout(); 136 137 } 138} 139 140void tunegen() { 141 si5351.set_freq_manual((freq + (interfreq 142 * 1000ULL)) * 100ULL, pll_freq, SI5351_CLK0); 143} 144 145void displayfreq() { 146 147 unsigned int m = freq / 1000000; 148 unsigned int k = (freq % 1000000) / 1000; 149 150 unsigned int h = (freq % 1000) / 1; 151 152 display.clearDisplay(); 153 display.setTextSize(2); 154 155 156 char buffer[15] = ""; 157 if (m < 1) { 158 display.setCursor(41, 1); sprintf(buffer, 159 "%003d.%003d", k, h); 160 } 161 else if (m < 100) { 162 display.setCursor(5, 163 1); sprintf(buffer, "%2d.%003d.%003d", m, k, h); 164 } 165 else if (m >= 100) 166 { 167 unsigned int h = (freq % 1000) / 10; 168 display.setCursor(5, 1); sprintf(buffer, 169 "%2d.%003d.%02d", m, k, h); 170 } 171 display.print(buffer); 172} 173 174void 175 setstep() { 176 switch (stp) { 177 case 1: 178 stp = 2; 179 fstep 180 = 1; 181 break; 182 case 2: 183 stp = 3; 184 fstep = 10; 185 break; 186 187 case 3: 188 stp = 4; 189 fstep = 1000; 190 break; 191 case 192 4: 193 stp = 5; 194 fstep = 5000; 195 break; 196 case 5: 197 stp 198 = 6; 199 fstep = 10000; 200 break; 201 case 6: 202 stp = 1; 203 204 fstep = 1000000; 205 break; 206 } 207} 208 209void layout() { 210 display.setTextColor(WHITE); 211 212 display.drawLine(0, 20, 127, 20, WHITE); 213 display.drawLine(0, 43, 127, 43, 214 WHITE); 215 display.drawLine(105, 24, 105, 39, WHITE); 216 display.setTextSize(2); 217 218 display.setCursor(2, 25); 219 display.print("TS:"); 220 if (stp == 2) display.print("1Hz"); 221 if (stp == 3) display.print("10Hz"); if (stp == 4) display.print("1k"); 222 223 if (stp == 5) display.print("5k"); if (stp == 6) display.print("10k"); if 224 (stp == 1) display.print("1M"); 225 display.setCursor(2, 48); 226 display.print("IF:"); 227 228 display.print(interfreq); 229 display.print("k"); 230 display.setTextSize(1); 231 232 display.setCursor(110, 23); 233 if (freq < 1000000) display.print("kHz"); 234 235 if (freq >= 1000000) display.print("MHz"); 236 display.setCursor(110, 33); 237 238 if (interfreq == 0) display.print("VFO"); 239 if (interfreq != 0) display.print("L 240 O"); 241 display.display(); 242} 243 244void statup_text() { 245 display.setTextSize(1); 246 247 display.setCursor(4, 5); 248 display.print("Si5351"); 249 display.setCursor(4, 250 20); 251 display.print("VFO / RF Generator"); 252 display.setCursor(4, 35); 253 254 display.print("Version 1.0"); 255 display.setCursor(4, 50); 256 display.print(">> 257 JCR RADIO <<"); 258 display.display(); 259 delay(3000); 260 display.clearDisplay(); 261}
Downloadable files
Wiring diagram (schematics)
To interconnect the parts.
Wiring diagram (schematics)
Comments
Only logged in users can leave comments
10kHz to 120MHz VFO / RF Generator with Si5351 and Arduino | Arduino Project Hub