Я понял. О результате отпишусь
Собрал Универсальный синтезатор на микросхеме Si5351
Полный пакет библиотек и скетч в файле vfo-si5351-new.zip (102 кб)
Скетч рабочий. Скомпилировался и загрузился без проблем.
Всё бы хорошо, но изображение перевернуто на 180 градусов.
Вопрос остался открытым. Куда вписать вышеуказанные строки, в скетч, что бы свершилось ожидаемое “чудо”?

С этого нужно было начинать. И код вставить по правилам форума.
Простите ошибочка с фото. Второе фото уже не актуально. Вот правильное фото дисплея собранного проекта.
ВНИМАТЕЛЬНО прочти #23 !!!
ЗЫ: По внешним ссылкам тут никто не ходит, код нужно выкладывать сюда (правильно оформив).
#include <Rotary.h>
/*
A part of this program is taken from Jason Mildrum, NT7S.
All extra functions are written by me, Rob Engberts PA0RWE
References:
http://nt7s.com/
http://sq9nje.pl/
http://ak2b.blogspot.com/
http://pa0rwe.nl/?page_id=804
* SI5351_VFO control program for Arduino NANO
* Copyright PA0RWE Rob Engberts
*
* Using the old Si5351 library by Jason Mildrun nt7s
*
* Functions:
* - CLK0 - Tx frequency = Display frequency
* - CLK1 - Rx / RIT frequency = Tx +/- BFO (upper- or lower mixing)
* When RIT active, RIT frequency is displayed and is tunable.
* When RIT is inactive Rx = Tx +/- BFO
* - CLK2 - BFO frequency, tunable
*
* - Stepsize: select (pushbutton)
* - Calibrate: (pushbutton) calculates difference between X-tal and measured
* x-tal frequency, to correct x-tal frequency.
* - Selection: (pushbutton) Switch between TRx and BFO mode
* - RIT switch: tunable Rx frequency, while Tx frequency not changed
* - Programming PIC by ICSP
*
* Si5351 settings: I2C address is in the .h file
* X-tal freq is in the .h file but set in line 354
*
***************************************************************************
* 02-04-2015 1.0 Start building program based on the PIC version
* 18-06-2019 1.1 Extend frequency range to 10 KHz down
* Update frequency display. Added 'MHz' and 'KHz'
* Set max frequency to 100 MHz.
*
***************************************************************************
* Includes
**************************************************************************/
#include <Rotary.h>
#include <RWE_si5351.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
/**************************************************************************
* (Pin) Definitions
**************************************************************************/
#define ENCODER_A 2 // Encoder pin A INT0/PCINT18 D2
#define ENCODER_B 3 // Encoder pin B INT1/PCINT19 D3
#define ENCODER_BTN 4 // Encoder pushbutton D4
#define OLED_RESET 8 // OLED reset
#define Calibrbtn 5 // Calibrate
#define RIT_Switch 6 // RIT Switch
#define TX_Switch 7 // Select TRx or BFO
// I2C-SDA A4 // I2C-SDA
// I2C-SCL A5 // I2C-SCL
#define F_MIN 10000UL // Lower frequency limit 10 KHz
#define F_MAX 100000000UL // Upper frequency limit 100 MHz
/**************************************************************************
* EEPROM data locations
**************************************************************************/
#define EE_SAVED_RADIX 0 // Stepsize pointer
#define EE_SAVED_AFREQ 4 // Actual Tx Frequency (CLK0)
#define EE_SAVED_BFREQ 8 // BFO (IF) Frequency (CLK2)
#define EE_SAVED_XFREQ 12 // X-tal frequency (25 or 27 MHz)
#define EE_SAVED_OFSET 16 // store correction
#define EE_SAVED_CALBR 20 // calibrated indicator
Adafruit_SSD1306 display(OLED_RESET);
Si5351 si5351;
Rotary r = Rotary(ENCODER_A, ENCODER_B);
/**************************************************************************
* Declarations
**************************************************************************/
volatile uint32_t bfo_f = 900000000ULL / SI5351_FREQ_MULT; // CLK0 start IF
volatile uint32_t vfo_t = 1420000000ULL / SI5351_FREQ_MULT; // CLK2 start Tx freq
volatile uint32_t vfo_r = vfo_t - bfo_f; // CLK1 start Rx freq
volatile uint32_t vfo_s = vfo_t; // Saved for RIT
uint32_t vco_c = 0; // X-tal correction factor
uint32_t xt_freq;
long radix = 100L, old_radix = 100L; //start step size
boolean changed_f = 0, stepflag = 0, calflag = 0, modeflag = 0, ritset = 0;
boolean calibrate = 0;
byte act_clk = 0, disp_txt = 0;
/**************************************/
/* Interrupt service routine for */
/* encoder frequency change */
/**************************************/
ISR(PCINT2_vect) {
char result = r.process();
if (result == DIR_CW)
set_frequency(1);
else if (result == DIR_CCW)
set_frequency(-1);
}
/**************************************/
/* Change the frequency */
/* dir = 1 Increment */
/* dir = -1 Decrement */
/**************************************/
void set_frequency(short dir)
{
switch (act_clk)
{
case 0: // Tx frequency
if (dir == 1)
vfo_t += radix;
if (dir == -1) {
if (vfo_t < radix) break; // to prevent negative value
vfo_t -= radix;
}
break;
case 1: // Tx frequency (only if RIT is on)
if (dir == 1)
vfo_t += radix;
if (dir == -1) {
if (vfo_t < radix) break; // to prevent negative value
vfo_t -= radix;
}
break;
case 2: // BFO frequency
if (dir == 1)
bfo_f += radix;
if (dir == -1) {
if (bfo_f < radix) break; // to prevent negative value
bfo_f -= radix;
}
break;
}
if(vfo_t > F_MAX)
vfo_t = F_MAX;
if(vfo_t < F_MIN)
vfo_t = F_MIN;
changed_f = 1;
}
/**************************************/
/* Read the buttons with debouncing */
/**************************************/
boolean get_button()
{
if (!digitalRead(ENCODER_BTN)) // Stepsize
{
delay(20);
if (!digitalRead(ENCODER_BTN))
{
while (!digitalRead(ENCODER_BTN));
stepflag = 1;
}
}
else if (!digitalRead(Calibrbtn)) // Calibrate
{
delay(20);
if (!digitalRead(Calibrbtn))
{
while (!digitalRead(Calibrbtn));
calflag = 1;
}
}
else if (!digitalRead(TX_Switch)) // Selection
{
delay(20);
if (!digitalRead(TX_Switch))
{
while (!digitalRead(TX_Switch));
modeflag = 1;
}
}
if (stepflag | calflag | modeflag) return 1;
else return 0;
}
/********************************************************************************
* RIT switch handling
* Switch to small stepsize (100 Hz)
*******************************************************************************/
void RIT_switch() // Read RIT_switch
{
if (!digitalRead(RIT_Switch) && ritset == 0){ // RIT on
act_clk = 1;
ritset = 1;
vfo_s = vfo_t; // Save Tx freq
old_radix = radix; // Save actual stepsize
radix = 100; // Set stepsize to 100 Hz
}
else if (digitalRead(RIT_Switch) && ritset == 1){ // RIT 0ff
act_clk = 0; // RTx mode
ritset = 0;
vfo_t = vfo_s; // Restore to original vco_t
radix = old_radix; // Back to old stepsize
disp_txt = 0; // Clear line
// Update Rx frequency based on the restored Tx frequency
if (vfo_t <= bfo_f) vfo_r = vfo_t + bfo_f; // Upper / lower mixing
else vfo_r = vfo_t - bfo_f;
si5351.set_freq((vfo_r * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK1);
}
}
/**************************************/
/* Displays the frequency and stepsize*/
/**************************************/
void display_frequency()
{
char LCDstr[10];
char Hertz[7];
int p,q = 0;
unsigned long freq;
display.clearDisplay();
switch(act_clk)
{
case 0: // Tx frequency
freq = vfo_t;
break;
case 1: // Tx frequency (Used in RIT Mode)
freq = vfo_t;
break;
case 2: // MF frequency
freq = bfo_f;
break;
}
Hertz[1]='\0'; // empty array
sprintf(LCDstr, "%ld", freq); // convert freq to string
p=strlen(LCDstr); // determine length
display.setCursor(100,16);
display.setTextSize(1);
if (p>6){ // MHz
display.print(F("MHz"));
q=p-6;
strcpy(Hertz,LCDstr); // get Herz digits (6)
strcpy(LCDstr+q,Hertz+(q-1)); // copy into LCDstr and add to MHz
LCDstr[q]='.'; // decimal point
}
else { // KHz
display.print(F("KHz"));
q=p-3;
strcpy(Hertz,LCDstr); // get Herz digits (3)
strcpy(LCDstr+q,Hertz+(q-1)); // copy into LCDstr and add to KHz
LCDstr[q]='.'; // decimal point
}
switch (p)
{
case 5: // 10 KHZ
display.setCursor(36,0);
break;
case 6: // 100 KHZ
display.setCursor(24,0);
break;
case 7: // 1 MHZ
display.setCursor(12,0);
break;
case 8: // 10 MHZ
display.setCursor(0,0);
break;
case 9: // 100 MHZ
display.setCursor(0,0);
break;
}
display.setTextSize(2);
display.println(LCDstr);
display_settings();
}
/**************************************/
/* Displays step, mode and version */
/**************************************/
void display_settings()
{
// Stepsize
display.setCursor(8, 40);
display.setTextSize(1);
display.print(F("Step:"));
switch (radix)
{
case 1:
display.println(F(" 1Hz"));
break;
case 10:
display.println(F(" 10Hz"));
break;
case 100:
display.println(F(" 100Hz"));
break;
case 1000:
display.println(F(" 1kHz"));
break;
case 10000:
display.println(F(" 10kHz"));
break;
case 100000:
display.println(F("100kHz"));
break;
case 1000000:
display.println(F(" 1MHz"));
break;
}
// Mode
display.setCursor(100, 40);
switch (act_clk)
{
case 0:
display.println(F("TRx"));
break;
case 1:
display.println(F("RIT"));
break;
case 2:
display.println(F("BFO"));
break;
}
// Version
display.setCursor(15, 55);
display.print(F("Si5351 vfo V.1.1"));
// Messages
display.setCursor(12, 25);
switch (disp_txt)
{
case 0:
display.print(F(" ")); // clear line
break;
case 1:
display.print(F("** Turn RIT Off *"));
break;
case 2:
display.print(F("*** Set to TRx **"));
break;
case 3:
display.print(F("** Calibration **"));
break;
case 4:
display.print(F("* Calibration OK!"));
break;
}
display.display();
}
/**************************************/
/* S E T U P */
/**************************************/
void setup()
{
Serial.begin(115200);
Wire.begin();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x64)
// Read EEPROM
radix = eeprom_read_dword((const uint32_t *)EE_SAVED_RADIX);
if ((radix < 10UL) | (radix > 1000000UL)) radix = 100UL;
vfo_t = eeprom_read_dword((const uint32_t *)EE_SAVED_AFREQ);
if ((vfo_t < F_MIN) | (vfo_t > F_MAX)) vfo_t = 14000000ULL;
bfo_f = eeprom_read_dword((const uint32_t *)EE_SAVED_BFREQ);
if ((bfo_f < F_MIN) | (bfo_f > F_MAX)) bfo_f = 9000000ULL;
vco_c = 0;
if (eeprom_read_dword((const uint32_t *)EE_SAVED_CALBR) == 0x60) {
vco_c = eeprom_read_dword((const uint32_t *)EE_SAVED_OFSET);
}
xt_freq = SI5351_XTAL_FREQ + vco_c;
//initialize the Si5351
si5351.set_correction(0); // Set to zero because I'm using an other calibration method
si5351.init(SI5351_CRYSTAL_LOAD_8PF, xt_freq); // Frequency get from settings in VFO_si5351.h file
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
// Set CLK0 to output the starting "vfo" frequency as set above by vfo = ?
si5351.set_freq((vfo_t * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK0);
si5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_2MA);
// Set CLK1 to output the Rx frequncy = vfo +/- bfo frequency
if (vfo_t <= bfo_f) vfo_r = vfo_t + bfo_f; // Upper / lower mixing
else vfo_r = vfo_t - bfo_f;
si5351.set_freq((vfo_r * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK1);
si5351.drive_strength(SI5351_CLK1,SI5351_DRIVE_2MA);
// Set CLK2 to output bfo frequency
si5351.set_freq((bfo_f * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK2);
si5351.drive_strength(SI5351_CLK2,SI5351_DRIVE_2MA);
// Clear the buffer.
display.clearDisplay();
display.display();
// text display tests
display.setTextSize(1);
display.setTextColor(WHITE);
// Encoder setup
pinMode(ENCODER_BTN, INPUT_PULLUP);
PCICR |= (1 << PCIE2); // Enable pin change interrupt for the encoder
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
sei();
// Pin Setup
pinMode(Calibrbtn, INPUT_PULLUP); // Calibrate
pinMode(RIT_Switch, INPUT_PULLUP); // RIT Switch
pinMode(TX_Switch, INPUT_PULLUP); // Select TRx or BFO
// Display first time
display_frequency(); // Update the display
}
/**************************************/
/* L O O P */
/**************************************/
void loop()
{
if (disp_txt == 4) {
delay(3000); // Display calibration OK and wait 3 seconds
disp_txt = 0;
}
get_button();
// Update the display if the frequency has been changed
if (changed_f) {
display_frequency();
if (act_clk == 0 && !calibrate) // No Tx update during calibrate
si5351.set_freq((vfo_t * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK0);
else if (act_clk == 2) // BFO update
si5351.set_freq((bfo_f * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK2);
// Update Rx frequency
if (vfo_t <= bfo_f) vfo_r = vfo_t + bfo_f; // Upper / lower mixing
else vfo_r = vfo_t - bfo_f;
si5351.set_freq((vfo_r * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK1);
changed_f = 0;
disp_txt = 0; // Clear line
}
RIT_switch(); // read RIT switch
// Button press
// Also stored the last used frequency together with the step size before store
//
if (get_button()) {
if (stepflag) { // Stepsize button
eeprom_write_dword((uint32_t *)EE_SAVED_RADIX, radix); // Store frequency and stepsize
eeprom_write_dword((uint32_t *)EE_SAVED_AFREQ, vfo_t);
switch (radix)
{
case 1:
radix = 10;
break;
case 10:
radix = 100;
break;
case 100:
radix = 1000;
break;
case 1000:
radix = 10000;
break;
case 10000:
radix = 100000;
break;
case 100000:
radix = 1000000;
break;
case 1000000:
radix = 10;
break;
}
stepflag = 0;
}
else if (modeflag) { // Mode button
if (act_clk == 0) act_clk = 2; else act_clk = 0;
eeprom_write_dword((uint32_t *)EE_SAVED_BFREQ, bfo_f);
modeflag = 0;
disp_txt = 0; // Clear line
}
else if (calflag) { // Calibrate button
if (!digitalRead(RIT_Switch)){ // RIT is on
disp_txt = 1; // Message RIT off
}
else if (act_clk == 2){ // BFO mode on
disp_txt = 2; // Message BFO off
}
else if (!calibrate) { // Start calibrate
vfo_s = vfo_t; // Save actual freq
old_radix = radix; // and stepsize
vfo_t = SI5351_XTAL_FREQ; // en set to default x-tal
disp_txt = 3; // Message Calibrate
calibrate = 1;
radix = 10; // Set to 10 Hz
si5351.set_freq((vfo_t * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK0); // Set CLK0
}
else if (calibrate) { // after tuning x-tal freq
calibrate = 0;
vco_c = vfo_t - SI5351_XTAL_FREQ; // difference
vfo_t = vfo_s; // restore freq
radix = old_radix; // and stepsize
disp_txt = 4; // Message Calibrate OK
eeprom_write_dword((uint32_t *)EE_SAVED_OFSET, vco_c); // store correction
xt_freq = SI5351_XTAL_FREQ + vco_c; // Calibrated x-tal freq
eeprom_write_dword((uint32_t *)EE_SAVED_CALBR, 0x60); // Calibrated
si5351.init(SI5351_CRYSTAL_LOAD_8PF, xt_freq); // Initialize
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
si5351.set_freq(bfo_f * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK2); // correct BFO frequency
si5351.set_freq(vfo_t * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0); // Correct Tx freq
if (vfo_t <= bfo_f) vfo_r = vfo_t + bfo_f; // Upper / lower mixing
else vfo_r = vfo_t - bfo_f;
si5351.set_freq(vfo_r * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK1); // correct Rx frequency
}
calflag = 0;
}
}
display_frequency(); // Update display
} // end while loop
ssd1306_command(uint8_t c);
или подправить библиотеку
static const uint8_t PROGMEM init3[] = {SSD1306_MEMORYMODE, // 0x20
0x00, // 0x0 act like ks0108
SSD1306_SEGREMAP ,
SSD1306_COMSCANINC};
Понял. Попробую.
Сделал как рекомендовано. Первая корректировка, выводит ошибку при компиляции.
Вторая корректировка, компилируется,
но результат остается без изменений. Изображение на дисплее перевернутое, на 180 градусов. Что не так?
Оно оно чё, Михалыч… Он оно чё…
Пиз…ец…
“и эти люди запрешают мне ковырятьмя в носу”
Вторую правку надо делать в коде самой библиотеки !!!
Первая - это прототип функции для примера. Надо ее дважды (команды то две у нас) вызвать с нужными данными.
Сейчас библиотеку ему поправишь - Задолбаешься объяснять как её “подхватить…”
Библиотеки подправлять не рекомендуется, они общего применения. А через изменения в самом скетче, разве нельзя реализовать разворот изображения дисплея на 180 градусов?
как её “подхватить…”
Так подскажите.
Что-то мне кажется, что из setup’а просто так это не пропихнуть…
Ну да ладно, попробуй так (авось сработает):
Вместо этого кода:
// Clear the buffer.
display.clearDisplay();
display.display();
Вставь вот этот:
// Clear the buffer.
display.ssd1306_command(0xA0);
display.ssd1306_command(0xC0);
display.clearDisplay();
display.display();
Но что-то я сомневаюсь )))
Или это:
// Clear the buffer.
display.ssd1306_command(0xA1);
display.ssd1306_command(0xC8);
display.clearDisplay();
display.display();
Да напишите уже весь код за ТС, а то с вероятностью 99% у него защита горит …
Мне просто интересно - пропихнется или нет из setup ))
Вам уже нарисовали строки, которые надо вставить, раз вам самому ума ге хватило подставить A0 и C0 …
А что помешает ?
Я с этим дисплеем никогда не работал. Может быть у него последовательность посыла команд имеется? Или нет?
Вы слишком хорошего мнения об этом дисплее!
ТС может осилит скопировать две нужные строчки и порадует нас картинкой …
Вангую что 10 строк скопирует и опять нихуа не заработает … и станете вы как и я 'подсказчиком хрЕновым"…