Arduino:Примеры/shieldtest

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

Перевод: Максим Кузьмин (Cubewriter) Контакты:</br>* Skype: cubewriter</br>* E-mail: cubewriter@gmail.com</br>* Максим Кузьмин на freelance.ru
Проверка/Оформление/Редактирование: Мякишев Е.А.


Перемещение картинки на 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 }

См.также

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