Cat hungry.png
Здравствуйте! Собираем деньги на перевод материалов по электронике(https://www.allaboutcircuits.com/education/). Реквизиты указаны здесь.

Arduino:Примеры/spitftbitmap

Материал из Онлайн справочника
Перейти к: навигация, поиск

Перевод: Максим Кузьмин (Cubewriter)
Перевел 2686 статей для сайта.

Контакты:

Проверка/Оформление/Редактирование: Мякишев Е.А.


Вывод изображения на 1,8-дюймовый или 1,44-дюймовый TFT-дисплей[1]

Это скетч для библиотеки ST7735, который при помощи платы Arduino показывает на TFT-дисплее (1,8-дюймовый или 1,44-дюймовый) заданную картинку. Для скетча потребуется 1,8-дюймовая TFT-плата с SD-картой или «голый» 1,8-дюймовый TFT-дисплей.

Код

  1.  
  2. /***************************************************
  3.  
  4. Вывод изображения на 1,8-дюймовый или 1,44-дюймовый TFT-дисплей
  5.  
  6. Этот скетч предназначен для 1,8-дюймового или 1,44-дюймового
  7. TFT-дисплея, работающего через SPI-интерфейс (от Adafruit).
  8.  
  9. Для этого скетча подойдет 1,8-дюймовая TFT-плата с SD-картой
  10. ----> http://www.adafruit.com/products/358
  11. или 1,8-дюймовый TFT-модуль
  12. ----> https://www.adafruit.com/product/802
  13. или 1,44-дюймовая TFT-плата
  14. ----> https://www.adafruit.com/product/2088
  15. или «голый» 1,8-дюймовый TFT-дисплей
  16. ----> http://www.adafruit.com/products/618
  17.  
  18. Руководства и схемы подключения ищите по ссылкам выше. Этим дисплеям
  19. для коммуникации требуется SPI-интерфейс с 4 или 5 контактами (контакт
  20. RST опционален).
  21.  
  22. Adafruit инвестировала время и ресурсы, создавая эту библиотеку с
  23. открытым кодом. Пожалуйста, поддержите Adafruit и оборудование с
  24. открытым кодом, покупая продукты Adafruit!
  25.  
  26. Библиотека написана Лимор Фрид (Limor Fried, Ladyada) для Adafruit
  27. Industries. Весь текст выше должен быть включен при любом повторном
  28. распространении.
  29.  
  30. ****************************************************/
  31.  
  32. #include <Adafruit_GFX.h>    // подключаем графическую библиотеку
  33. #include <Adafruit_ST7735.h> // подключаем библиотеку для управления дисплеем
  34. #include <SPI.h>
  35. #include <SD.h>
  36.  
  37. // Коммуникация будет вестись через аппаратный SPI-интерфейс,
  38. // и им будут пользоваться сразу два устройства: TFT-дисплей
  39. // и SD-карта. На платах Arduino аппаратный SPI всегда находится на
  40. // одних и тех же контактах, и переназначить их нельзя.
  41. // На Arduino Uno, Duemilanove и т.д. за SPI отвечают следующие
  42. // контакты: 11-ый контакт – MOSI, 12-ый контакт – MISO,
  43. // 13-ый контакт – SCK.
  44.  
  45. #define TFT_CS  10  // CS-контакт для TFT-дисплея
  46. #define TFT_RST  9  // RESET-контакт для TFT-дисплея (или см. ниже)
  47. #define TFT_DC   8  // DC-контакт для TFT-дисплея (для переключения между передачей данных и команд)
  48. #define SD_CS    4  // CS-контакт для SD-карты
  49.  
  50. // Это RESET-контакт для TFT-модуля
  51. //#define TFT_RST  0  // этот контакт также можно подключить к RESET-контакту Arduino
  52.  
  53. Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
  54.  
  55. void setup(void) {
  56.   Serial.begin(9600);
  57.  
  58.   // инициализатор для 1,8-дюймового дисплея:
  59.   tft.initR(INITR_BLACKTAB);
  60.  
  61.   // инициализатор для 1,44-дюймового дисплея (раскомментируйте):
  62.   //tft.initR(INITR_144GREENTAB);
  63.  
  64.   Serial.print("Initializing SD card...");  //  "Инициализация SD-карты... "
  65.   if (!SD.begin(SD_CS)) {
  66.     Serial.println("failed!");  //  "не удалась"
  67.     return;
  68.   }
  69.   Serial.println("OK!");
  70.  
  71.   // поменяйте название картинки, если нужно:
  72.   bmpDraw("parrot.bmp", 0, 0);
  73.   // ждем 5 секунд:
  74.   delay(5000);
  75. }
  76.  
  77. void loop() {
  78. // раскомментируйте этот код, если хотите нарисовать картинку
  79. // в другом месте и немного ее повращать.
  80. /*
  81.   tft.fillScreen(ST7735_BLACK); // очищаем дисплей
  82.   for(uint8_t i=0; i<4; i++)    // рисуем 4 попугая
  83.     bmpDraw("parrot.bmp", tft.width() / 4 * i, tft.height() / 4 * i);
  84.   delay(1000);
  85.   tft.setRotation(tft.getRotation() + 1); // вращение на 90 градусов
  86. */
  87. }
  88.  
  89. // Эта функция открывает BMP-файл и печатает его на заданных
  90. // координатах. Ее работу можно ускорить, считывая сразу несколько
  91. // пикселей, а не пиксель за пикселем. Для этого нужно увеличить
  92. // размер буфера, однако это, в свою очередь, потребует ресурсов
  93. // RAM-памяти Arduino. Разумным компромиссом будет 20 пикселей.
  94.  
  95. #define BUFFPIXEL 20
  96.  
  97. void bmpDraw(char *filename, uint8_t x, uint8_t y) {
  98.  
  99.   File     bmpFile;
  100.   int      bmpWidth, bmpHeight;   // ширина и высота в пикселях
  101.   uint8_t  bmpDepth;              // глубина цвета (по умолчанию должно стоять 24)
  102.   uint32_t bmpImageoffset;        // место, с которого в файле начинается само изображение
  103.   uint32_t rowSize;               // это значение не всегда будет равно bmpWidth; возможно, будет отступ
  104.   uint8_t  sdbuffer[3*BUFFPIXEL]; // буфер для пикселей (значения R, G и B для каждого пикселя)
  105.   uint8_t  buffidx = sizeof(sdbuffer); // текущая позиция в буфере для пикселей
  106.   boolean  goodBmp = false;       // если скетч определит нужный тип заголовка, он выставит здесь «true»
  107.   boolean  flip    = true;        // данные BMP-файла хранятся по принципу «снизу вверх»
  108.   int      w, h, row, col;
  109.   uint8_t  r, g, b;
  110.   uint32_t pos = 0, startTime = millis();
  111.  
  112.   if((x >= tft.width()) || (y >= tft.height())) return;
  113.  
  114.   Serial.println();
  115.   Serial.print("Loading image '");  //  "Загрузка изображения «"
  116.   Serial.print(filename);
  117.   Serial.println('\'');
  118.  
  119.   // открываем на SD-карте запрашиваемый файл:
  120.   if ((bmpFile = SD.open(filename)) == NULL) {
  121.     Serial.print("File not found");  //  "Файл не найден"
  122.     return;
  123.   }
  124.  
  125.   // анализируем заголовок BMP-Файла:
  126.   if(read16(bmpFile) == 0x4D42) { // сигнатура BMP-файла
  127.     Serial.print("File size: ");  //  "Размер файла: "
  128.     Serial.println(read32(bmpFile));
  129.     (void)read32(bmpFile); // считываем и игнорируем байты, вписанные при создании файла
  130.     bmpImageoffset = read32(bmpFile); // место, с которого начинается в файле само изображение (смещение)
  131.     Serial.print("Image Offset: ");  //  "Смещение: "
  132.     Serial.println(bmpImageoffset, DEC);
  133.     // считываем заголовок DIB:
  134.     Serial.print("Header size: ");  //  "Размер заголовка: "
  135.     Serial.println(read32(bmpFile));
  136.     bmpWidth  = read32(bmpFile);
  137.     bmpHeight = read32(bmpFile);
  138.     if(read16(bmpFile) == 1) {  //  количество цветовых плоскостей – должно быть «1»
  139.       bmpDepth = read16(bmpFile); // биты на пиксель
  140.       Serial.print("Bit Depth: ");  //  "Глубина цвета: "
  141.       Serial.println(bmpDepth);
  142.       if((bmpDepth == 24) && (read32(bmpFile) == 0)) {  //  «0» – это без сжатия
  143.  
  144.         goodBmp = true; // поддерживаемый формат BMP – продолжаем дальше!
  145.         Serial.print("Image size: ");  //  "Размер изображения: "
  146.         Serial.print(bmpWidth);
  147.         Serial.print('x');
  148.         Serial.println(bmpHeight);
  149.  
  150.         // если нужно, границы BMP-изображения будут иметь 4-байтный отступ:
  151.         rowSize = (bmpWidth * 3 + 3) & ~3;
  152.  
  153.         // Если значение в bmpHeight отрицательное, то данные
  154.         // изображения хранятся по принципу «сверху вниз»
  155.         // Это не канон, но иногда встречается.  
  156.         if(bmpHeight < 0) {
  157.           bmpHeight = -bmpHeight;
  158.           flip      = false;
  159.         }
  160.  
  161.         // загружаем обрезанную область:
  162.         w = bmpWidth;
  163.         h = bmpHeight;
  164.         if((x+w-1) >= tft.width())  w = tft.width()  - x;
  165.         if((y+h-1) >= tft.height()) h = tft.height() - y;
  166.  
  167.         // задаем адресный промежуток для границ обрезанного изображения:
  168.         tft.setAddrWindow(x, y, x+w-1, y+h-1);
  169.  
  170.         for (row=0; row<h; row++) { // для каждого пиксельного ряда...
  171.  
  172.           // Ищем начало пиксельного ряда. Возможно, делать это для
  173.           // каждой строки – слишком трудоемко, однако эта функция
  174.           // выполняет много «грязной работы» вроде обрезки
  175.           // изображения и создания отступа для нового пиксельного
  176.           // ряда. Кроме того, этот поиск имеет место только в том
  177.           // случае, если нужно поменять позицию файла (это позволяет
  178.           // избежать кластерных расчетов в библиотеке SD).
  179.  
  180.           if(flip) // данные BMP-файла хранятся по принципу «снизу вверх» (нормальный BMP)
  181.             pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
  182.           else     // BMP-файл хранится по принципу «сверху вниз»
  183.             pos = bmpImageoffset + row * rowSize;
  184.           if(bmpFile.position() != pos) { // нужно ли запустить поиск?
  185.             bmpFile.seek(pos);
  186.             buffidx = sizeof(sdbuffer); // перезагружаем буфер
  187.           }
  188.  
  189.           for (col=0; col<w; col++) { // для каждого пикселя...
  190.             // настало время считывать новые пиксельные данные?        
  191.             if (buffidx >= sizeof(sdbuffer)) { // да!
  192.               bmpFile.read(sdbuffer, sizeof(sdbuffer));
  193.               buffidx = 0; // выставляем индекс на начало
  194.             }
  195.  
  196.             // конвертируем пиксели из формата BMP в формат TFT,
  197.             // а затем выводим их на дисплей:
  198.             b = sdbuffer[buffidx++];
  199.             g = sdbuffer[buffidx++];
  200.             r = sdbuffer[buffidx++];
  201.             tft.pushColor(tft.Color565(r,g,b));
  202.           } // последний пиксель
  203.         } // последняя строка пикселей
  204.         Serial.print("Loaded in ");  //  "Картинка загрузилась за "
  205.         Serial.print(millis() - startTime);
  206.         Serial.println(" ms");  // "миллисекунд"
  207.       } // конец goodBMP
  208.     }
  209.   }
  210.  
  211.   bmpFile.close();
  212.   if(!goodBmp) Serial.println("BMP format not recognized.");  //  "Формат BMP не обнаружен"
  213. }
  214.  
  215. // Эти функции считывают из BMP-файла 16-битные и 32-битные данные.
  216. // Данные BMP-файла, как и у Arduino, хранятся по принципу
  217. // «от младшего к старшему». При портировании куда-либо этот порядок,
  218. // возможно, придется поменять.
  219.  
  220. uint16_t read16(File f) {
  221.   uint16_t result;
  222.   ((uint8_t *)&result)[0] = f.read(); // самый младший бит
  223.   ((uint8_t *)&result)[1] = f.read(); // самый старший бит
  224.   return result;
  225. }
  226.  
  227. uint32_t read32(File f) {
  228.   uint32_t result;
  229.   ((uint8_t *)&result)[0] = f.read(); // самый младший бит
  230.   ((uint8_t *)&result)[1] = f.read();
  231.   ((uint8_t *)&result)[2] = f.read();
  232.   ((uint8_t *)&result)[3] = f.read(); // самый старший бит
  233.   return result;
  234. }

См.также

Внешние ссылки

  1. github.com - spitftbitmap.ino