И еще одно замечание: судя по myOLED.upgate(), используется библиотека с буферизацией. Во многих проектах это недопустимо ресурсоемко. Ну и, кроме того, не позволяет подключить к одному контроллеру типа Atmega328 более одного дисплея.
Отсюда пожелание: переделать все примеры на библиотеку без экранного буфера. К сожалению, это вопрос не чисто механического переноса, т.к. нужно будет адаптировать сами "картинки" под аппаратные возможности дисплея.
Думал над этим. Нет хороших графических библиотек без буфера у меня на примете, а так да, сразу можно на про мини 168 замахнуться :-)
Отсюда пожелание: переделать все примеры на библиотеку без экранного буфера. К сожалению, это вопрос не чисто механического переноса, т.к. нужно будет адаптировать сами "картинки" под аппаратные возможности дисплея.
drawCircle без экранного буфера ?
Что Вы хотели сказать этим вопросом?
Переделывать, очевидно, нужно не drawCircle, а процедуру вывода изображения на дисплей. Если непонятно, скажу проще: нужно отказываться от drawCircle и других функций, которые не могут работать без экранного буфера.
lilik пишет:
Думал над этим. Нет хороших графических библиотек без буфера у меня на примете, а так да, сразу можно на про мини 168 замахнуться :-)
А их и не может быть. По определению - многие графические операции не могут быть выполнены аппаратно на этом дисплее.
Собственно, именно в этом и заключается "изюминка" - при невозможности реализации универсальных функций отрисовки придумать и реализовать способы обхода этого ограничения в каждом конкретном случае. И задача из чисто механической сразу переходит в разряд творческих.
andriano я прекрасно умею общаться с SSD1306 без буфера, без библиотеки - напрямую. Просто у ТС есть вызовы функций, которые реализовать без буфера достаточно проблематично.
andriano я прекрасно умею общаться с SSD1306 без буфера, без библиотеки - напрямую. Просто у ТС есть вызовы функций, которые реализовать без буфера достаточно проблематично.
Их не нужно реализовывать. Нужно придумать им замену для конкретного случая.
Как в принципе можно обойтись без буфера? Предположим есть функция математическая как строить фигуру по точкам. "Одну точку" не передать в экран, а только 8 "одного байта" по конкретному адресу. Если точек 200 - это 200 передач по адресам. Они быстрее чем 1 по всем адресам?
Как в принципе можно обойтись без буфера? Предположим есть функция математическая как строить фигуру по точкам. "Одну точку" не передать в экран, а только 8 "одного байта" по конкретному адресу. Если точек 200 - это 200 передач по адресам. Они быстрее чем 1 по всем адресам?
Другая логика работы используется. Для фигур все сложно, но возможно ...
Как в принципе можно обойтись без буфера? Предположим есть функция математическая как строить фигуру по точкам. "Одну точку" не передать в экран, а только 8 "одного байта" по конкретному адресу. Если точек 200 - это 200 передач по адресам. Они быстрее чем 1 по всем адресам?
Другая логика работы используется. Для фигур все сложно, но возможно ...
Как в принципе можно обойтись без буфера? Предположим есть функция математическая как строить фигуру по точкам. "Одну точку" не передать в экран...
Правильно рассуждаешь.
Но медленно. На каждый маленький шажочек нужен очередной толчок.
Раз "одну точку не передать на экран", значит, следует принципиально избавляться от попиксельной графики. Т.е. рассматривать экран не как набор пикселей, а как набор более крупных примитивов. Хотя бы 8-пиксельных. А желательно - больше. Скажем N*M, где N - кратно 8, а M - больше 1.
А желательно - больше. Скажем N*M, где N - кратно 8, а M - больше 1.
Так можно реализовывать вывод текста, имея в постоянной памяти картинки букв размером N*M, но в графике как , например, вывести отрезок заданной длины, под заданным углом? Мне кажется, в общем случае без буфера, хоть и скромного размера, не обойтись. Кстати если бы в используемой мной библиотеке буфер сократили в 2 раза, а вывод разделили на 2 части - про мини 168 справилась бы уже. "Вообщем" тема "безбуферных графических библиотек" для ssd1306 не мой уровень творчества :-(
Пришёл таки второй экранчик. От радости захотелось узоров.
////////////// генератор узоров для ковра
#include <OLED_I2C.h>
OLED myOLED(SDA, SCL);
int t = 1000; // пауза между сменой рисунка ковра
int uz = 1000; // плотность узора ковра
void setup()
{
myOLED.begin();
myOLED.invert(0);//инверсия цвета
}
void loop()
{
myOLED.clrScr(); // очищаем дисплей
int p = map(analogRead(A0), 0, 1023, 0, 100); //размер ковра
/////
for (int i = 0; i < uz; i++) {
int x = random(0, 128);
int y = random(0, 64);
if (x * x + y * y < p * p) {//вышиваем, выплетаем узоры
myOLED.setPixel(x + 63, y + 32);
myOLED.setPixel(x + 63, -y + 32);
myOLED.setPixel(-x + 63, -y + 32);
myOLED.setPixel(-x + 63, y + 32);
}
}
///
myOLED.update(); delay(t);
}
Так можно реализовывать вывод текста, имея в постоянной памяти картинки букв размером N*M, но в графике как , например, вывести отрезок заданной длины, под заданным углом?
Другими словами, Вы согласны решать исключительно тривиальные задачи?
Цитата:
Мне кажется, в общем случае без буфера, хоть и скромного размера, не обойтись.
В общем случае - да.
Но речь идет не об общем, а о частном конкретном случае: для каждого из вариантов "шкал" придумать такой алгоритм, который позволит обойтись без буфера.
Берем OLED128х64, Цепляем к нему Нанку, общаемся по I2C, на Нанке - драйвер со всеми примитивами графики, анимации, 3Д элементов. И уже это "бутерброд" используем как экран для своей поделки, в которой уже не нужен будет буфер.
Вот тока не надо говорить, что я изобрел Некстион! ;))) Моя идея дешевше будет!
Берем OLED128х64, Цепляем к нему Нанку, общаемся по I2C, на Нанке - драйвер со всеми примитивами графики, анимации, 3Д элементов. И уже это "бутерброд" используем как экран для своей поделки, в которой уже не нужен будет буфер.
Вот тока не надо говорить, что я изобрел Некстион! ;))) Моя идея дешевше будет!
Я вроде писал уже, что (чисто ИМХО, не настаиваю! ...ну кроме как на перце и зубровке ;)) ) что кнопки и индикацию отмел для себя полностью. Если забыть про 8ми битный "ужОс" в виде АВР, то ESP дает возможность сделать веб-морду, а тилипон всегда в кармане. ;))) Да и памяти там побольше и частота повыше. АВР-ки в автомобиль оставляю - 5В немного более устойчивы к помехам и интерфейс мне там не нужен никакой.
/////////////////// индикатор наполнения ёмкости жидкостью
#include <OLED_I2C.h>
OLED myOLED(SDA, SCL);
extern const unsigned char schkala_A[];
int t = 30; // пауза между считываниями потенциометра
int pp = 0; // переменная для хранения предыдущего значения уровня
void setup()
{
myOLED.begin();
myOLED.invert(0);//инверсия цвета
}
void loop()
{
myOLED.drawBitmap(0, 0, schkala_A, 128, 64); // рисование картинки ёмкости
int p = map(analogRead(A0), 0, 1023, 15, 122); // считывание потенциометра и определение высоты уровня жидкости
if (abs(p - pp) > 1) { //если значение уровня поменялось выше порогового в 1 единицу
myOLED.drawRect(p, 8, 122, 54); // прорисовка контура столба жидкости
for (int i = 0; i < 2000 - p * 15; i++) { // прорисовка столба жидкости
int x = random(p, 122);
int y = random(8, 54);
myOLED.setPixel(x , y );
}
myOLED.update(); delay(t);
pp = p; //запоминание "нового предыдущего" значения
}
}
Но речь идет не об общем, а о частном конкретном случае: для каждого из вариантов "шкал" придумать такой алгоритм, который позволит обойтись без буфера.
Я придумал общий алгоритм для графической библиотеки совсем без буфера экрана. Но реализовать его сам едва ли смогу. Да и Ардуино тоже :-) Попробую изложить его простым языком, если получится, может сведущие разберутся.
Это индикация дозы (в каплях). А еще же нужен контроль остатков. И еще можно добавить расчетное количество промилле в крови (степень готовости), с учетом типа напитка и массы тушки поциЭнта
Итак любую картинку можно представить как множество отрезков, а поле экрана как декартову систему координат. Отрезки описываются уравнением вида:
где x,y координаты подходящих отрезку точек.
Заполнение экрана светящимися (не светящимися) пикселями происходит сначала по столбцам, потом по страницам. Проблема в том, что столбец из 8 точек надо заполнить один раз, зная какие точки в нём принадлежат хотя бы одному из отрезков и потом отправить в экран. То есть каждый текущий бит-точку с координатами x,y надо проверять на принадлежность всем отрезкам картинки. Например, картинка состоит из 100 отрезков, значит Ардуино должна пересчитать 100 условий. А всего около 800000 на картинку прежде чем весь экран отрисуется. Вот и получается, что вместо буфера МК нужен быстро считающий МК.
тема из полезной медленно дрейфует в фарс. Перенесли в "Проекты", скоро придется в "Отвлеченные" переносить :)
ИМХО. тема раскрыта почти полностью - происходит обсуждение по применению... и ТС не виноват, что народ на больную тему понесло. Если чего и переносить, то отдельные посты :)))))
lilik пишет:
...значит Ардуино должна пересчитать 100 условий. А всего около 800000 на картинку прежде чем весь экран отрисуется. Вот и получается, что вместо буфера МК нужен быстро считающий МК.
как-то даже и не удивительно... может видеокарту для ардуино пора придумать? :))))
Итак любую картинку можно представить как множество отрезков...
НизачОт!
Повторяю, наверное, уже в третий или четвертый раз: не нужно пытаться искать универсальное решение (рисование отрезка - это именно элемент универсального решения), нужно рисовать конкретную картинку. Без буфера. И без универсальных примитивов.
А прогресс ли это? Все шрифты набиты картинками в библиотеках под экранчики. Буквы-цифры не повернуть и не масштабировать. И тем не менее по другому не делают.
В коде я конечно не понял ничего, но подход ясен - буфер размером с символ, символ это отрезки-кривые, масштабирование, повороты. Вот мне и интересно, почему авторы библиотеки OLED_I2C не делали векторные шрифты в довесок к "картиночным"?
Примитивов могли добавить - эллипсов, звёзд,многоугольников, дуг, спиралей и т.д.
Там почитай. С начала автор темы хотел много разных примитивов. По ходу отказались. Отрезков для шрифтов с головой хватает. На таких разрешениях, как экран этот, дуги легко аппроксимируются.
//Вот мне и интересно, почему авторы библиотеки OLED_I2C не делали векторные шрифты в довесок к "картиночным"?
В векторном шрифте вся загвоздка в формате хранения. Нужно хранить очень сжато и распаковывать быстро. А растровый напрягов не требует.
Ждём тетриса!
Мне кажется, слишком контрастно.
Я бы попробовал вместо сплошной заливки использовать полутона, реализуемые чем-то вроде шахматного поля (квадратик - 1 пиксель).
///////////////////стрелочный индикатор уровня сигнала #include <OLED_I2C.h> OLED myOLED(SDA, SCL); int t = 50; // пауза между считываниями потенциометра void setup() { myOLED.begin(); myOLED.invert(0);//инверсия цвета } void loop() { myOLED.clrScr(); // очищаем дисплей int x = map(analogRead(A0), 0, 1023, 5, 124); //считывание данных с потенциометра и задание координаты стрелки myOLED.drawRect(0, 0, 127, 63); //рамка myOLED.drawLine(x, 5, x, 58); // стрелка и её положение myOLED.drawRect(5, 22, 90, 42); //шкала прогресса myOLED.drawRect(95, 22, 124, 42); ///// for (int j = 0; j < 20; j = j + 3) { // раскраска прямоугольника точками for (int i = 0; i < 30; i = i + 2) { myOLED.setPixel(95 + i, 22 + j); } } /// myOLED.update(); delay(t); }Подправил.
И еще одно замечание: судя по myOLED.upgate(), используется библиотека с буферизацией. Во многих проектах это недопустимо ресурсоемко. Ну и, кроме того, не позволяет подключить к одному контроллеру типа Atmega328 более одного дисплея.
Отсюда пожелание: переделать все примеры на библиотеку без экранного буфера. К сожалению, это вопрос не чисто механического переноса, т.к. нужно будет адаптировать сами "картинки" под аппаратные возможности дисплея.
Думал над этим. Нет хороших графических библиотек без буфера у меня на примете, а так да, сразу можно на про мини 168 замахнуться :-)
Отсюда пожелание: переделать все примеры на библиотеку без экранного буфера. К сожалению, это вопрос не чисто механического переноса, т.к. нужно будет адаптировать сами "картинки" под аппаратные возможности дисплея.
drawCircle без экранного буфера ?
Что Вы хотели сказать этим вопросом?
Переделывать, очевидно, нужно не drawCircle, а процедуру вывода изображения на дисплей. Если непонятно, скажу проще: нужно отказываться от drawCircle и других функций, которые не могут работать без экранного буфера.
Думал над этим. Нет хороших графических библиотек без буфера у меня на примете, а так да, сразу можно на про мини 168 замахнуться :-)
А их и не может быть. По определению - многие графические операции не могут быть выполнены аппаратно на этом дисплее.
Собственно, именно в этом и заключается "изюминка" - при невозможности реализации универсальных функций отрисовки придумать и реализовать способы обхода этого ограничения в каждом конкретном случае. И задача из чисто механической сразу переходит в разряд творческих.
andriano я прекрасно умею общаться с SSD1306 без буфера, без библиотеки - напрямую. Просто у ТС есть вызовы функций, которые реализовать без буфера достаточно проблематично.
andriano я прекрасно умею общаться с SSD1306 без буфера, без библиотеки - напрямую. Просто у ТС есть вызовы функций, которые реализовать без буфера достаточно проблематично.
Их не нужно реализовывать. Нужно придумать им замену для конкретного случая.
Заготовка под вывод ошибок OBD:
#define SCL0PORT PORTC #define SCL0PIN PORTC5 #define SDA0PORT PORTC #define SDA0PIN PORTC4 #define SCL1PORT PORTB #define SCL1PIN PORTB3 #define SDA1PORT PORTB #define SDA1PIN PORTB4 #include <avr/pgmspace.h> void __attribute__ ((noinline)) i2c_init(uint8_t device=0) { asm volatile( "TST %8\n\t" "BRNE i2c_init_1\n\t" "CBI %0-1,%1\n\t" "CBI %2-1,%3\n\t" "CBI %2,%3\n\t" "CBI %0,%1\n\t" "RJMP i2c_init_2\n\t" "i2c_init_1:\n\t" "CBI %4-1,%5\n\t" "CBI %6-1,%7\n\t" "CBI %6,%7\n\t" "CBI %4,%5\n\t" "NOP\n\t" "i2c_init_2:\n\t" ::"I" (_SFR_IO_ADDR(SCL0PORT)), "I" (SCL0PIN), "I" (_SFR_IO_ADDR(SDA0PORT)), "I" (SDA0PIN), "I" (_SFR_IO_ADDR(SCL1PORT)), "I" (SCL1PIN), "I" (_SFR_IO_ADDR(SDA1PORT)), "I" (SDA1PIN), "r" (device) ); } void __attribute__ ((noinline)) i2c_start(uint8_t device=0) { asm volatile( "SBRS %4,0\n\t" "SBI %0-1,%1\n\t" "SBRC %4,0\n\t" "SBI %2-1,%3\n\t" ::"I" (_SFR_IO_ADDR(SDA0PORT)), "I" (SDA0PIN), "I" (_SFR_IO_ADDR(SDA1PORT)), "I" (SDA1PIN), "r" (device) ); } void __attribute__ ((noinline)) i2c_write(uint8_t data, uint8_t device=0) { uint8_t b,i; asm ( "LDI %10,8\n\t" "i2c_write_1:" "SBRS %8,0\n\t" "SBI %0-1,%1\n\t" "SBRC %8,0\n\t" "SBI %4-1,%5\n\t" "ROL %9\n\t" "BRCS i2c_write_2\n\t" "SBRS %8,0\n\t" "SBI %2-1,%3\n\t" "SBRC %8,0\n\t" "SBI %6-1,%7\n\t" "RJMP i2c_write_3\n" "i2c_write_2:\n\t" "SBRS %8,0\n\t" "CBI %2-1,%3\n\t" "SBRC %8,0\n\t" "CBI %6-1,%7\n\t" "NOP\n" "i2c_write_3:\n\t" "LDI %11,4\n" "i2c_write_4:\n\t" "DEC %11\n\t" "BRNE i2c_write_4\n\t" "SBRS %8,0\n\t" "CBI %0-1,%1\n\t" "SBRC %8,0\n\t" "CBI %4-1,%5\n\t" "LDI %11,2\n" "i2c_write_5:\n\t" "DEC %11\n\t" "BRNE i2c_write_5\n\t" "DEC %10\n\t" "BRNE i2c_write_1\n\t" "NOP\n\t" "SBRS %8,0\n\t" "SBI %0-1,%1\n\t" "SBRC %8,0\n\t" "SBI %4-1,%5\n\t" "SBRS %8,0\n\t" "CBI %2-1,%3\n\t" "SBRC %8,0\n\t" "CBI %6-1,%7\n\t" "TST %8\n\t" "BRNE i2c_write_6\n\t" "NOP\n" "i2c_write_7:\n\t" "SBIC %2-2,%3\n\t" "RJMP i2c_write_7\n\t" "RJMP i2c_write_8\n" "i2c_write_6:\n\t" "SBIC %6-2,%7\n\t" "RJMP i2c_write_6\n\t" "NOP\n\t" "NOP\n" "i2c_write_8:\n\t" "LDI %11,3\n\t" "i2c_write_9:\n\t" "DEC %11\n\t" "BRNE i2c_write_9\n\t" "SBRS %8,0\n\t" "CBI %0-1,%1\n\t" "SBRC %8,0\n\t" "CBI %4-1,%5\n\t" "LDI %11,3\n" "i2c_write_10:\n\t" "DEC %11\n\t" "BRNE i2c_write_10\n\t" "SBRS %8,0\n\t" "SBI %0-1,%1\n\t" "SBRC %8,0\n\t" "SBI %4-1,%5\n\t" "LDI %11,4\n" "i2c_write_11:\n\t" "DEC %11\n\t" "BRNE i2c_write_11\n\t" "NOP\n\t" "NOP\n\t" ::"I" (_SFR_IO_ADDR(SCL0PORT)), "I" (SCL0PIN), "I" (_SFR_IO_ADDR(SDA0PORT)), "I" (SDA0PIN), "I" (_SFR_IO_ADDR(SCL1PORT)), "I" (SCL1PIN), "I" (_SFR_IO_ADDR(SDA1PORT)), "I" (SDA1PIN), "r" (device), "r" (data), "r" (b), "r" (i) ); } void __attribute__ ((noinline)) i2c_stop(uint8_t device=0) { uint8_t i; asm volatile( "SBRS %8,0\n\t" "SBI %2-1,%3\n\t" "SBRC %8,0\n\t" "SBI %6-1,%7\n\t" "LDI %9,6\n" "i2c_stop_1:\n\t" "DEC %9\n\t" "BRNE i2c_stop_1\n\t" "SBRS %8,0\n\t" "CBI %0-1,%1\n\t" "SBRC %8,0\n\t" "CBI %4-1,%5\n\t" "LDI %9,2\n\t" "i2c_stop_2:\n\t" "DEC %9\n\t" "BRNE i2c_stop_2\n\t" "SBRS %8,0\n\t" "CBI %2-1,%3\n\t" "SBRC %8,0\n\t" "CBI %6-1,%7\n\t" "LDI %9,3\n" "i2c_stop_3:\n\t" "DEC %9\n\t" "BRNE i2c_stop_3\n\t" ::"I" (_SFR_IO_ADDR(SCL0PORT)), "I" (SCL0PIN), "I" (_SFR_IO_ADDR(SDA0PORT)), "I" (SDA0PIN), "I" (_SFR_IO_ADDR(SCL1PORT)), "I" (SCL1PIN), "I" (_SFR_IO_ADDR(SDA1PORT)), "I" (SDA1PIN), "r" (device), "r" (i) ); } #define SSD128x64 #define addr 0x3C #if !defined (SSD128x64) static const uint8_t PROGMEM init_bytes[]={addr<<1, 0x00,0xAE,0xD5,0x80,0xA8,0x1F,0xD3,0x00,0x40,0x8D,0x14,0x20,0x00,0xA1,0xC8, 0xDA,0x02,0xD9,0xF1,0xDB,0x40,0x21,0x00,0x7f,0x22,0x00,0x03,0xA4,0xA6,0xAF}; #else static const uint8_t PROGMEM init_bytes[]={addr<<1, 0x00,0xAE,0xD5,0x80,0xA8,0x3F,0xD3,0x00,0x40,0x8D,0x14,0x20,0x00,0xA1,0xC8, 0xDA,0x12,0xD9,0xF1,0xDB,0x40,0xA4,0xA6,0xAF}; #endif static const uint8_t PROGMEM impreza[] = { 0xF8, 0xF8, 0x00, 0x00, 0xF8, 0xF8, 0x38, 0x70, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x38, 0xF8, 0xF8, 0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x38, 0xF0, 0xE0, 0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x38, 0xF0, 0xE0, 0x00, 0x00, 0xE0, 0xF0, 0x38, 0x18, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x98, 0x98, 0xD8, 0xD8, 0x78, 0x78, 0x38, 0x38, 0x18, 0x18, 0x00, 0x00, 0xE0, 0xF0, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x38, 0xF0, 0xE0, 0x1F, 0x1F, 0x00, 0x00, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0E, 0x1C, 0x0E, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x00, 0x00, 0x1F, 0x1F, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x03, 0x01, 0x00, 0x00, 0x1F, 0x1F, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x1F, 0x1B, 0x11, 0x00, 0x00, 0x07, 0x0F, 0x1C, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x00, 0x00, 0x18, 0x18, 0x1C, 0x1C, 0x1E, 0x1E, 0x1B, 0x1B, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x1F, 0x1F, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1F, 0x1F}; static const uint8_t PROGMEM pbcu[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x87, 0xfe, 0xfc, 0x00, 0x00, 0xfc, 0xfe, 0x07, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0xfe, 0xfc, 0x00, 0x00, 0xfc, 0xfe, 0x07, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0xfe, 0xfc, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x87, 0xfe, 0xfc, 0x00, 0x00, 0xfc, 0xfe, 0x07, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0xfe, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x7f, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0x7f, 0x3f, 0x00, 0x00, 0x3f, 0x7f, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0x7f, 0x3f, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7f, 0x3c, 0x00, 0x00, 0x3f, 0x7f, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0x7f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x84, 0xb4, 0xb4, 0x84, 0xfc, 0x00, 0x00, 0xfc, 0x84, 0x84, 0x84, 0x84, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; void setup() { i2c_init(); i2c_start(); for(uint8_t i=0;i<sizeof(init_bytes);i++) i2c_write(pgm_read_byte(init_bytes+i)); asm volatile ("nop\n\t""nop"); i2c_stop(); i2c_start(); i2c_write(addr<<1); asm volatile ("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop"); i2c_write(0x40); asm volatile ("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop"); } void loop() { for (uint8_t c=0;c<=16;c++) { for (uint8_t s=0;s<=16;s++) { for(uint8_t e=0;e<(c+s);e++) { for(uint8_t i=0;i<(128-c*8)/2;i++) i2c_write(0x00); for(uint8_t i=0;i<c;i++) { i2c_write(0x00);i2c_write(0x3F);i2c_write(0x21); if (i==e) {i2c_write(0x2D);i2c_write(0x2D);} else {i2c_write(0x21);i2c_write(0x21);}; i2c_write(0x21);i2c_write(0x3F);i2c_write(0x00); }; for(uint8_t i=0;i<(128-c*8)/2;i++) i2c_write(0x00); for(uint8_t i=0;i<128;i++) i2c_write(pgm_read_byte(pbcu+i)); for(uint8_t i=0;i<128;i++) i2c_write(pgm_read_byte(pbcu+i+128)); for(uint8_t i=0;i<(128-s*8)/2;i++) i2c_write(0x00); for(uint8_t i=0;i<s;i++) { i2c_write(0x00);i2c_write(0xFC);i2c_write(0x84); if (i==(e-c)) {i2c_write(0xB4);i2c_write(0xB4);} else {i2c_write(0x84);i2c_write(0x84);}; i2c_write(0x84);i2c_write(0xFC);i2c_write(0x00); }; for(uint8_t i=0;i<(128-s*8)/2;i++) i2c_write(0x00); #if defined (SSD128x64) for(uint16_t i=0;i<512;i++) i2c_write(0x00); #endif }; }; }; }Квадратики внизу - количество ошибок
Квадратик с точкой - отображаемая
void OLED::_initTWI() { // activate internal pullups for twi. digitalWrite(SDA, HIGH); digitalWrite(SCL, HIGH); //delay(1); // Workaround for a linker bug // initialize twi prescaler and bit rate __cbi2(TWSR, TWPS0); __cbi2(TWSR, TWPS1); TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; // enable twi module, acks, and twi interrupt TWCR = _BV(TWEN) | _BV(TWIE)/* | _BV(TWEA)*/;Тёмный лес. Нашёл в файлах библиотеки используемой вот этот фрагмент. Строка для изменений 11 ?
Это не Wire, это прямое обращение к железу через порты ! С Wire было бы совсем все плохо - пришлось бы делить посылки на размер буфера Wire.
Да можно пробовать записывать в TWBR 0, 1, 2, ... Или найти где определяется TWI_FREQ и менять частоту.
Или найти где определяется TWI_FREQ и менять частоту.
Попробую в библиотеке OLED_I2C.
Как в принципе можно обойтись без буфера? Предположим есть функция математическая как строить фигуру по точкам. "Одну точку" не передать в экран, а только 8 "одного байта" по конкретному адресу. Если точек 200 - это 200 передач по адресам. Они быстрее чем 1 по всем адресам?
Ну, еще не забуть, прежде чем рисовать новую фигуру, надо старую стереть, т.е + еще 200 передач
Как в принципе можно обойтись без буфера? Предположим есть функция математическая как строить фигуру по точкам. "Одну точку" не передать в экран, а только 8 "одного байта" по конкретному адресу. Если точек 200 - это 200 передач по адресам. Они быстрее чем 1 по всем адресам?
Другая логика работы используется. Для фигур все сложно, но возможно ...
Как в принципе можно обойтись без буфера? Предположим есть функция математическая как строить фигуру по точкам. "Одну точку" не передать в экран, а только 8 "одного байта" по конкретному адресу. Если точек 200 - это 200 передач по адресам. Они быстрее чем 1 по всем адресам?
Другая логика работы используется. Для фигур все сложно, но возможно ...
Для спрайтов кратных 8 должно быть легко.
Как в принципе можно обойтись без буфера? Предположим есть функция математическая как строить фигуру по точкам. "Одну точку" не передать в экран...
Правильно рассуждаешь.
Но медленно. На каждый маленький шажочек нужен очередной толчок.
Раз "одну точку не передать на экран", значит, следует принципиально избавляться от попиксельной графики. Т.е. рассматривать экран не как набор пикселей, а как набор более крупных примитивов. Хотя бы 8-пиксельных. А желательно - больше. Скажем N*M, где N - кратно 8, а M - больше 1.
А желательно - больше. Скажем N*M, где N - кратно 8, а M - больше 1.
Так можно реализовывать вывод текста, имея в постоянной памяти картинки букв размером N*M, но в графике как , например, вывести отрезок заданной длины, под заданным углом? Мне кажется, в общем случае без буфера, хоть и скромного размера, не обойтись. Кстати если бы в используемой мной библиотеке буфер сократили в 2 раза, а вывод разделили на 2 части - про мини 168 справилась бы уже. "Вообщем" тема "безбуферных графических библиотек" для ssd1306 не мой уровень творчества :-(
Пришёл таки второй экранчик. От радости захотелось узоров.
////////////// генератор узоров для ковра #include <OLED_I2C.h> OLED myOLED(SDA, SCL); int t = 1000; // пауза между сменой рисунка ковра int uz = 1000; // плотность узора ковра void setup() { myOLED.begin(); myOLED.invert(0);//инверсия цвета } void loop() { myOLED.clrScr(); // очищаем дисплей int p = map(analogRead(A0), 0, 1023, 0, 100); //размер ковра ///// for (int i = 0; i < uz; i++) { int x = random(0, 128); int y = random(0, 64); if (x * x + y * y < p * p) {//вышиваем, выплетаем узоры myOLED.setPixel(x + 63, y + 32); myOLED.setPixel(x + 63, -y + 32); myOLED.setPixel(-x + 63, -y + 32); myOLED.setPixel(-x + 63, y + 32); } } /// myOLED.update(); delay(t); }Ползунок прогресса. Управлять кнопкой конечно будет ловчее.
/////////////////// индикатор "ползунок прогресса" #include <OLED_I2C.h> OLED myOLED(SDA, SCL); int t = 50; // пауза между считываниями потенциометра extern uint8_t SmallFont[]; void setup() { myOLED.begin(); myOLED.invert(0);//инверсия цвета myOLED.setFont(SmallFont); } void loop() { myOLED.clrScr(); // очищаем дисплей int x = map(analogRead(A0), 0, 1023, 0, 99); //считывание данных с потенциометра и задание положения ползунка myOLED.drawRect(0, 30, 127, 36); //канал ползунка myOLED.drawRect(x + 2, 20, x + 25, 44); // тело ползунка myOLED.clrRect(x + 2, 30, x + 25, 36); myOLED.printNumI(x, x + 6 , 30 ); // числовое значение к положению ползунка myOLED.update(); delay(t); }Так можно реализовывать вывод текста, имея в постоянной памяти картинки букв размером N*M, но в графике как , например, вывести отрезок заданной длины, под заданным углом?
Другими словами, Вы согласны решать исключительно тривиальные задачи?
Мне кажется, в общем случае без буфера, хоть и скромного размера, не обойтись.
В общем случае - да.
Но речь идет не об общем, а о частном конкретном случае: для каждого из вариантов "шкал" придумать такой алгоритм, который позволит обойтись без буфера.
Господа! Я решил вашу задачку! ;))))))
Берем OLED128х64, Цепляем к нему Нанку, общаемся по I2C, на Нанке - драйвер со всеми примитивами графики, анимации, 3Д элементов. И уже это "бутерброд" используем как экран для своей поделки, в которой уже не нужен будет буфер.
Вот тока не надо говорить, что я изобрел Некстион! ;))) Моя идея дешевше будет!
Другими словами, Вы согласны решать исключительно тривиальные задачи?
:-)
Природа не сильно интересовалась моим мнением.
Господа! Я решил вашу задачку! ;))))))
Берем OLED128х64, Цепляем к нему Нанку, общаемся по I2C, на Нанке - драйвер со всеми примитивами графики, анимации, 3Д элементов. И уже это "бутерброд" используем как экран для своей поделки, в которой уже не нужен будет буфер.
Вот тока не надо говорить, что я изобрел Некстион! ;))) Моя идея дешевше будет!
С практической точки зрения это вариант.
Индикация это ~5-10% от задач.
Индикация это ~5-10% от задач.
Я вроде писал уже, что (чисто ИМХО, не настаиваю! ...ну кроме как на перце и зубровке ;)) ) что кнопки и индикацию отмел для себя полностью. Если забыть про 8ми битный "ужОс" в виде АВР, то ESP дает возможность сделать веб-морду, а тилипон всегда в кармане. ;))) Да и памяти там побольше и частота повыше. АВР-ки в автомобиль оставляю - 5В немного более устойчивы к помехам и интерфейс мне там не нужен никакой.
/////////////////// индикатор наполнения ёмкости жидкостью #include <OLED_I2C.h> OLED myOLED(SDA, SCL); extern const unsigned char schkala_A[]; int t = 30; // пауза между считываниями потенциометра int pp = 0; // переменная для хранения предыдущего значения уровня void setup() { myOLED.begin(); myOLED.invert(0);//инверсия цвета } void loop() { myOLED.drawBitmap(0, 0, schkala_A, 128, 64); // рисование картинки ёмкости int p = map(analogRead(A0), 0, 1023, 15, 122); // считывание потенциометра и определение высоты уровня жидкости if (abs(p - pp) > 1) { //если значение уровня поменялось выше порогового в 1 единицу myOLED.drawRect(p, 8, 122, 54); // прорисовка контура столба жидкости for (int i = 0; i < 2000 - p * 15; i++) { // прорисовка столба жидкости int x = random(p, 122); int y = random(8, 54); myOLED.setPixel(x , y ); } myOLED.update(); delay(t); pp = p; //запоминание "нового предыдущего" значения } }#include <avr/pgmspace.h> const unsigned char schkala_A[]PROGMEM = { 0X00,0X00,0X00,0X80,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0XF0,0XF8,0XFC,0XFC,0X1C, 0X0C,0X0C,0X1C,0XFC,0XFC,0XF8,0XF0,0X60,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70, 0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X60,0X60,0XF0,0XF8,0XFC, 0XFC,0X1C,0X0C,0X0C,0X0C,0X1C,0XFC,0XF8,0XF0,0X60,0X70,0X70,0X70,0X70,0X70,0X70, 0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X60,0XF0, 0XF8,0XFC,0XFC,0X1C,0X0C,0X0C,0X0C,0X1C,0XFC,0XFC,0XF8,0XF0,0X60,0X70,0X70,0X70, 0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70,0X70, 0X60,0X60,0XF8,0XF8,0XFC,0X1C,0X0C,0X0C,0X0C,0X1C,0XFC,0XFC,0XF8,0XF0,0X00,0X00, 0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X0E,0X0E,0X0E,0X0E,0X0E,0XFF,0XFF,0XFF,0XFF,0X00, 0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF, 0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF, 0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0XFC,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00, 0X00,0X00,0X3F,0X3F,0X3F,0X3F,0X1C,0X1C,0X1C,0X1C,0X1C,0XFF,0XFF,0XFF,0XFF,0X00, 0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF, 0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF, 0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00, 0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF, 0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF, 0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00, 0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF, 0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF, 0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00, 0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF, 0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF, 0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00, 0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF, 0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0X1F,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF, 0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X00,0X1F,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X00,0X00, 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0X0F,0X1F,0X1F,0X38, 0X38,0X38,0X38,0X1F,0X1F,0X0F,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07, 0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X0F,0X1F, 0X1F,0X3C,0X38,0X38,0X38,0X1C,0X1F,0X1F,0X0F,0X07,0X07,0X07,0X07,0X07,0X07,0X07, 0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07, 0X0F,0X1F,0X1F,0X1C,0X38,0X38,0X38,0X3C,0X1F,0X1F,0X0F,0X07,0X07,0X07,0X07,0X07, 0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07,0X07, 0X07,0X07,0X0F,0X1F,0X1F,0X1C,0X38,0X38,0X38,0X3C,0X1F,0X1F,0X0F,0X07,0X00,0X00 };Индикатор уровня жидкости. С библиотекой, как и с индикаторами-шкалами в принципе ясно, можно добавить ещё функций построения графических примитивов.
Потестил схему двумя экранами, вроде всё работает.
В общем случае - да.
Но речь идет не об общем, а о частном конкретном случае: для каждого из вариантов "шкал" придумать такой алгоритм, который позволит обойтись без буфера.
Я придумал общий алгоритм для графической библиотеки совсем без буфера экрана. Но реализовать его сам едва ли смогу. Да и Ардуино тоже :-) Попробую изложить его простым языком, если получится, может сведущие разберутся.
Бочка в разрезе жаркого лета будет весьма актуальна
Бутылка. В проект наливатора. Тамошние алкаши будут рады
Для "наливатора нужен струемер-каплемер" :-)
Этот вариант сразу на три экрана (в наличии правда только два).
/////////////проверка одновременной работы 3 экранов на 3 разных индикаторах-шкалах #include <OLED_I2C.h> OLED myOLED(SDA, SCL); #define disp_1 12 // управляющие дисплееями выводы #define disp_2 11 #define disp_3 10 extern const unsigned char schkala_A[]; extern const unsigned char schkala_B[]; int t = 25; // пауза между считываниями потенциометра int dlina_1 = 30; int tabl_[10];//массив хранения данных с потенциометра int kap=55;// extern uint8_t MediumNumbers[]; void setup() { ////// подключение всех дисплеев pinMode(disp_1, OUTPUT); digitalWrite(disp_1, HIGH); myOLED.begin(); digitalWrite(disp_1, LOW); delay(50); ////// pinMode(disp_2, OUTPUT); digitalWrite(disp_2, HIGH); myOLED.begin(); digitalWrite(disp_2, LOW); delay(50); //////// pinMode(disp_3, OUTPUT); digitalWrite(disp_3, HIGH); myOLED.begin(); digitalWrite(disp_3, LOW); delay(50); //////// myOLED.invert(0);//инверсия цвета myOLED.setFont( MediumNumbers); } void loop() { pribor_1(); dis_1(); //обработка и обновление данных на 1 индикаторе pribor_2(); dis_2(); //обработка и обновление данных на 2 индикаторе pribor_3(); dis_3(); //обработка и обновление данных на 3 индикаторе delay(t); } //////////////////////////// void dis_1() { //функции обновления изображений на экранах digitalWrite(disp_1, HIGH); myOLED.update(); digitalWrite(disp_1, LOW); } void dis_2() { digitalWrite(disp_2, HIGH); myOLED.update(); digitalWrite(disp_2, LOW); } void dis_3() { digitalWrite(disp_3, HIGH); myOLED.update(); digitalWrite(disp_3, LOW); } ///////////////////////// void pribor_1() { //индикатор "текущий кран" myOLED.clrScr(); // очищаем дисплей myOLED.drawBitmap(0, 0, schkala_A, 64, 64); // рисование картинки int p = map(analogRead(A0), 0, 1023, 0, 200); // считывание потенциометра и задаём скорость капели myOLED.drawBitmap(kap, 45, schkala_B, 16, 16); myOLED.drawBitmap(kap+20, 45, schkala_B, 16, 16); kap=kap+20;if(kap>150){kap=55;} delay(p); } ///////////////////////////////// void pribor_2() { // индикатор построения графика онлайн int h = map(analogRead(A0), 0, 1023, 0, 63); //считывание данных с потенциометра и запись в массив данных на последнюю позицию for (int i = 0; i < 10; i++) { if (i != 9) { tabl_[i] = tabl_[i + 1]; } else { tabl_[i] = h; } } myOLED.clrScr(); // очищаем дисплей for (int i = 0; i < 10; i++) {//прорисовка кадра myOLED.drawLine(i * 13 + 5, 63, i * 13 + 5, tabl_[i]); //каскад отрезков вертикальных высотой h if (i < 9) { myOLED.drawLine((i + 1) * 13 + 5, tabl_[i + 1] , i * 13 + 5, tabl_[i]); // цепочка отрезков между соседними вершинами - линия графика } } } /////////////////////////////////////// void pribor_3() { //стрелочный индикатор уровня сигнала myOLED.clrScr(); // очищаем дисплей int x = map(analogRead(A0), 0, 1023, 5, 124); //считывание данных с потенциометра и задание координаты стрелки myOLED.drawRect(0, 0, 127, 63); //рамка myOLED.drawLine(x, 5, x, 58); // стрелка и её положение myOLED.drawRect(5, 22, 90, 42); //шкала прогресса myOLED.drawRect(95, 22, 124, 42); ///// for (int j = 0; j < 20; j = j + 3) { // раскраска прямоугольника точками for (int i = 0; i < 30; i = i + 2) { myOLED.setPixel(95 + i, 22 + j); } } /// }Это индикация дозы (в каплях). А еще же нужен контроль остатков. И еще можно добавить расчетное количество промилле в крови (степень готовости), с учетом типа напитка и массы тушки поциЭнта
(степень готовости), с учетом типа напитка и массы тушки поциЭнта
Типа как с бочкой, но с фигуркой человека?
(степень готовости), с учетом типа напитка и массы тушки поциЭнта
Можно и так. А можно угол наклона
тема из полезной медленно дрейфует в фарс. Перенесли в "Проекты", скоро придется в "Отвлеченные" переносить :)
Подправил - к изменению скорости капели добавляется изменение высоты стакана :-)
тема из полезной медленно дрейфует в фарс. Перенесли в "Проекты", скоро придется в "Отвлеченные" переносить :)
Я сейчас добавлю грусти про универсальную безбуферную графическую библиотеку.
Итак любую картинку можно представить как множество отрезков, а поле экрана как декартову систему координат. Отрезки описываются уравнением вида:
где x,y координаты подходящих отрезку точек.
Заполнение экрана светящимися (не светящимися) пикселями происходит сначала по столбцам, потом по страницам. Проблема в том, что столбец из 8 точек надо заполнить один раз, зная какие точки в нём принадлежат хотя бы одному из отрезков и потом отправить в экран. То есть каждый текущий бит-точку с координатами x,y надо проверять на принадлежность всем отрезкам картинки. Например, картинка состоит из 100 отрезков, значит Ардуино должна пересчитать 100 условий. А всего около 800000 на картинку прежде чем весь экран отрисуется. Вот и получается, что вместо буфера МК нужен быстро считающий МК.
Поэтому люди буфер и придумали ;)
тема из полезной медленно дрейфует в фарс. Перенесли в "Проекты", скоро придется в "Отвлеченные" переносить :)
ИМХО. тема раскрыта почти полностью - происходит обсуждение по применению... и ТС не виноват, что народ на больную тему понесло. Если чего и переносить, то отдельные посты :)))))
...значит Ардуино должна пересчитать 100 условий. А всего около 800000 на картинку прежде чем весь экран отрисуется. Вот и получается, что вместо буфера МК нужен быстро считающий МК.
как-то даже и не удивительно... может видеокарту для ардуино пора придумать? :))))
lilik, библиотека OLED вот эта используется?
https://github.com/jlegas/OLED_I2C
http://www.rinkydinkelectronics.com/library.php?id=79
Вот отсюда качал по моему.
Итак любую картинку можно представить как множество отрезков...
НизачОт!
Повторяю, наверное, уже в третий или четвертый раз: не нужно пытаться искать универсальное решение (рисование отрезка - это именно элемент универсального решения), нужно рисовать конкретную картинку. Без буфера. И без универсальных примитивов.
нужно рисовать конкретную картинку. Без буфера. И без универсальных примитивов.
Картинка это множество хаотично расположенных точек, координаты которых где то должны храниться?
Какой промежуточный вариант между крайностями?
А прогресс ли это? Все шрифты набиты картинками в библиотеках под экранчики. Буквы-цифры не повернуть и не масштабировать. И тем не менее по другому не делают.
та конечно! ))))
Уже столько лет как решено. А начало http://arduino.ru/forum/programmirovanie/krivye-beze?page=1 там и про безбуферную работу с экраном есть маленько.
В коде я конечно не понял ничего, но подход ясен - буфер размером с символ, символ это отрезки-кривые, масштабирование, повороты. Вот мне и интересно, почему авторы библиотеки OLED_I2C не делали векторные шрифты в довесок к "картиночным"?
Примитивов могли добавить - эллипсов, звёзд,многоугольников, дуг, спиралей и т.д.
Там почитай. С начала автор темы хотел много разных примитивов. По ходу отказались. Отрезков для шрифтов с головой хватает. На таких разрешениях, как экран этот, дуги легко аппроксимируются.
//Вот мне и интересно, почему авторы библиотеки OLED_I2C не делали векторные шрифты в довесок к "картиночным"?
В векторном шрифте вся загвоздка в формате хранения. Нужно хранить очень сжато и распаковывать быстро. А растровый напрягов не требует.
Вот мне и интересно, почему авторы библиотеки OLED_I2C не делали векторные шрифты в довесок к "картиночным"?
сложность кода на порядок выше
Мне кажется, что "математическое" хранение символа предпочтительнее "картиночного". А вот такой вариант не
облегчает кодирование?
Вот мне и интересно, почему авторы библиотеки OLED_I2C не делали векторные шрифты в довесок к "картиночным"?
Они задали себе вопрос "наюха?" и совершенно правильно на него ответили - "нахнесдалось!".
А вот такой вариант не
облегчает кодирование?
попробуйте вписать в него "Д" или "Й", я уж не говорю про буквы арабского алфавита.
Или даже проще - изобразите своим вариантом фонты bold и italic, так чтобы они четко отличались от plain
не думаю что символ '@' сюда влезет ))) Использую для символа 9*17