Отвлёкся я на скорость вывода картинки от вариаций раскрашивания. Пока в голову пришло три варианта - сектора цвета, градиент цвета и пиксель-ассорти. Какие ещё варианты могут быть?
Для начала - любые варианты, в которых цвет не жестко зависит от координат пикселя, а определяется самим изображением. Например, зависит от расстояния до границы. Либо каждый изолированный фрагмент заливается своим цветом. Еще цвет может зависеть от времени.
PS. Но, прежде, чем рассуждать, хотелось бы понять, зачем это все может понадобиться?
... Либо каждый изолированный фрагмент заливается своим цветом.
...Еще цвет может зависеть от времени.
... хотелось бы понять, зачем это все может понадобиться?
...Это самый интересный и трудно реализуемый вариант раскраски.
...Был бы интересен при анимации, но перерисовка экрана медленная даже при tft.setAddrWindow(0,0,128,160); и ... if(...) { tft.pushColor(tft.Color565(255,255,255) );}else { tft.pushColor(tft.Color565(0,0,0) );}
...Для полноценного использования экрана с про мини и уно.
... Либо каждый изолированный фрагмент заливается своим цветом.
...Еще цвет может зависеть от времени.
... хотелось бы понять, зачем это все может понадобиться?
...Это самый интересный и трудно реализуемый вариант раскраски.
Реализуется просто до безобразия, только для этого нужно иметь возможность читать цвет, что при последовательном интерфейсе, как правило, не поддерживается.
Цитата:
...Был бы интересен при анимации, но перерисовка экрана медленная даже при tft.setAddrWindow(0,0,128,160); и ... if(...) { tft.pushColor(tft.Color565(255,255,255) );}else { tft.pushColor(tft.Color565(0,0,0) );}
При таком подходе перерисовка в принципе не может быть быстрой.
Цитата:
...Для полноценного использования экрана с про мини и уно.
Полноценное использование экрана - это как?
Экран должен выполнять свои функции в пределах поставленной задачи. Все. Какое еще может быть полноценное использование?
PS. Ну и позволю себе еще раз вернуться к вопросу скорости отрисовки.
1. То, что подход, проиллюстрированный в ответе на п.2 не может быть быстрым по определению, я уже сказал.
2. То, что на мой взгляд, следовало бы сначала научиться быстро работать с экраном и только потом начинать извращаться, я тоже писал ранее.
3. Для ускорения вывода имеет смысл перейти с последовательного интерфейса на параллельный.
Реализуется просто до безобразия, только для этого нужно иметь возможность читать цвет, что при последовательном интерфейсе, как правило, не поддерживается.
[quote]
Мне кажется достаточно уметь находить в массиве данных картинки границы локаций 0 или 1. Как чтение цвета пикселя экрана это реализует? Впрочем тема где то тут на форуме была про чтение из экрана 18 бит данных на пиксель и дальнейшее использование, но до библиотеки дело не дошло :)
В рамках имеющегося модуля-экрана параллельный интерфейс не пройдёт.
Поставленная задача..., например, мимика-моська робота в цвете на про мини 168.
Мне кажется достаточно уметь находить в массиве данных картинки границы локаций 0 или 1. Как чтение цвета пикселя экрана это реализует?
В исходном массиве у нас двух цветное изображение. Ну нашли мы границу, откуда нам знать, в какой цвет красить по одну сторону, и в какой - по другую?
Т.е. когда мы на экране добавляем третий цвет, то эта информация уже может использоваться для дальнейшей раскраски. А в исходном двухцветном изображении этой информации еще нет.
Цитата:
Поставленная задача..., например, мимика-моська робота в цвете на про мини 168.
Нет такой задачи.
Задача может быть: построить прибор с определенными техническими характеристиками. А "робота в цвете" - это не задача. И "на про мини" - это тоже не задача.
В исходном массиве у нас двух цветное изображение. Ну нашли мы границу, откуда нам знать, в какой цвет красить по одну сторону, и в какой - по другую?
Нет такой задачи.
Задача может быть: построить прибор с определенными техническими характеристиками. А "робота в цвете" - это не задача. И "на про мини" - это тоже не задача.
Одну локацию в один цвет, соседнюю в другой.
Т.е. создать поделку с заданными св-вами на заданных модулях это не задача? Вот незадача :)
Тогда SPI.transfer(&lineBuf, dispW); останется и должна заработать?, а в tft.setAddrWindow(0, j, dispW-1, j); убрать хвост tft.
никаких хвостов убирать не надо
по хорошему добавить в библиотеку Адафрута новую функцию которая выводит не пиксель, я именно строку.
Завтра может время найду поставлю эти библиотеки. посмотрю.
Не дождался, извратил-исправил код (не знаю сдвиги-преобразования битов в байтах) до рабочего, и действительно так быстрее чем у меня (нос Эйнштейна просматривается чётко в попе у Шерон Стоун). Но как теперь делить два байта цвета на части?
//РИСУНОК
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
extern const unsigned char ris_1[];
extern const unsigned char ris_2[];
#define dispW 128
#define dispH 160
unsigned char lineBuf[dispW*2 ];
void setup() {
// put your setup code here, to run once:
// Используйте этот инициализатор, если вы используете 1,8-дюймовый TFT
tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab
tft.fillScreen(ST7735_BLACK);
tft.setRotation(0);//ориентация экрана
}
void loop() {
// put your main code here, to run repeatedly:
drawBitmap_(ris_1,128);
drawBitmap_(ris_2,128);
}
void drawBitmap_(const uint8_t *bitmap,int16_t w) {
int16_t i, j, byteWidth = (w + 7) / 8;
uint8_t byte;
for (unsigned short j = 0; j < dispH; j++) {
for (unsigned short i = 0; i < dispW; ++i) {
if(i & 7) byte <<= 1;
else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
if(byte & 0x80)
{
lineBuf[i*2 ] =0xFF ; lineBuf[i * 2 + 1] = 0xFF; // white color
} else {
lineBuf[i*2 ] =0x00 ; lineBuf[i * 2 + 1] = 0x00; // black color
}
}
tft.setAddrWindow(0, j, dispW-1, j);
///
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_CS, LOW);
SPI.transfer(&lineBuf, 2*dispW);
digitalWrite(TFT_CS, HIGH);
SPI.endTransaction();
///
}
}
//////////////////////////////////////////////////////////////////////////////////////
Нет, я не сообразил сходу как делить на 2 части tft.Color565(255,255,0) . Теперь сообразил. Вот пример радужного секундомера (для опытов на "пипика" :)
// СЕКУНДОМЕР РАДУЖНЫЙ
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
extern const unsigned char ris_1[];
float a = -PI/2-PI/30; // переменная для угла поворота стрелки
int str = 60; //длина стрелки в пикселях
byte sek=0;//
void setup(void) {
// Используйте этот инициализатор, если вы используете 1,8-дюймовый TFT
tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab
tft.fillScreen(ST7735_BLACK);
tft.setRotation(0);//ориентация экрана
}
void loop() {
//
drawBitmap_(0,16,ris_1, 128,128);//фоновая картинка секундомера
//
a=a+PI/30;
tft.drawLine(64+ cos(a+1.5)*str*0.1, 80+ sin(a+1.5)*str*0.1, 64 + cos(a)*str, 80 + sin(a)*str,tft.Color565(0,0,0));// рисование новой стрелки
tft.drawLine(64+ cos(a-1.5)*str*0.1, 80+ sin(a-1.5)*str*0.1, 64 + cos(a)*str, 80 + sin(a)*str,tft.Color565(0,0,0));//
tft.drawCircle(64,80,6,tft.Color565(0,0,0) );
tft.setCursor(55, 95);//дублирование данных числом
tft.setTextSize(2);
tft.setTextColor(tft.Color565(0,0,0));
if(sek<10){tft.print("0");}tft.println(sek);
sek++;if(sek>59){sek=0;}
//
delay(835);//подбираем опытным путём
}
////////////////////////////////////////////////////////
void drawBitmap_(int x,int y, const uint8_t *bitmap,int16_t W ,int16_t H) {
if(x<0||x+W>128||y<0||y+H>160){return;}
unsigned char lineBuf[W*2 ];
int16_t i, j, byteWidth = (W + 7) / 8;
uint8_t byte;
for (unsigned short j = 0; j < H; j++) {
for (unsigned short i = 0; i < W; ++i) {
if(i & 7) byte <<= 1;
else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
if(byte & 0x80)
{
if(j<=H/2&&i<=W/2){lineBuf[i*2 ] =tft.Color565(255,0,0)/256 ; lineBuf[i * 2 + 1] =tft.Color565(255,0,0)%256 ;} // задаём условия цветных секторов для основного изображения
else{ if(j<=H/2&&i>W/2){lineBuf[i*2 ] =tft.Color565(255,0,255)/256 ; lineBuf[i * 2 + 1] =tft.Color565(255,0,255)%256 ; }
else{ if(j>H/2&&i>W/2){lineBuf[i*2 ] =tft.Color565(0,150,255)/256 ; lineBuf[i * 2 + 1] =tft.Color565(0,150,255)%256 ;}
else{ if(j>H/2&&i<=W/2){lineBuf[i*2 ] =tft.Color565(255,255,0)/256 ; lineBuf[i * 2 + 1] =tft.Color565(255,255,0)%256 ;}
}
}
}
} else {
lineBuf[i*2 ] =tft.Color565((1.6)*(j%H),200-(200/W)*(i%W),(255/W)*(i%W))/256 ; lineBuf[i * 2 + 1] =tft.Color565((1.6)*(j%H),200-(200/W)*(i%W),(255/W)*(i%W))%256 ; //задаём условия цветового градиента для фонового изображения
}
}
tft.setAddrWindow(x+0, y+j, x+W-1, y+j);
///
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_CS, LOW);
SPI.transfer(&lineBuf, 2*W);
digitalWrite(TFT_CS, HIGH);
SPI.endTransaction();
///
}
}
//////////////////////////////////////////////////////////
sketch_enshtein:99:36: error: 'class Adafruit_ST7735' has no member named 'Color565'; did you mean 'color565'?
99 | drawBitmap_(0,0,ris_1,128,160,tft.Color565(255,255,255),tft.Color565(0,0,0));
| ^~~~~~~~
| color565
sketch_enshtein:99:62: error: 'class Adafruit_ST7735' has no member named 'Color565'; did you mean 'color565'?
99 | drawBitmap_(0,0,ris_1,128,160,tft.Color565(255,255,255),tft.Color565(0,0,0));
| ^~~~~~~~
| color565
sketch_enshtein:100:36: error: 'class Adafruit_ST7735' has no member named 'Color565'; did you mean 'color565'?
100 | drawBitmap_(0,0,ris_2,128,160,tft.Color565(255,255,255),tft.Color565(150,150,50));
| ^~~~~~~~
| color565
sketch_enshtein:100:62: error: 'class Adafruit_ST7735' has no member named 'Color565'; did you mean 'color565'?
100 | drawBitmap_(0,0,ris_2,128,160,tft.Color565(255,255,255),tft.Color565(150,150,50));
| ^~~~~~~~
| color565
'class Adafruit_ST7735' has no member named 'Color565'; did you mean 'color565'?
lilik, ну нет вариантов натянуть сову на глобус)
У atmega328p есть свой предел и у дисплея тоже, если выкините adafrut библиотеки и начнёте напрямую с дисплеем общаться, будет побыстрее, но глобально для мультиков менять МК!
lilik, ну нет вариантов натянуть сову на глобус) У atmega328p есть свой предел и у дисплея тоже, если выкините adafrut библиотеки и начнёте напрямую с дисплеем общаться, будет побыстрее, но глобально для мультиков менять МК!
Ну всё равно, принципиально эти варианты на порядок лучше чем по точечный вывод картинки. Как напрямую работать статей толковых в интернете не видел.
Дык статей и не будет, даташит и вперёд, руками отправляем в spi нужные команды и будет счастье.
Я с ili9341 тупо нашёл самую простую библиотеку, её разобрал по косточкам и просто что то добавил.
Adafrut библиотеки мне кажется слишком перегружена универсальностью (
По переводу понял что с маленькой буквы надо писать Color, но у меня в библиотеке с большой в функции:
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t Adafruit_ST7735::Color565(uint8_t r, uint8_t g, uint8_t b)
{
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
Может посмотрите у себя в файле "адафрукт ST_7735".cpp с большой или с маленькой.
у меня такой функции вообще нет, библиотеку поставил сейчас с сайта arduino.cc 1.9 версии, но и в прежней не было
а цвета перевожу своей функцией, правда ее адриано поправил, у меня было в лоб...
// функция перекодировки цвета в формат библиотеки Adafruin_GFX
//
uint16_t setColor(uint8_t red, uint8_t green, uint8_t blue) {
//uint16_t color = ((red & 0xf8)<<11) + ((green & 0xfc) <<5) + (blue & 0xf8); //uint16_t(r5-g6-b5 bit)
uint16_t color = ((red & 0x0b11111000) << 11) + ((green & 0b11111100) << 5 ) + (blue & 0b11111000);
return color;
}
я на RP2040 пробую, пока не взлетело, почему-то картинка не выводится, loop отрабатывает
Самое смешное - не могу вспомнить где я брал вариант библиотеки. На гитхабе смотрел- нет функции этой нигде.
много ссылок, что скетчи ругаются на эту функцию, так надо проверить, в функции 100500 байт цвета blue правильно переводится..сейчас буду проверять, что-то мне адриано не то подсказал, чую
Я жеж под rp2040 пока не одолел, висит в твоей функции, всё выводит да выводит, но на экране ничего...
я тут чуток порассуждал и пришёл к выводу, что правильней функцию сделать так:
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t Adafruit_ST7735::Color565(uint8_t r, uint8_t g, uint8_t b)
{
r = r >>3;
g = g >>2;
b = b >>3;
return ((r << 11) + (g << 5) + b;
}
проверил, если в расчётах перевести на флоат (что не правильно) всё равно разброс по переводным данным, правильно - отбросить незначащие биты, а это только сдвиг...
Я в два захода приводил, так как пока не отложилось, что делается вначале, что слева, что справа (для однозначности)...ты показал, осталось запомнить )))
И в связи с отмеченным выше, совершенно непонятно, откуда у Вас появился "разброс по переводимым данным".
ну я то изначально делю 31 или 63 на 255, в этом случае вся дробная часть (хоть это 0.999) отбрасывается, от того и разброс...
я вот только не знаю, в C++ сдвиг с переносом старших (или младших) битов идет или без оных, если с переносом, то сначала надо незначащие биты обнулить, тогда сперва логическое & а потом сдвиг
что-то никак не одолею с этой RP2040, на экран при инициализации вывожу заставку, она и висит, скетч далее такой:
ЗЫ сейчас раз в секунду в монитор порта летит - работаю )))
void loop() {
tft.setRotation(0);
drawBitmap_(0, 0, ris_1, 128, 160, ST77XX_WHITE /*setColor(255, 255, 255)*/, ST77XX_BLACK /*setColor(0, 0, 0)*/);
drawBitmap_(0, 0, ris_2, 128, 160, ST77XX_WHITE /*setColor(255, 255, 255)*/, ST77XX_RED/*setColor(150, 150, 50)*/);
Serial.println("работаю");
}
/////////////////////////////////////////////////////////////////////
void drawBitmap_(int x, int y, const uint8_t *bitmap, int w, int h, const uint16_t color_1, const uint16_t color_2) {
if (x < 0 || x + w > 128 || y < 0 || y + h > 160) {
return;
}
tft.setAddrWindow(x, y, x + w - 1, y + h - 1);
int16_t i, j, byteWidth = (w + 7) / 8;
uint8_t byte;
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
if (i & 7) {byte <<= 1; /*Serial.println("in if");*/
}else{ byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);/*Serial.print(byte);Serial.println(" - in else");*/}
if (byte & 0x80)
{
tft.pushColor(color_1 ); /*Serial.println("цвет 1");*/
}
else {
tft.pushColor(color_2 ); /*Serial.println("цвет 2");*/
}
}
}
}
/////////////////////////////////////////////////////////////////////
ну я то изначально делю 31 или 63 на 255, в этом случае вся дробная часть (хоть это 0.999) отбрасывается, от того и разброс...
Деление - очень медленная операция. Применять ее трижды для каждого пикселя - очень неэффективное решение.
Цитата:
я вот только не знаю, в C++ сдвиг с переносом старших (или младших) битов идет или без оных, если с переносом, то сначала надо незначащие биты обнулить, тогда сперва логическое & а потом сдвиг
В Си сдвиг не циклический, если Вы это имеете в виду.
Циклический сдвиг реализуется примерно так (для 16-разрядного целого):
И ещё: про функцию Color565. У меня в иде встроена библиотека TFT. А она лишь ширма для адафрутовской GFX и ST7735. А вот уже в ней и есть эта функция. Я не знал, у меня получается дубликаты стоят.
Отвлёкся я на скорость вывода картинки от вариаций раскрашивания. Пока в голову пришло три варианта - сектора цвета, градиент цвета и пиксель-ассорти. Какие ещё варианты могут быть?
... в которых цвет не жестко зависит от координат пикселя, а определяется самим изображением...
Прорыв в нанотехнологиях :)
Догадался как выделять контур изображения. Функцию по наитию переделал.
//РИСУНОК преобразование в контур 3 цвета в картинке
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
extern const unsigned char ris_1[];
void setup() {
// put your setup code here, to run once:
// Используйте этот инициализатор, если вы используете 1,8-дюймовый TFT
tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab
tft.fillScreen(ST7735_BLACK);
tft.setRotation(0);//ориентация экрана
}
void loop() {
drawBitmap_(0,0,ris_1,128,160,tft.Color565(255,255,255),tft.Color565(0,0,0),tft.Color565(75,75,0));
delay(1000);
}
/////////////////////////////////////////////////////////////////////////////////////////
void drawBitmap_(int x,int y, const uint8_t *bitmap,int16_t W ,int16_t H,const uint16_t color_1,const uint16_t color_2,const uint16_t color_3) {
bool flag=true;//
if(x<0||x+W>128||y<0||y+H>160){return;}
unsigned char lineBuf[W*2 ];
int16_t i, j, byteWidth = (W + 7) / 8;
uint8_t byte_;uint8_t byte_st;
for (unsigned short j = 0; j < H; j++) {
for (unsigned short i = 0; i < W; i++) {
if(i & 7) {byte_ <<= 1;byte_st <<= 1;}
else { byte_ = pgm_read_byte(bitmap + j * byteWidth + i / 8);if(j>0){byte_st = pgm_read_byte(bitmap + (j-1) * byteWidth + i / 8);}}
if(byte_ & 0x80)
{
if(flag||!(byte_st & 0x80)){lineBuf[i*2 ] =color_1/256 ; lineBuf[i * 2 + 1] =color_1%256 ;} // цвет контура
else{lineBuf[i*2 ] =color_3/256 ; lineBuf[i * 2 + 1] =color_3%256 ;} // цвет раскраски внутри контура
flag=false;
} else {
if(!flag||byte_st & 0x80){ lineBuf[i*2 ] =color_1/256 ; lineBuf[i * 2 + 1] =color_1%256 ;} //цвет контура
else{lineBuf[i*2 ] =color_2/256 ; lineBuf[i * 2 + 1] =color_2%256 ;} // цвет фона
flag=true;
}
}
tft.setAddrWindow(x+0, y+j, x+W-1, y+j);
///
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
digitalWrite(TFT_DC, HIGH);
digitalWrite(TFT_CS, LOW);
SPI.transfer(&lineBuf, 2*W);
digitalWrite(TFT_CS, HIGH);
SPI.endTransaction();
///
}
}
//////////////////////////////////////////////////////////////////////////////////////
В принципе, при таком алгоритме выделения контура рисунка, можно контур сделать двухцветным - для большей выразительности по сравнению с исходным ч/б изображением.
Нам учитель задаёт с иксами задачу...это я к тому, что только решил одну задачку, ты подкинул вторую...
Под Rasberry PI Pico RP2040 предыдущее заработало!!!
// РИСУНОК
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <SPI.h>
#if ( defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || \
defined(ARDUINO_GENERIC_RP2040) )
// замаркировать если используем наоборот
#define SPI01 // Дисплей на SPIO1, NRF24L01 на SPI0 (выбор между SPI0 и SPI1)
#if defined(SPI01) // для RP2040 SPI1
#define TFT_CS 13 // GP13 - CS
#define TFT_RST 14 // GP14 - RESET
#define TFT_DC 15 // GP15 - A0
#define TFT_MISO 12 // GP12 - MISO (MISO, RX)
#define TFT_MOSI 11 // GP11 - SDA (MOSI, TX)
#define TFT_SCLK 10 // GP10 - SCK
#else // для RP2040 SPI0
#define TFT_CS 5 // GP5 - CS
#define TFT_RST 6 // GP6 - RESET
#define TFT_DC 7 // GP7 - A0
#define TFT_MISO 4 // GP4 - MISO (MISO, RX)
#define TFT_MOSI 3 // GP3 - SDA (MOSI, TX)
#define TFT_SCLK 2 // GP2 - SCK
#endif
// SPI definitions and macros то NRF24L01
#if defined(SPI01)
#define CE_pin 7
#define CS_pin 5
#define MOSI_pin 3
#define MISO_pin 4
#define SCK_pin 2
#else
#define CE_pin 15
#define CS_pin 13
#define MOSI_pin 11
#define MISO_pin 12
#define SCK_pin 10
#endif
#elif ( defined(ESP32))
#define WIFI // Используем модуль вайфая
#include "WiFi.h"
// *** *** *** Для ESP32 подключаем SPI так:
#define HSPI // Дисплей на HSPI, NRF24L01 на VSPI
#if defined(HSPI) // для ESP32 HSPI
#define TFT_CS 15 // GP13 - CS
#define TFT_RST 16 // GP14 - RESET
#define TFT_DC 17 // GP15 - A0
#define TFT_MISO 12 // GP12 - MISO (MISO, RX)
#define TFT_MOSI 13 // GP11 - SDA (MOSI, TX)
#define TFT_SCLK 14 // GP10 - SCK
#else // для ESP32 VSPI
#define TFT_CS 5 // GP5 - CS
#define TFT_RST 20 // GP20 - RESET
#define TFT_DC 21 // GP21 - A0
#define TFT_MISO 19 // GP19 - MISO (MISO, RX)
#define TFT_MOSI 23 // GP23 - SDA (MOSI, TX)
#define TFT_SCLK 18 // GP18 - SCK
#endif
// SPI definitions and macros то NRF24L01
#if defined(HSPI) // NRF24L01 на VSPI если монитор на HSPI и наоборот ;-)
#define CE_pin 21
#define CS_pin 5
#define MOSI_pin 23
#define MISO_pin 19
#define SCK_pin 18
#else // HSPI
#define CE_pin 17
#define CS_pin 15
#define MOSI_pin 13
#define MISO_pin 12
#define SCK_pin 14
#endif
#else
#error This code is intended to run on the RP2040 or ESP32 modules!
#endif
// For ST7735-based displays, we will use this call
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
extern const unsigned char ris_1[];
extern const unsigned char ris_2[];
// функция перекодировки цвета в формат библиотеки Adafruin_GFX
//
uint16_t setColor(uint8_t red, uint8_t green, uint8_t blue) {
return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3);
}
void dispInit() {
// Use this initializer if using a 1.8" TFT screen:
tft.initR(INITR_BLACKTAB); // Init ST7735S chip, black tab
tft.setRotation(1);
tft.cp437(true); // не пропускаем 176 символ
#ifdef WIFI // SPI для ESP32
tft.setSPISpeed(50000000); // отдельные экземпляры дисплеев не работают на такой скорости
#else // откоректируйте по конкретный экземпляр
tft.setSPISpeed(50000000);
#endif
tft.fillScreen(ST77XX_BLACK);
tft.setCursor(22, 50);
tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
tft.setTextSize(1);
tft.print(" R I S U N O K");
tft.setCursor(3, 70);
tft.setTextSize(1);
tft.setTextColor(ST77XX_CYAN, ST77XX_BLACK);
#ifdef WIFI
tft.print("Modified to ESP32 - UA6EM");
#else
tft.print("Modified to RP2040 - UA6EM");
#endif
delay(3000);
}
void setup(void) {
dispInit();
Serial.begin(115200);
tft.setRotation(0);
tft.fillScreen(ST7735_BLACK); // добавил эту строку - З А Р А Б О Т А Л О !!!
}
void loop() {
drawBitmap_(0, 0, ris_1, 128, 160, ST77XX_WHITE /*setColor(255, 255, 255)*/, ST77XX_BLACK /*setColor(0, 0, 0)*/);
drawBitmap_(0, 0, ris_2, 128, 160, ST77XX_WHITE /*setColor(255, 255, 255)*/, ST77XX_RED/*setColor(150, 150, 50)*/);
//Serial.println("работаю");
}
/////////////////////////////////////////////////////////////////////
void drawBitmap_(int x, int y, const uint8_t *bitmap, int w, int h, const uint16_t color_1, const uint16_t color_2) {
if (x < 0 || x + w > 128 || y < 0 || y + h > 160) {
return;
}
tft.setAddrWindow(x, y, x + w - 1, y + h - 1); // координаты окна 0,0 - 127-159
int16_t i, j, byteWidth = (w + 7) / 8;
uint8_t bytes;
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
if (i & 7) {
bytes <<= 1; /*Serial.println("in if");*/
} else {
bytes = pgm_read_byte(bitmap + j * byteWidth + i / 8);/*Serial.print(byte);Serial.println(" - in else");*/
}
if (bytes & 0x80)
{
tft.pushColor(color_1 ); /*Serial.println("цвет 1");*/
}
else {
tft.pushColor(color_2 ); /*Serial.println("цвет 2");*/
}
}
}
}
/////////////////////////////////////////////////////////////////////
Нам учитель задаёт с иксами задачу...это я к тому, что только решил одну задачку, ты подкинул вторую...
Под Rasberry PI Pico RP2040 предыдущее заработало!!!
// РИСУНОК
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <SPI.h>
#if ( defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || \
defined(ARDUINO_GENERIC_RP2040) )
// замаркировать если используем наоборот
#define SPI01 // Дисплей на SPIO1, NRF24L01 на SPI0 (выбор между SPI0 и SPI1)
#if defined(SPI01) // для RP2040 SPI1
#define TFT_CS 13 // GP13 - CS
#define TFT_RST 14 // GP14 - RESET
#define TFT_DC 15 // GP15 - A0
#define TFT_MISO 12 // GP12 - MISO (MISO, RX)
#define TFT_MOSI 11 // GP11 - SDA (MOSI, TX)
#define TFT_SCLK 10 // GP10 - SCK
#else // для RP2040 SPI0
#define TFT_CS 5 // GP5 - CS
#define TFT_RST 6 // GP6 - RESET
#define TFT_DC 7 // GP7 - A0
#define TFT_MISO 4 // GP4 - MISO (MISO, RX)
#define TFT_MOSI 3 // GP3 - SDA (MOSI, TX)
#define TFT_SCLK 2 // GP2 - SCK
#endif
// SPI definitions and macros то NRF24L01
#if defined(SPI01)
#define CE_pin 7
#define CS_pin 5
#define MOSI_pin 3
#define MISO_pin 4
#define SCK_pin 2
#else
#define CE_pin 15
#define CS_pin 13
#define MOSI_pin 11
#define MISO_pin 12
#define SCK_pin 10
#endif
#elif ( defined(ESP32))
#define WIFI // Используем модуль вайфая
#include "WiFi.h"
// *** *** *** Для ESP32 подключаем SPI так:
#define HSPI // Дисплей на HSPI, NRF24L01 на VSPI
#if defined(HSPI) // для ESP32 HSPI
#define TFT_CS 15 // GP13 - CS
#define TFT_RST 16 // GP14 - RESET
#define TFT_DC 17 // GP15 - A0
#define TFT_MISO 12 // GP12 - MISO (MISO, RX)
#define TFT_MOSI 13 // GP11 - SDA (MOSI, TX)
#define TFT_SCLK 14 // GP10 - SCK
#else // для ESP32 VSPI
#define TFT_CS 5 // GP5 - CS
#define TFT_RST 20 // GP20 - RESET
#define TFT_DC 21 // GP21 - A0
#define TFT_MISO 19 // GP19 - MISO (MISO, RX)
#define TFT_MOSI 23 // GP23 - SDA (MOSI, TX)
#define TFT_SCLK 18 // GP18 - SCK
#endif
// SPI definitions and macros то NRF24L01
#if defined(HSPI) // NRF24L01 на VSPI если монитор на HSPI и наоборот ;-)
#define CE_pin 21
#define CS_pin 5
#define MOSI_pin 23
#define MISO_pin 19
#define SCK_pin 18
#else // HSPI
#define CE_pin 17
#define CS_pin 15
#define MOSI_pin 13
#define MISO_pin 12
#define SCK_pin 14
#endif
#else
#error This code is intended to run on the RP2040 or ESP32 modules!
#endif
// For ST7735-based displays, we will use this call
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
extern const unsigned char ris_1[];
extern const unsigned char ris_2[];
// функция перекодировки цвета в формат библиотеки Adafruin_GFX
//
uint16_t setColor(uint8_t red, uint8_t green, uint8_t blue) {
return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3);
}
void dispInit() {
// Use this initializer if using a 1.8" TFT screen:
tft.initR(INITR_BLACKTAB); // Init ST7735S chip, black tab
tft.setRotation(1);
tft.cp437(true); // не пропускаем 176 символ
#ifdef WIFI // SPI для ESP32
tft.setSPISpeed(50000000); // отдельные экземпляры дисплеев не работают на такой скорости
#else // откоректируйте по конкретный экземпляр
tft.setSPISpeed(50000000);
#endif
tft.fillScreen(ST77XX_BLACK);
tft.setCursor(22, 50);
tft.setTextColor(ST77XX_YELLOW, ST77XX_BLACK);
tft.setTextSize(1);
tft.print(" R I S U N O K");
tft.setCursor(3, 70);
tft.setTextSize(1);
tft.setTextColor(ST77XX_CYAN, ST77XX_BLACK);
#ifdef WIFI
tft.print("Modified to ESP32 - UA6EM");
#else
tft.print("Modified to RP2040 - UA6EM");
#endif
delay(3000);
}
void setup(void) {
dispInit();
Serial.begin(115200);
tft.setRotation(0);
tft.fillScreen(ST7735_BLACK); // добавил эту строку - З А Р А Б О Т А Л О !!!
}
void loop() {
drawBitmap_(0, 0, ris_1, 128, 160, ST77XX_WHITE /*setColor(255, 255, 255)*/, ST77XX_BLACK /*setColor(0, 0, 0)*/);
drawBitmap_(0, 0, ris_2, 128, 160, ST77XX_WHITE /*setColor(255, 255, 255)*/, ST77XX_RED/*setColor(150, 150, 50)*/);
//Serial.println("работаю");
}
/////////////////////////////////////////////////////////////////////
void drawBitmap_(int x, int y, const uint8_t *bitmap, int w, int h, const uint16_t color_1, const uint16_t color_2) {
if (x < 0 || x + w > 128 || y < 0 || y + h > 160) {
return;
}
tft.setAddrWindow(x, y, x + w - 1, y + h - 1); // координаты окна 0,0 - 127-159
int16_t i, j, byteWidth = (w + 7) / 8;
uint8_t bytes;
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
if (i & 7) {
bytes <<= 1; /*Serial.println("in if");*/
} else {
bytes = pgm_read_byte(bitmap + j * byteWidth + i / 8);/*Serial.print(byte);Serial.println(" - in else");*/
}
if (bytes & 0x80)
{
tft.pushColor(color_1 ); /*Serial.println("цвет 1");*/
}
else {
tft.pushColor(color_2 ); /*Serial.println("цвет 2");*/
}
}
}
}
/////////////////////////////////////////////////////////////////////
Фантазии человека безграничны!
Отвлёкся я на скорость вывода картинки от вариаций раскрашивания. Пока в голову пришло три варианта - сектора цвета, градиент цвета и пиксель-ассорти. Какие ещё варианты могут быть?
PS. Но, прежде, чем рассуждать, хотелось бы понять, зачем это все может понадобиться?
:)
А возможности нет.
... Либо каждый изолированный фрагмент заливается своим цветом.
...Еще цвет может зависеть от времени.
... хотелось бы понять, зачем это все может понадобиться?
...Это самый интересный и трудно реализуемый вариант раскраски.
...Был бы интересен при анимации, но перерисовка экрана медленная даже при tft.setAddrWindow(0,0,128,160); и ... if(...) { tft.pushColor(tft.Color565(255,255,255) );}else { tft.pushColor(tft.Color565(0,0,0) );}
...Для полноценного использования экрана с про мини и уно.
... Либо каждый изолированный фрагмент заливается своим цветом.
...Еще цвет может зависеть от времени.
... хотелось бы понять, зачем это все может понадобиться?
...Это самый интересный и трудно реализуемый вариант раскраски.
...Был бы интересен при анимации, но перерисовка экрана медленная даже при tft.setAddrWindow(0,0,128,160); и ... if(...) { tft.pushColor(tft.Color565(255,255,255) );}else { tft.pushColor(tft.Color565(0,0,0) );}
...Для полноценного использования экрана с про мини и уно.
Экран должен выполнять свои функции в пределах поставленной задачи. Все. Какое еще может быть полноценное использование?
PS. Ну и позволю себе еще раз вернуться к вопросу скорости отрисовки.
1. То, что подход, проиллюстрированный в ответе на п.2 не может быть быстрым по определению, я уже сказал.
2. То, что на мой взгляд, следовало бы сначала научиться быстро работать с экраном и только потом начинать извращаться, я тоже писал ранее.
3. Для ускорения вывода имеет смысл перейти с последовательного интерфейса на параллельный.
:)
А возможности нет.
как говорил один богатый человек - "Вы даже представить себе не можете, что можно сделать имея миллиард долларов"
[quote=andriano]
Реализуется просто до безобразия, только для этого нужно иметь возможность читать цвет, что при последовательном интерфейсе, как правило, не поддерживается.
[quote]
Мне кажется достаточно уметь находить в массиве данных картинки границы локаций 0 или 1. Как чтение цвета пикселя экрана это реализует? Впрочем тема где то тут на форуме была про чтение из экрана 18 бит данных на пиксель и дальнейшее использование, но до библиотеки дело не дошло :)
В рамках имеющегося модуля-экрана параллельный интерфейс не пройдёт.
Поставленная задача..., например, мимика-моська робота в цвете на про мини 168.
Мне кажется достаточно уметь находить в массиве данных картинки границы локаций 0 или 1. Как чтение цвета пикселя экрана это реализует?
Т.е. когда мы на экране добавляем третий цвет, то эта информация уже может использоваться для дальнейшей раскраски. А в исходном двухцветном изображении этой информации еще нет.
Поставленная задача..., например, мимика-моська робота в цвете на про мини 168.
Задача может быть: построить прибор с определенными техническими характеристиками. А "робота в цвете" - это не задача. И "на про мини" - это тоже не задача.
В исходном массиве у нас двух цветное изображение. Ну нашли мы границу, откуда нам знать, в какой цвет красить по одну сторону, и в какой - по другую?
Нет такой задачи.
Задача может быть: построить прибор с определенными техническими характеристиками. А "робота в цвете" - это не задача. И "на про мини" - это тоже не задача.
Одну локацию в один цвет, соседнюю в другой.
Т.е. создать поделку с заданными св-вами на заданных модулях это не задача? Вот незадача :)
Т.е. создать поделку с заданными св-вами на заданных модулях это не задача? Вот незадача :)
"создать поделку с заданными св-вами" - это задача. А "на заданных модулях" - это лишь пожелание.
Тогда SPI.transfer(&lineBuf, dispW); останется и должна заработать?, а в tft.setAddrWindow(0, j, dispW-1, j); убрать хвост tft.
никаких хвостов убирать не надо
по хорошему добавить в библиотеку Адафрута новую функцию которая выводит не пиксель, я именно строку.
Завтра может время найду поставлю эти библиотеки. посмотрю.
Не дождался, извратил-исправил код (не знаю сдвиги-преобразования битов в байтах) до рабочего, и действительно так быстрее чем у меня (нос Эйнштейна просматривается чётко в попе у Шерон Стоун). Но как теперь делить два байта цвета на части?
Мой вариант
Эйнштейн и Стоун
Тогда SPI.transfer(&lineBuf, dispW); останется и должна заработать?, а в tft.setAddrWindow(0, j, dispW-1, j); убрать хвост tft.
никаких хвостов убирать не надо
по хорошему добавить в библиотеку Адафрута новую функцию которая выводит не пиксель, я именно строку.
Завтра может время найду поставлю эти библиотеки. посмотрю.
Не дождался,
Сорри, никак не найду время :(
по поводу цветов, вот тема была (если я правильно вопрос понял):
https://arduino.ru/forum/programmirovanie/sortirovka-palitry-rgb565#comm...
(если я правильно вопрос понял):
https://arduino.ru/forum/programmirovanie/sortirovka-palitry-rgb565#comm...
Нет, я не сообразил сходу как делить на 2 части tft.Color565(255,255,0) . Теперь сообразил. Вот пример радужного секундомера (для опытов на "пипика" :)
и картинка фоновая для него.
Забавно, если присмотреться к массиву, то картинка в нём просматривается :)
Не поленился, сделал сравнительный тест вариантов вывода картинок в режиме раскраски.
Визуально преимущества в скорости вывода почти сошли на нет :(
не компилируется
lilik, ну нет вариантов натянуть сову на глобус)
У atmega328p есть свой предел и у дисплея тоже, если выкините adafrut библиотеки и начнёте напрямую с дисплеем общаться, будет побыстрее, но глобально для мультиков менять МК!
не компилируется
По переводу понял что с маленькой буквы надо писать Color, но у меня в библиотеке с большой в функции:
Может посмотрите у себя в файле "адафрукт ST_7735".cpp с большой или с маленькой.
Ну всё равно, принципиально эти варианты на порядок лучше чем по точечный вывод картинки. Как напрямую работать статей толковых в интернете не видел.
Дык статей и не будет, даташит и вперёд, руками отправляем в spi нужные команды и будет счастье.
Я с ili9341 тупо нашёл самую простую библиотеку, её разобрал по косточкам и просто что то добавил.
Adafrut библиотеки мне кажется слишком перегружена универсальностью (
не компилируется
По переводу понял что с маленькой буквы надо писать Color, но у меня в библиотеке с большой в функции:
Может посмотрите у себя в файле "адафрукт ST_7735".cpp с большой или с маленькой.
у меня такой функции вообще нет, библиотеку поставил сейчас с сайта arduino.cc 1.9 версии, но и в прежней не было
а цвета перевожу своей функцией, правда ее адриано поправил, у меня было в лоб...
я на RP2040 пробую, пока не взлетело, почему-то картинка не выводится, loop отрабатывает
...почему-то картинка не выводится, loop отрабатывает
Из 114 сообщения тест раскраски можно попробовать.
Адафрутовскую функцию можно в скетч вставить, только хвост tft. откинуть от tft.Color565(255,255,255);
...почему-то картинка не выводится, loop отрабатывает
Из 114 сообщения тест раскраски можно попробовать.
Адафрутовскую функцию можно в скетч вставить, только хвост tft. откинуть от tft.Color565(255,255,255);
я на свою поменял, кстати адриано похоже поправил неправильно, у меня было так -
Я картинки прямо в скетч вставил, правильно?
У меня отдельный файл в папке со скетчем, назвал его ris.c
... но и в прежней не было
Самое смешное - не могу вспомнить где я брал вариант библиотеки. На гитхабе смотрел- нет функции этой нигде.
... но и в прежней не было
Самое смешное - не могу вспомнить где я брал вариант библиотеки. На гитхабе смотрел- нет функции этой нигде.
много ссылок, что скетчи ругаются на эту функцию, так надо проверить, в функции 100500 байт цвета blue правильно переводится..сейчас буду проверять, что-то мне адриано не то подсказал, чую
Я жеж под rp2040 пока не одолел, висит в твоей функции, всё выводит да выводит, но на экране ничего...
см. сообщение 129
как бы пространственные рассуждения о точности цветопередачи при перекодировании в формат 565 и скетч, адриано заблуждался )))
я тут чуток порассуждал и пришёл к выводу, что правильней функцию сделать так:
ua6em, что-то не могу найти своего исходного сообщения. Но, не исключено, я там действительно напутал.
Правильные варианты:
((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3)
или
((r >>3) << 11) | ((g >>2) << 5) | (b >> 3)
Эти варианты эквивалентны.
Кроме того, | можно заменить на +.
Кроме того, | можно заменить на +.
проверил, если в расчётах перевести на флоат (что не правильно) всё равно разброс по переводным данным, правильно - отбросить незначащие биты, а это только сдвиг...
Я в два захода приводил, так как пока не отложилось, что делается вначале, что слева, что справа (для однозначности)...ты показал, осталось запомнить )))
перевод обсуждали тут
Вот такой вариант использовал на матрице ws2812b, взял на забугорном форуме.
из JPG на экран выводил так, тоже с какого то форума:
всё равно разброс по переводным данным, правильно - отбросить незначащие биты, а это только сдвиг...
И в связи с отмеченным выше, совершенно непонятно, откуда у Вас появился "разброс по переводимым данным".
Вот такой вариант использовал на матрице ws2812b, взял на забугорном форуме.
На примере десятичной арифметики это как бы число 53 округлять не до 50, а до 3.
Ну и второе - ws2812 требует 24-разрядного цвета, зачем там приводить к 16 разрядам?
И в связи с отмеченным выше, совершенно непонятно, откуда у Вас появился "разброс по переводимым данным".
ну я то изначально делю 31 или 63 на 255, в этом случае вся дробная часть (хоть это 0.999) отбрасывается, от того и разброс...
я вот только не знаю, в C++ сдвиг с переносом старших (или младших) битов идет или без оных, если с переносом, то сначала надо незначащие биты обнулить, тогда сперва логическое & а потом сдвиг
что-то никак не одолею с этой RP2040, на экран при инициализации вывожу заставку, она и висит, скетч далее такой:
ЗЫ сейчас раз в секунду в монитор порта летит - работаю )))
ну я то изначально делю 31 или 63 на 255, в этом случае вся дробная часть (хоть это 0.999) отбрасывается, от того и разброс...
я вот только не знаю, в C++ сдвиг с переносом старших (или младших) битов идет или без оных, если с переносом, то сначала надо незначащие биты обнулить, тогда сперва логическое & а потом сдвиг
Циклический сдвиг реализуется примерно так (для 16-разрядного целого):
x = (x >> k) | (x << (16-k));
ua6em, а что это за
uint8_t byte;
?
Я бы поостерегся так называть переменную.
[
Ну и второе - ws2812 требует 24-разрядного цвета, зачем там приводить к 16 разрядам?
Для пользования библиотекой "адафрукт GFX"
Кстати именно из неё запись про byte.
И ещё: про функцию Color565. У меня в иде встроена библиотека TFT. А она лишь ширма для адафрутовской GFX и ST7735. А вот уже в ней и есть эта функция. Я не знал, у меня получается дубликаты стоят.
ua6em, а что это за
uint8_t byte;
?
Я бы поостерегся так называть переменную.
я тоже, код сдёрнул у ТС, выше по теме, попробую заменить
ua6em, а что это за
uint8_t byte;
?
Я бы поостерегся так называть переменную.
я тоже, код сдёрнул у ТС, выше по теме, попробую заменить
Я тоже взял это из библиотеки.
Такой секундомер должен выйти.
Из вот такой ч/б.
Отвлёкся я на скорость вывода картинки от вариаций раскрашивания. Пока в голову пришло три варианта - сектора цвета, градиент цвета и пиксель-ассорти. Какие ещё варианты могут быть?
Прорыв в нанотехнологиях :)
Догадался как выделять контур изображения. Функцию по наитию переделал.
Сколько кадров в секунду? Не меряли?
На таком варианте 5 кадров в секунду.
В принципе, при таком алгоритме выделения контура рисунка, можно контур сделать двухцветным - для большей выразительности по сравнению с исходным ч/б изображением.
Нам учитель задаёт с иксами задачу...это я к тому, что только решил одну задачку, ты подкинул вторую...
Под Rasberry PI Pico RP2040 предыдущее заработало!!!
Нам учитель задаёт с иксами задачу...это я к тому, что только решил одну задачку, ты подкинул вторую...
Под Rasberry PI Pico RP2040 предыдущее заработало!!!
Из 147 сообщения теперь можно пробовать :)
картинка:
не идёт, у него SPI 32-х разрядный, по 4 байта сразу кидает, это не отрабатывает: