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

Arduino:Примеры/shieldtest

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

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

Контакты:

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


Перемещение картинки на TFT-дисплее (при помощи джойстика)[1]

Это скетч для библиотеки ST7735, который при помощи платы Arduino и джойстика позволяет двигать картинку на TFT-дисплее. Для скетча потребуется вот этот TFT-модуль, оснащенный джойстиком (он представляет собой небольшую черную кнопку) и TFT-дисплеем.

Код

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

См.также

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

  1. github.com - shieldtest.ino