/********************************************************************************************** 10kHz to 120MHz VFO / RF Generator with Si5351 and Arduino Nano, with Zwischenfrquenz (ZF) offset + . See the schematics for wiring details. By J. CesarSound - ver 1.0 - Dec/2020. Originallösung verwendet PINCHANGE Interrupt etwas geändert auf Timer2 Interrupt Timer0 wird in Arduino für millis() verwendet Funktionen Wobbeln, Calibration via DCF-Frequenzabgleich mit Oszi, ev mit Lissajoufigur. und aus hist. Gründen 9 MHz an clk0 und clk2 90° phasenverschoben etwas FM-Modulation mit 2,5kHz Jan 2022 adapted by eRDe mit Danke an CesarSound s.o. ***********************************************************************************************/ //Libraries #include //IDE Standard //#include //Ben Buxton https://github.com/brianlow/Rotary #include //Etherkit https://github.com/etherkit/Si5351Arduino #include //Adafruit GFX https://github.com/adafruit/Adafruit-GFX-Library #include //Adafruit SSD1306 https://github.com/adafruit/Adafruit_SSD1306 #include // //------------User preferences---------------------------------------------------------------- #define ZF 0 //Enter your ZF frequency, ex: 455000 = 455kHz, 10700 = 10.7MHz, // direct convert receiver or RF generator, + will add ZF offfset. #define FREQ_INIT 1000000 //Enter your initial frequency at startup, ex: 7000000 = 7MHz, #define XT_CAL_F 110000 //Si5351 calibration factor, adjust to get exatcly 10MHz. #define tunestep A0 //Change the pin used by encoder push button if you want. #define calib 4 //Taster für Calibration ACHTUNG RUHEKONTAKT!!! #define wobble 8 //Schalter für Funktionswahl #define phas9 9 //Schalter für 9 MHZ phasehift #define trigger 10 //Triggerausgang für Osci bei wobbel Funktion //--------------------------------------------------------------------------------------------- //Rotary r = Rotary(2, 3); // die Originallösung verwendet PINCHANGE Interrupt Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire); Si5351 si5351; unsigned long freq = FREQ_INIT; unsigned long freqold, fstep, f_zfold; //sehr feiner Unterschied gggg qqqq Vorsicht! long f_zf = ZF; long cal = XT_CAL_F; unsigned long long pll_freq = 90000000000ULL; //Angabe für PLL_A byte encoder = 1; byte stp, esaved = 0, leave = 1, done = 1; // esaved = Status ob EEPROM Werte hält mit 010101 unsigned int period = 100; //millis display active unsigned long time_now = 0; //millis display active const int analogInPin = A1; // Analog input pin für den Schleifer des Potentiometers int sensorValue = 0; // lese potentiometer static uint8_t flag; //Wert aus LUT /**********************Interrupt*********************************/ ISR(TIMER2_OVF_vect) { const uint8_t enc_lut[16] = {0,0,2,0,0,0,0,1,0,0,0,0,0,0,0,0}; uint8_t index; static uint8_t last; //alte Encoderphasen static uint8_t aktuell; //aktuelle -"- aktuell = PIND & 0b00001100; //input PORTD PINS 2,3 und maskiere Encoder Phasen index = aktuell | last >>2; //erzeuge index für enc_lut last = aktuell; //altes last im Nirvana flag = enc_lut[index]; // flag ist ja global verwendbar if (flag == 1) {freq = freq + fstep; cal = cal + fstep; if (freq >= 120000000) freq = 12000000; if (cal >=150000) cal = 150000;} if (flag == 2) {freq = freq - fstep; cal = cal - fstep; if (freq <= 10000) freq = 10000; else if (freq < 10000) freq = 100000000; if (cal <= -150000) cal = -150000; } } /* Ende ISR Routine**************Start setup*******************/ void setup() { Wire.begin(); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); display.setTextColor(WHITE); display.display(); // PCICR |= (1 << PCIE2); //alte Version mit PinChangeInt // PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); TCCR2A |= (1 << WGM21)|(0 << WGM20); //CTC TCCR2B |= (1 << CS22)| ( 1<>1)); wobstep = f_zf >>6; //Hub/2 und wobstep = Hub/64 while(digitalRead(wobble) == LOW) //wenn Schalter "Wobbler" gerückt sonst endet wobbeln { i = 0; //innere while Schleife neu starten digitalWrite(trigger, HIGH); // und Triggerpuls generieren delay(2); // Dauer für X-Y auf Osci via Sägezahn digitalWrite(trigger, LOW); // Triggerpuls für Osci-Timebase fertig displayfreq(); while( i++ <64) //zuerst Vergleich, dann increm. bis Abbruchkriterium { fnow = fstart + (i * wobstep); si5351.set_freq_manual((fnow) * 100ULL, pll_freq, SI5351_CLK0); } } } void phase90() // ehemalige Freq. für SSB-Quarzfilter 90°-phase clk0 zu clk1 { unsigned long freqi = 9000000; leave = 1; si5351.set_freq_manual((freqi) * 100ULL, pll_freq, SI5351_CLK0); si5351.set_freq_manual((freqi) * 100ULL, pll_freq, SI5351_CLK1); si5351.set_phase(SI5351_CLK0, 0); si5351.set_phase(SI5351_CLK1, 100); //900/9=100 also offset = 100 si5351.pll_reset(SI5351_PLLA); // aus library examples, ist nötig display.clearDisplay(); display.setTextSize(2); display.setCursor(20, 1); display.print(freqi); layout(); display.display(); while(digitalRead(phas9) == LOW) { delay(100); //bleib solange } } /***************************displayroutinen*********************************/ void displaycal() { display.clearDisplay(); display.setTextSize(2); display.setCursor(10, 1); display.print("Calibrate"); display.setCursor(20, 25); display.print(cal); display.display(); } 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 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.setTextSize(1); display.setCursor(2, 25); display.print("Step:"); display.setTextSize(2); if (stp == 1) display.print("1Hz"); if (stp == 2) display.print("10Hz"); if (stp == 3) display.print("1k"); if (stp == 4) display.print("5k"); if (stp == 5) display.print("9k"); if (stp == 6) display.print("10k"); if (stp == 7) display.print("100k"); if (stp == 8) display.print("1MHz"); if (stp == 0) display.print("setIF");if (stp == 9) display.print("clrIF"); display.setCursor(2, 48); display.setTextSize(1); display.print("ZF: "); display.setTextSize(2); display.print(f_zf/1000); if (f_zf != 0) 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 (f_zf == 0) display.print("VFO"); if (f_zf != 0) display.print("L O"); display.display(); } void startup_text() { display.setTextSize(1); display.setCursor(4, 5); display.print("Si5351"); display.setCursor(4, 20); display.print("Signal Generator"); display.setCursor(4, 35); display.print("Version 0.0"); display.setCursor(4, 50); display.print(">> eRDe <<"); display.display(); delay(2500); display.clearDisplay(); }