Вопросы по OLED-дисплеям на контроллере SSD1306

qbaddev

✩✩✩✩✩✩✩
23 Апр 2020
54
8
23
[email protected]
t.me
Кто знает, если для SSD1306 легкая библиотека? Мне нужно только рисовать по пикселям.
Пытался написать свою, но что то пошло не так...
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,407
976
58
Марий-Эл
С графикой лёгких нет. Только текстовые.
Во всех графических библиотеках используется буфер в памяти микроконтроллера. В котором формируется изображение которое потом скидывается в контроллер дисплеях.
Может и существуют такие, но я этим вопросом не задавался.
Я им наигрался и бросил.
 
  • Лойс +1
Реакции: Mix_man и qbaddev

qbaddev

✩✩✩✩✩✩✩
23 Апр 2020
54
8
23
[email protected]
t.me
С графикой лёгких нет. Только текстовые.
Во всех графических библиотеках используется буфер в памяти микроконтроллера. В котором формируется изображение которое потом скидывается в контроллер дисплеях.
Может и существуют такие, но я этим вопросом не задавался.
Я им наигрался и бросил.
Спасибо)
 

qbaddev

✩✩✩✩✩✩✩
23 Апр 2020
54
8
23
[email protected]
t.me
Пишу в Atmel Studio, работаю с дисплеем через I2C.
Написал примитивный код по готовым библиотекам и даташиту (кривому).

При отправке команд на отрисовку пикселей, они рисуются тольков опредленных координатах по Y.
Текст работает отлично.

(I2C - полный аналог Wire, просто на чистом си)
Код:
    I2C_beginTransmission(OLED_ADDRESS);
    I2C_write(OLED_COMMAND_MODE);
    I2C_write(0x21); I2C_write(x); I2C_write(127);
    I2C_write(0x22); I2C_write(y / 8); I2C_write(3);
    I2C_endTransmission();
  
    I2C_beginTransmission(OLED_ADDRESS);
    I2C_write(OLED_DATA_MODE);
    I2C_write(1 << (y % 8));
    I2C_endTransmission();
Пишу в Atmel Studio, работаю с дисплеем через I2C.
Написал примитивный код по готовым библиотекам и даташиту (кривому).

При отправке команд на отрисовку пикселей, они рисуются тольков опредленных координатах по Y.
Текст работает отлично.

Код:
    I2C_beginTransmission(OLED_ADDRESS);
    I2C_write(OLED_COMMAND_MODE);
    I2C_write(0x21); I2C_write(x); I2C_write(127);
    I2C_write(0x22); I2C_write(y / 8); I2C_write(3);
    I2C_endTransmission();
   
    I2C_beginTransmission(OLED_ADDRESS);
    I2C_write(OLED_DATA_MODE);
    I2C_write(1 << (y % 8));
    I2C_endTransmission();
В реальности горизонтально линии не прирывыстые.
 

Вложения

qbaddev

✩✩✩✩✩✩✩
23 Апр 2020
54
8
23
[email protected]
t.me
Я работал.
Там система инициализации - не пара строк.
ssd1306.h:
#include "font.h"

#define OLED_ADDRESS            0x3c
#define OLED_COMMAND_MODE       0x00
#define OLED_ONE_COMMAND_MODE   0x80
#define OLED_DATA_MODE          0x40
#define OLED_ONE_DATA_MODE      0xC0

#define OLED_W 128
#define OLED_H 32

void OLED_init();
void OLED_clear();
void OLED_setCursor(unsigned char row, unsigned char line);
void OLED_print(const char *string);

void OLED_sendCmd(unsigned char state);
void OLED_sendChar(char data);
void OLED_pixel(byte x, byte y);


static const uint8_t _oled_init[] PROGMEM = {
    0xAE,    //
    0xD5,    // CLOCK_DIV_RATIO
    0x80,
    0x8D,    // Charge pump
    0x14,
    0x20,    // Memory mode
    0x01,    // Vertical _addressing
    0xA1,    // Flip horizontally
    0xC8,    // Flip vertically
    0x81,    // Set contrast
    0xCF,    // brighter
    0xDB,    //
    0x40,    // brighter
    0xAF,    //
};

void OLED_init() {
    I2C_init();
    
    /*
    OLED_sendCmd(0xae);
    OLED_sendCmd(0xa1);
    OLED_sendCmd(0xaf);*/
    
    I2C_beginTransmission(OLED_ADDRESS);
    I2C_write(OLED_COMMAND_MODE);
    for (uint8_t i = 0; i < 15; i++) I2C_write(pgm_read_byte(&_oled_init[i]));
    
    I2C_write(0xDA);
    I2C_write(0x02);
    
    I2C_write(0xA8);
    I2C_write(0x1F);
    
    I2C_endTransmission();
    
    delay(10);
    OLED_clear();
}

void OLED_clear() {
    /*unsigned char i, k;
    for(k = 0; k < 2; k++) {
        OLED_setCursor(0, k);
        for(i = 0; i < 128; i++) {//clear all COL
            OLED_sendChar(0);
        }
    }*/
    I2C_beginTransmission(OLED_ADDRESS);
    I2C_write(OLED_COMMAND_MODE);
    I2C_write(0x21); I2C_write(0); I2C_write(127);
    I2C_write(0x22); I2C_write(0); I2C_write(3);
    I2C_endTransmission();
    for (int i = 0; i < 32; i++) {
        I2C_beginTransmission(OLED_ADDRESS);
        I2C_write(OLED_DATA_MODE);
        for (int i = 0; i < 32; i++) I2C_write(0);
        I2C_endTransmission();
    }
}

void OLED_setCursor(unsigned char row, unsigned char line) {
    unsigned char realrow = row;
    OLED_sendCmd(0xb1 + line);
    OLED_sendCmd(0x00 + (8 * realrow & 0x0f));
    OLED_sendCmd(0x10 + ((8 * realrow >> 4) & 0x07));
}

void OLED_print(const char *string) {
    char i = 0;
    while(*string) {
        for(i=0;i<8;i++) {
            OLED_sendChar(pgm_read_byte_near(OLED_Font + (*string - 0x20) * 8 + i));
        }
        *string++;
    }
}

void OLED_sendCmd(unsigned char state) {
    I2C_beginTransmission(OLED_ADDRESS);
    I2C_write(OLED_ONE_COMMAND_MODE);
    I2C_write(state);
    I2C_endTransmission();
}

void OLED_sendChar(char data) {
    I2C_beginTransmission(OLED_ADDRESS);
    I2C_write(0x40);
    I2C_write(data);
    I2C_endTransmission();
}

void OLED_pixel(byte x, byte y) {
    I2C_beginTransmission(OLED_ADDRESS);
    I2C_write(OLED_COMMAND_MODE);
    I2C_write(0x21); I2C_write(x); I2C_write(127);
    I2C_write(0x22); I2C_write(y / 8); I2C_write(3);
    I2C_endTransmission();
    
    I2C_beginTransmission(OLED_ADDRESS);
    I2C_write(OLED_DATA_MODE);
    I2C_write(1 << (y % 8));
    I2C_endTransmission();
}
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,407
976
58
Марий-Эл
Лучше не связываться с этим дисплеем.
Организация памяти дурная. Работать с ним сложно. Очень маленький.
И за те деньги, что он стоит, можно купить 1.8" цветной дисплей.
 

qbaddev

✩✩✩✩✩✩✩
23 Апр 2020
54
8
23
[email protected]
t.me
Лучше не связываться с этим дисплеем.
Организация памяти дурная. Работать с ним сложно. Очень маленький.
И за те деньги, что он стоит, можно купить 1.8" цветной дисплей.
Насчет 1.8" - не правда. Где ты так дешево найдешь?
Да и скорость поменьше будет. Этот дисплей поговаривают до 35 FPS выдает.

И еще, он уже есть. А делать нечего...
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,407
976
58
Марий-Эл
Этот дисплей поговаривают до 35 FPS выдает
На лифте тоже много чего написано. Тем не менее он железный и поднимается на тросе.
Такую скорость можно получить только выводя готовые картинки.
Посчитай, сколько байт нужно ему пихнуть для вывода картинки, посчитай сколько выдерживает интерфейс. И ты узнаешь чистое время вывода, без пересчёта картинки, а если начнёшь её ещё и считать.....
На любом дисплее можно получить что то приличное, но придётся забыть про библиотеки.
Wfvgat пока не доступен. Поэтому скину скриншот
1594662549665.png
Ну и как разница в цене?
Прямо огромная?
А цветным работать проще и быстрее.
 
  • Лойс +1
Реакции: qbaddev

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
573
@qbaddev, что именно не работало? Все примеры в examples 146% работают с дисплеем на SSD1306 и разрешением 128х64 и 128х32. Текст, геометрия и битмапы.
 

Askelat

✩✩✩✩✩✩✩
17 Авг 2020
2
0
Тоже столкнулся с проблемой, при подключении OLED_EXTFONTS и выборе любого шрифта print() работает хорошо, а println() при переносе похоже учитывает высоту стандартного шрифта а не дополнительного. Пробовал на 128x32 и 128x64. Может кто знает решение?
 

Askelat

✩✩✩✩✩✩✩
17 Авг 2020
2
0
Решение очевидное - рассчитывать высоту строчек самостоятельно и размещать текст вручную по координатам
Да, действительно, до этого пробовал но что-то не получалось, наверное где-то ошибся, спасибо.
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,407
976
58
Марий-Эл
Да, действительно, до этого пробовал но что-то не получалось, наверное где-то ошибся, спасибо.
Можно новую позицию по Y вообще вычислять опираясь на размер шрифта по вертикали и увеличение шрифта.
Когда я сам писал библиотеку, я так и делал.
 

druna20031

✩✩✩✩✩✩✩
10 Фев 2021
1
0
Сразу скажу, что это первый мой проект, так что сильно не пинайте. Не могу понять, как заставить дисплей ВКЛЮЧАТЬСЯ после выключения.
C++:
void setup() {
Serial.begin(9600);
attachInterrupt(1, inter, FALLING);  //подключает прерывания
power.setSystemPrescaler(PRESCALER_2); //делитель для работы на 8 мегагерцах
power.setSleepMode(POWERDOWN_SLEEP); //режим сна (глубокий)
// Пины D9 и D10 - 31.4 кГц
TCCR1A = 0b00000001 ;  // 8bit
TCCR1B = 0b00000001;   // x1 phase correct
analogReference(INTERNAL);    // опорное напряжение в 1,1в
pinMode(tranz, OUTPUT);   // настройка пина транзистора

  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);  // инициализация подачи питания на дисплей

  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH); // подача питания на дисплей
  digitalWrite(9, 0);
  delay(100);
  oled.init();
  oled.clear();
  oled__();
кусок из сетапа, который может о чем то скажет, пины 7 и 8 подают питание на дисплей.
C++:
    if (down.isHolded() && ON == 1) {
       OFF__();
      }
      void ON__() {
// digitalWrite(7, HIGH);
//  digitalWrite(8, HIGH);
  digitalWrite(9, 0);
  power.hardwareEnable(PWR_ADC | PWR_I2C);
  delay(100);
  delay(50);
  Wire.begin();
  delay(50);
  oled.init();
  oled.clear();
  oled__();
  ON = 1;
  Serial.print("Я родился");
}
  void OFF__() {
  ON = 0;
  oled.clear();
  oled.setScale(2);
  oled.setCursorXY(36, 42);  
  oled.print("ЧАО))");
  delay(1300);
  oled.clear();
  power.hardwareDisable(PWR_ADC | PWR_I2C);
  delay(50);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  analogWrite (9, 0); //вырубает транзистор
  Serial.println("Выключено");
  delay(50);
  power.sleep(SLEEP_FOREVER);
}
    void inter() { //ф-я для включения через прерывания
      if (ON_ == 0) {
      up.tick();
    if (up.isHolded() && ON == 0) {ON_ = 1; ON__();}
      }
  }
тут самый первый кусочек из лупа, который вызывает функцию выключения дисплея. Далее как раз начинаются проблемы, дисплей выключается, выводится надпись, мол я выключился и далее должно происходить следующее: я нажимаю кнопку которая подвязана на аппаратные прерывания, она запускает функцию, которая вызывает функцию включения дисплея (ON__()) и в ф-ии включения дисплея должен включится собственно дисплей. Но после выключения у меня ардуино зависает дисплей не загорается. Вот весь код (это должен быть вейп).
 

Вложения

demiz

✩✩✩✩✩✩✩
25 Фев 2021
1
0
Доброго времени суток.
Помогите понять, в чем проблема. Итак, имеем:
1. OLED экран 0,91' размером 128*32 пикселя, подключен к Ардуино нано по I2C
2. Простенький скетч для проверки работоспособности:

C++:
#include <GyverOLED.h>
GyverOLED<SSD1306_128x32, OLED_NO_BUFFER> oled;

void setup() {
  Serial.begin(9600);
  oled.init();              // инициализация
  oled.clear();
}
  void loop() {

oled.setScale(1);
oled.setCursor(0, 0);
oled.print("morning");
oled.setCursor(0,1);
oled.print("day");
oled.setCursor(0,2);
oled.print("evening");
oled.setCursor(0,3);
oled.print("night");
    
  }
Проблема: не выводит 4-ю строку. Причем с библиотекой Adafruit выводит корректно все четыре строки.
 

kostyamat

★★★★★★✩
29 Окт 2019
1,098
632
@druna20031, я не думаю, что ардуино, как мастеру на шине i2c нравится тот факт, што slave (раб) на шине постоянно куда-то на пиво убегает. И когда раб возвращеться, они долго соряться, и им явно не до ваших проблем. Чисто мое имхо.
 

MadMouse

✩✩✩✩✩✩✩
26 Мар 2021
4
3
Всем доброго здравия!
@druna20031, Удалось решить проблему?
Сам с такой проблемой боролся пару вечеров.
Дерни А4, А5 к нулю после выключения питания дисплея и все получится.
 
  • Лойс +1
Реакции: kostyamat

kostyamat

★★★★★★✩
29 Окт 2019
1,098
632
@MadMouse, а может стоит до выключения дисплея сделать Wire.end(), а после включения Wire.begin()? Имхо, так красивше.
 

MadMouse

✩✩✩✩✩✩✩
26 Мар 2021
4
3
@kostyamat, Wire.endTransmission() красиво, спору нет (в моем приложении так и делается до выключения), но только этого не достаточно. Пока линии шины I2C к нулю не притянешь дисплей во второй раз не стартует. Может быть, это как то связано с фантомным питанием от линий шины.