Arduino:Примеры/soft spitftbitmap
Перейти к навигации
Перейти к поиску
Поддержать проект | Содержание | Знакомство с Arduino | Продукты | Основы | Справочник языка Arduino | Примеры | Библиотеки | Хакинг | Изменения | Сравнение языков Arduino и Processing |
Перевод: Максим Кузьмин (Cubewriter) Контакты:</br>* Skype: cubewriter</br>* E-mail: cubewriter@gmail.com</br>* Максим Кузьмин на freelance.ru
Проверка/Оформление/Редактирование: Мякишев Е.А.
Вывод изображения на 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 }
См.также
Внешние ссылки