Arduino:Примеры/shieldtest
Перейти к навигации
Перейти к поиску
Поддержать проект | Содержание | Знакомство с Arduino | Продукты | Основы | Справочник языка Arduino | Примеры | Библиотеки | Хакинг | Изменения | Сравнение языков Arduino и Processing |
Перевод: Максим Кузьмин (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 }
См.также
Внешние ссылки