OLED дисплей 128*64 (вроде как ssd1306) показывает текст и фигуры через строку (т.е. одну строку закрашивает, следующую нет, после нее закрашивает и так далее.)

Я понял. О результате отпишусь :wink:

Собрал Универсальный синтезатор на микросхеме Si5351
Полный пакет библиотек и скетч в файле vfo-si5351-new.zip (102 кб)
Скетч рабочий. Скомпилировался и загрузился без проблем.


Всё бы хорошо, но изображение перевернуто на 180 градусов.

Вопрос остался открытым. Куда вписать вышеуказанные строки, в скетч, что бы свершилось ожидаемое “чудо”? :thinking:

С этого нужно было начинать. И код вставить по правилам форума.

Простите ошибочка с фото. Второе фото уже не актуально. Вот правильное фото дисплея собранного проекта.

ВНИМАТЕЛЬНО прочти #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 градусов. Что не так?

:rofl:

Оно оно чё, Михалыч… Он оно чё… :laughing:

Пиз…ец…
“и эти люди запрешают мне ковырятьмя в носу”
Вторую правку надо делать в коде самой библиотеки !!!
Первая - это прототип функции для примера. Надо ее дважды (команды то две у нас) вызвать с нужными данными.

Сейчас библиотеку ему поправишь - Задолбаешься объяснять как её “подхватить…” :laughing:

Библиотеки подправлять не рекомендуется, они общего применения. А через изменения в самом скетче, разве нельзя реализовать разворот изображения дисплея на 180 градусов?

как её “подхватить…”
Так подскажите. :grinning:

Что-то мне кажется, что из 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% у него защита горит …

2 лайка

Мне просто интересно - пропихнется или нет из setup ))

Вам уже нарисовали строки, которые надо вставить, раз вам самому ума ге хватило подставить A0 и C0 …

А что помешает ?

Я с этим дисплеем никогда не работал. Может быть у него последовательность посыла команд имеется? Или нет?

Вы слишком хорошего мнения об этом дисплее!

ТС может осилит скопировать две нужные строчки и порадует нас картинкой …

Вангую что 10 строк скопирует и опять нихуа не заработает … и станете вы как и я 'подсказчиком хрЕновым"…

1 лайк