ESP8266+экран ST7735, вывод изображения из памяти без SD карты.
- Войдите на сайт для отправки комментариев
Ср, 04/11/2020 - 08:03
Встал вопрос о выводе изображения без использования внешнего модуля SD(microSD) карт.
Имеем ESP8266, модуль ST7735S 0.96" 80x160 SPI
Заливаю файлы, предварительно подготовленные для этого экрана (с SD всё работало) в память модуля spiffs, по инструкции из простор интернета.
#include "FS.h" #include <Adafruit_GFX.h> // Core graphics library #include <Adafruit_ST7735.h> // Hardware-specific library #include <SPI.h> #define TFT_CS D2 #define TFT_RST D3 #define TFT_DC D4 Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); void setup(void) { Serial.begin(115200); tft.initR(INITR_MINI160x80); tft.initR(INITR_GREENTAB); //инвертирует цвета в норму tft.invertDisplay(true); tft.setRotation(1); // положение картинки горизонтально } void loop() { bmpDraw("1.bmp", 0, 0); delay(4000); } #define BUFFPIXEL 20 void bmpDraw(char *filename, uint8_t x, uint8_t y) { File bmpFile; int bmpWidth, bmpHeight; // W+H in pixels uint8_t bmpDepth; // Bit depth (currently must be 24) uint32_t bmpImageoffset; // Start of image data in file uint32_t rowSize; // Not always = bmpWidth; may have padding uint8_t sdbuffer[3 * BUFFPIXEL]; // pixel buffer (R+G+B per pixel) uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer boolean goodBmp = false; // Set to true on valid header parse boolean flip = true; // BMP is stored bottom-to-top int w, h, row, col; uint8_t r, g, b; uint32_t pos = 0, startTime = millis(); if ((x >= tft.width()) || (y >= tft.height())) return; Serial.println(); Serial.print("Loading image '"); Serial.print(filename); Serial.println('\''); // Open requested file on SD card if (File file = SPIFFS.open("/test_example.txt", "r") == NULL) { Serial.print("File not found"); return; } // Parse BMP header if (read16(bmpFile) == 0x4D42) { // BMP signature Serial.print("File size: "); Serial.println(read32(bmpFile)); (void)read32(bmpFile); // Read & ignore creator bytes bmpImageoffset = read32(bmpFile); // Start of image data Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC); // Read DIB header Serial.print("Header size: "); Serial.println(read32(bmpFile)); bmpWidth = read32(bmpFile); bmpHeight = read32(bmpFile); if (read16(bmpFile) == 1) { // # planes -- must be '1' bmpDepth = read16(bmpFile); // bits per pixel Serial.print("Bit Depth: "); Serial.println(bmpDepth); if ((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed goodBmp = true; // Supported BMP format -- proceed! Serial.print("Image size: "); Serial.print(bmpWidth); Serial.print('x'); Serial.println(bmpHeight); // BMP rows are padded (if needed) to 4-byte boundary rowSize = (bmpWidth * 3 + 3) & ~3; // If bmpHeight is negative, image is in top-down order. // This is not canon but has been observed in the wild. if (bmpHeight < 0) { bmpHeight = -bmpHeight; flip = false; } // Crop area to be loaded w = bmpWidth; h = bmpHeight; if ((x + w - 1) >= tft.width()) w = tft.width() - x; if ((y + h - 1) >= tft.height()) h = tft.height() - y; // Set TFT address window to clipped image bounds tft.setAddrWindow(x, y, x + w - 1, y + h - 1); for (row = 0; row < h; row++) { // For each scanline... // Seek to start of scan line. It might seem labor- // intensive to be doing this on every line, but this // method covers a lot of gritty details like cropping // and scanline padding. Also, the seek only takes // place if the file position actually needs to change // (avoids a lot of cluster math in SD library). if (flip) // Bitmap is stored bottom-to-top order (normal BMP) pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize; else // Bitmap is stored top-to-bottom pos = bmpImageoffset + row * rowSize; if (bmpFile.position() != pos) { // Need seek? bmpFile.seek(pos); buffidx = sizeof(sdbuffer); // Force buffer reload } for (col = 0; col < w; col++) { // For each pixel... // Time to read more pixel data? if (buffidx >= sizeof(sdbuffer)) { // Indeed bmpFile.read(sdbuffer, sizeof(sdbuffer)); buffidx = 0; // Set index to beginning } // Convert pixel from BMP to TFT format, push to display b = sdbuffer[buffidx++]; g = sdbuffer[buffidx++]; r = sdbuffer[buffidx++]; tft.pushColor(tft.Color565(r, g, b)); } // end pixel } // end scanline Serial.print("Loaded in "); Serial.print(millis() - startTime); Serial.println(" ms"); } // end goodBmp } } bmpFile.close(); if (!goodBmp) Serial.println("BMP format not recognized."); } // These read 16- and 32-bit types from the SD card file. // BMP data is stored little-endian, Arduino is little-endian too. // May need to reverse subscript order if porting elsewhere. uint16_t read16(File f) { uint16_t result; ((uint8_t *)&result)[0] = f.read(); // LSB ((uint8_t *)&result)[1] = f.read(); // MSB return result; } uint32_t read32(File f) { uint32_t result; ((uint8_t *)&result)[0] = f.read(); // LSB ((uint8_t *)&result)[1] = f.read(); ((uint8_t *)&result)[2] = f.read(); ((uint8_t *)&result)[3] = f.read(); // MSB return result; }
Смущает 50 строка кода, да может и сам скетч неправильно. Поправьте если неправильно написал. Там
Пишет Loading image '1.bmp'
Не могу поправить шапку, не понимаю как изменить.
никогда не пишите все в одну строчку...
правильно будет так:
Для этого лучше пользоваться библиотекой TFT_eSPI она проще и в настройках удобнее ее можно настроить под любой монитор. И скорость хорошая вот пример: https://yadi.sk/i/OvliKj5UOToVNw
Это простой код для демонстрации фото.
1.h код будет примерно такой.
Nikolaha53rus, есть такой анекдот про физиков:
Задача 1
дано: пустой чайник, кран с водой, газовая горелка, спички.
нужно: вскипятить воду.
решение:
- открыть кран,
- налить в чайник воды,
- закрыть кран,
- зажечь спичку,
- от спички зажечь горелку,
- поставить чайник на горелку,
- ждать, пока вода закипит.
Задача 2
дано: кран, чайник с водой, зажженная горелка, спички.
нужно: вскипятить воду.
решение:
Уважаемый Аndriano!!! Ответ очень прост, я чайник, мне никто, никогда не объяснял принципы работы и программирования МК, я пытаюсь учится с нуля, и помочь мне как здесь некому, не судите строго, я думаю Вы тоже не сразу взяли и начали программировать.
Уважаемый Nikolaha53rus, никто и никогда не объяснял тут andriano принципы работы и программирования МК. Знаете почему? Потому что над форумом не висит табличка "образовательное учреждение".
Совершенно непонятно кто Вас нагло обманул, рассказав, что всех тут учат с нуля и до конца. Но, если вы, вдруг, этого человека таки поймаете - плюньте ему в лицо, очень Вас прошу.
Ладно, проехали, я просто прошу помощи. Поможете, очень хорошо, не поможете, тоже не обижусь.
Я просто не понимаю как это работает, и хочу разобраться, с Вашей помощью. Не кидайтесь тапками. Извините если что не так сказал.
IVAN222 Сюда вставите изображение созданное программкой в формате
"С"
Подскажите чем конвертировать?
Странный форум, не пойму почему текст синий.
Отправьте на правила форума, киньте ссылку. Покопался, не вижу.
Вы можете скачать любой конвертер я предлагаю такую lcd-image-converter. с помощью ее конвертируете изображения с BMP,JPG в "С" для ESP это будет лучше а главное очень быстро.
я думаю Вы тоже не сразу взяли и начали программировать.
Я просто не понимаю как это работает, и хочу разобраться, с Вашей помощью.
1. Вы хотите научиться работать с Ардуино.
2. Вы хотите реализовать конкретный проект.
Так вот, традиции (и Правила) форума диктуют совершенно различную реакцию на эти варианты.
Если Вы хотите научиться, Вам следует отложить в сторону вышеупомянутый проект и начать с мигания светодиодом. К проекту Вы вернетесь не ранее, чем через год-два. Естественно, этот варианта подразумевает самостоятельное чтение учебников (без просьб к форуму пересказать, что в этих учебниках написано). В этом случае Вам здесь помогут преодолеть все сложности, с которыми Вы столкнетесь в процессе обучения.
Если же Вам нужно реализовать конкретный проект, а Вашей квалификации для этого недостаточно, то выход один: обратиться в платный раздел "Ищу исполнителя".
PS. Да, Правила содержатся в прикрепленной теме в разделе "Песочница". Если Вы собираетесь идти по первому пути, найдете там много полезной информации. Впрочем, если по второму, то изложенная там информация тоже окажется полезной.
Да ладно, даже если человек 40 лет программировал для него ардуинка может быть темным лесом, например я в начале 90х годов программировал на CLARION + Pascal, сейчас для меня основной язык это 1С, и для меня Cи очень тяжелый язык, немного выручает, то что недавно делал несколько больших проектов на PHP, там синтаксис близок...
Ну и про год самообучения до минимального уровня - это слишком страшно, я никогда в жизни не видя Си за пару месяцев сделал вполне рабочий проект http://arduino.ru/forum/proekty/kontroller-mufelnoi-pechi Ардуино тем и хороша, что очень простая и в нее порог входа вообще смешной...
На самом известном форуме по 1с я модератор и навидался много, главное чего надо требовать от вопрошающего - это воспринимать те советы которые ему дают и пытаться точно сформулировать проблему
в САБЖе автор разумеется не имеет классических навыков программирования, по этому он идет путем проб и ошибок. Его надо направлять туда где он сможет понять чего ему делать (например меня в последней моей ветке про сканер пальцев именно так и толкали). А вот выдавая ему точные советы которые он еще не в состоянии понять просто бесполезно (так например мне вряд ли помогут советы про схемотехнику всяких усилителей и прочего, я все равно не буду разбиратся в конкретной схемотехнике, по тому, что это не мое и я выбираю именно ардуинку как целый модуль а не микроконтроллер который надо прикрутить куда то).
Ладно, проехали, я просто прошу помощи. Поможете, очень хорошо, не поможете, тоже не обижусь.
Я просто не понимаю как это работает, и хочу разобраться, с Вашей помощью. Не кидайтесь тапками. Извините если что не так сказал.
если действительно хочешь разобраться, делается это так
берешь код, выделяешь одну процедуру, и каждую строку коментрируешь, потом на основе этого пишешь назначение этой процедуры.
Так далее весь код
//Не забудьте изменить User_Setup.h внутри библиотеки TFT_eSPI!
Раскомментировал
#define ST7735_DRIVER
#define TFT_WIDTH 160
#define TFT_HEIGHT 80
#define ST7735_GREENTAB
если действительно хочешь разобраться, делается это так
берешь код, выделяешь одну процедуру, и каждую строку коментрируешь, потом на основе этого пишешь назначение этой процедуры.
Так далее весь код
и куда потом этот комментированный код? в форум? - не надо :)
Или это для самообразования?
Nikolaha53rus - вы зря так негативно реагируете на советы andriano. Он говорит очень правильные вещи. Если предварительно обработаете свои картинки на компе и в ЕСП загрузите уже готовые массивы - программа станет в несколько раз проще и вам самому, как новичку - будет прощее ее отлаживать.
sck-D5
sda-D7
ao-D3
reset-D4
cs-D8
gnd--
vcc-+3,3 или 5 в
led-+3,3 в
раскаментируй
#define ST7735_DRIVER
#define TFT_WIDTH 80
#define TFT_HEIGHT 160
#define TFT_CS PIN_D8 // Chip select control pin D8
#define TFT_DC PIN_D3 // Data Command control pin
#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
попробуй так
у меня нет таких выводов
Есть вот такие scl,sda,res,dc,cs
Не работает. вообще тишина. Ни примеры из библиотеки, ни скетч из 3-го поста. Экран 100% рабочий, с Adafruit на ESP8266 работает, на UNO c SD картой работает.
Скетч заливается, но ничего не происходит.
Я не негативно реагирую, я просто что то не понимаю, и прошу мне объяснить. Я с Уважаемым andriano полностью согласен, много лишних действий, только мне не хватает мозгов всё это реализовать. Кто то шарит в машинах, кто то в контроллерах, кто то в локальных сетях, видеонаблюдении и т.д., и когда что то непонятно просят помощи. Вот так и я. Это для самообразования. Много чего знаю, а вот с МК пробел. Именно с данным ST7735S. Другие проекты я мог подсмотреть примеры, и настроить под себя. Тут засада.
Проверти все контакты если плохой контакт то вообще не запустится.
сначала раскоментируйте
#define ST7735_DRIVER
запустите .
потом
#define TFT_RGB_ORDER TFT_RGB
попробуйте это
#define ST7735_GREENTAB160x80
надо пробовать и другие .у меня именно такого монитора нет и я немогу сказать что именно раскоментировать.
ОК. Переводил комментарии в setup, вроде всё правильно делаю. Ещё раз проверю.
https://github.com/olikraus/u8g2/blob/master/sys/arduino/u8g2_full_buffe...
Тут вон вроде крутят битмапы, библиотека мощная.
Она не поддерживает ST7735.
Если кто тоже столкнется с ошибкой "BMP format not recognized." (гугл ведет сюда).
Итак, исходные данные:
- либа TFT_eSPI.
-cкетч - копипаста из примера TFT_eSPI/examples/Generic/TFT_SPIFFS_BMP
-картинка сгенерирована в гимпе, сохранена в data, загружена в SPIFFS.
Заливаем картинку, заливаем скетч, открываем монитор порта, видим ошибку BMP format not recognized.
Такой текст можно найти в файле проекта "bmpFunctions":
Открываем нашу картинку в hex-редакторе, видим, что там нет этих значений на своем определенном месте, а в картинке из примера - эти байты есть.
Решил путем научного тыка, пересохраняя картинку с разными параметрами, нужные параметры:
if ((read16(bmpFS) == 1) && (read16(bmpFS) == 24) && (read32(bmpFS) == 0))
Вот только код стремный: я сейчас навскидку не помню, оговорен ли в Си порядок вычисления логического выражения. Если "да", причем "слева направо" - все нормально, а если "нет" - можно обломаться. Лично я, чтобы не путаться в особенностях разных языков, предпочел бы сначала вычитать в нужном порядке переменные, и только потом делать проверки.
PS. И еще: на мой взгляд, хранить для МК картинки в одном из стандартных форматов вряд ли целесообразно. Гораздо лучше написать для ПК утилиту, которая перекодирует BMP в удобный для МК формат, и уже перекодированные картинки размещать на карте. Заодно можно решить и проблему с поддержкой всех вариантов формата BMP. А заодно и не только BMP, можно добавить JPG, PNG, GIF и другие форматы.