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

Arduino:Примеры/soft spitftbitmap

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

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

Контакты:

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


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

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

Код

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

См.также

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

  1. github.com - soft_spitftbitmap.ino