Плата расширения Arduino TFT

Arduino TFT - это плата расширения для Ардуино, которая содержит TFT-экран с подсветкой и разъем для карты памяти формата microSD. С помощью специальной библиотеки TFT на экран можно выводить текст, изображения или геометрические фигуры. 

Расположение внешних выводов платы расширения соответствует специальным разъемам на Arduino Esplora и Arduino Robot, что облегчает подключение экрана к этим устройствам. Однако, TFT-дисплей можно использовать с любой моделью Ардуино.

Библиотека TFT включается в состав среды разработки Ардуино. начиная с версии 1.0.5.

Библиотека

Библиотека Arduino TFT разработана на основе библиотек Adafruit GFX и Adafruit ST7735, и значительно расширяет их возможности. Библиотека GFX в основном содержит процедуры отрисовки графики, в том время, как ST7735 - функции для взаимодействия с TFT-экраном. Те дополнения библиотек, которые касаются Ардуино, спроектированы таким образом, чтобы максимально соответствовать API языка Processing.

Библиотека имеет обратную совместимость, что позволяет вам использовать в программах функции Adafruit (подробнее о них см. здесь).

Методы библиотеки TFT опираются на функции библиотеки SPI, поэтому во всех программах, работающих с TFT-экраном, должна быть объявлена библиотека SPI. Соответственно, при работе с SD-картой памяти - необходимо объявить библиотеку SD.

Организация экрана

По умолчанию экран имеет горизонтальную ориентацию, соответственно, его ширина - больше, чем высота. Верхняя часть экрана находится с той стороны платы, где указана надпись "SD CARD". При такой ориентации, разрешение экрана составляет 160 х 128 пикселей. 

Систему координат дисплея лучше всего представить в виде сетки, каждая ячейка которой является отдельным пикселем. Местоположение пикселя задается парой координат. Точка в левом верхнем углу экрана будет иметь координаты 0,0. Если эта точка сместится в верхний правый угол, то ее координаты будут равны 0, 159; в левый нижний угол - 127,0; в правый нижний - 127, 159.

Дисплей можно использовать и в вертикальном положении (также известном как "портретная ориентация"). Для этого достаточно вызвать функцию setRotation(0), после чего оси x и y поменяются местами. После вызова этого метода, функции screen.width() и screen.right() станут возвращать уже другие значения.

Цвета

Экран позволяет передавать цвет глубиной 16 бит. Красная и синяя составляющие цвета могут принимать 32 различных значения (разрядность 5 бит), а зеленая составляющая - 64 значения (разрядность 6 бит). Однако, с целью совместимости с другими программами, библиотека все равно работает с 8-битными значениями красного, зеленого и синего каналов (0 - 255), пропорционально масштабируя их в необходимый диапазон. 

Аппаратный и программный интерфейс SPI - что лучше?

Организовать работу с TFT-экраном можно двумя способами. Первый способ - использовать аппаратную шину SPI Ардуино, второй - вручную объявить расположение необходимых выводов. С точки зрения функциональности экрана, нет никакой разницы между первым и вторым способом. Однако скорость работы аппаратного интерфейса SPI значительно выше.

Если на TFT-модуле планируется использование SD-карты памяти, то взаимодействовать с модулем необходимо только через аппаратный интерфейс SPI. Он используется во всех примерах к данной библиотеке.

Подключение экрана

Подключение к Arduino Esplora

На лицевой стороне Arduino Esplora есть специальный разъем для подключения экрана. Вставьте экран Ардуино в этот разъем так, чтобы синяя надпись "SD Card" была расположена возде порта USB.

Подключение к другим платам Ардуино

Чтобы узнать, как подключать экран к другим моделям Ардуино, прочтите это руководство.

Пишем первую программу

Для начала работы с TFT-экраном, сперва попробуем написать программу, которая будет отрисовывать простую линию. После этого напишем программу, формирующую 2 цветных прямоугольника, пересекающие экран по горизонтали.

В примерах вначале будут приведены листинги программ для Arduino Uno, Leonardo и др. моделей. Листинги для Arduino Esplora будут приведены ниже.

Итак, в начале программы, объявим выводы Ардуино, которые будут использоваться для взаимодействия с экраном, импортируем необходимые библиотеки и создадим экземпляры основных классов библиотеки TFT:

#include <TFT.h> // библиотека для работы с TFT
#include <SPI.h>

#define CS   10
#define DC   9
#define RESET  8  

// объявление выводов для Arduino Leonardo
// #define CS   7
// #define DC   0
// #define RESET  1 

TFT myScreen = TFT(CS, DC, RESET);

В блоке setup() необходимо запустить библиотеку функцией begin() и очистить экран, установив черный цвет фона с помощью функции background().

void setup(){
  myScreen.begin();  
  myScreen.background(0,0,0);  // очищаем экран, заливая его черным цветом
  delay(1000);  // небольшая интригующая пауза
}

В блоке loop(), для отрисовки прямой линии на экране необходимо вызвать функцию line(). Функция line() принимает четыре аргумента: начальные координаты x и y, конечные координаты x и y. Чтобы нарисовать прямоугольник, необходимо вызвать функцию rect(), которая также принимает четыре параметра: координаты x и y левого верхнего угла, ширина и высота прямоугольника в пикселях. Между вызовами этих функций можно изменить цвет выводимой фигуры с помощью функций stroke() или fill(). Функция stroke() изменяет цвет линии или контура геометрической фигуры, а функция fill() - изменяет цвет заливки фигуры. После вызова функции noStroke() библиотека не будет отрисовывать границы выводимых фигур. Чтобы отменить действие этой функции, достаточно вызвать метод stroke().

void loop(){
  myScreen.stroke(255, 0, 0); // устанавливаем красный цвет кисти
  myScreen.line(0, 10, myScreen.width(), 10); // рисуем линию через весь экран
  delay(1000);

  myScreen.noStroke(); // не будем рисовать контуры вокруг будущего прямоугольника
  myScreen.fill(0,255,0); // устанавливаем зеленый цвет заливки
  myScreen.rect(0,20,myScreen.width(),10); //рисуем прямоугольник через экран
  delay(1000);

  myScreen.fill(0,0,255); // устанавливаем синий цвет заливки
  myScreen.stroke(255,255,255); // обводим прямоугольник белой линией
  myScreen.rect(0,45,myScreen.width(),45); // рисуем плоский прямоугольник
  delay(1000);

  myScreen.background(0,0,0); // очищаем экран перед тем, как все нарисовать снова
  delay(1000); 
}

Структура программы для Arduino Esplora практически ничем не отличается. В Arduino Esplora предусмотрен отдельный разъем для подключения TFT-экрана, поэтому выводы, взаимодействующие с ним, заданы аппаратно и не подлежат изменению. В программе в этом случае необходимо использовать специальный класс EsploraTFT для работы с экраном.

Именно поэтому в программе не нужно указывать выводы Ардуино, которые будут взаимодействовать с экраном; эта информация автоматически содержится внутри создаваемого объекта:

#include <TFT.h> // библиотека для работы с TFT

#include <SPI.h>
#include <Esplora.h>

void setup(){
  EsploraTFT.begin();  
  EsploraTFT.background(0,0,0);  // очищаем экран, заливая его черным цветом

  delay(1000);  // небольшая интригующая пауза
}

void loop(){
  EsploraTFT.stroke(255, 0, 0); // устанавливаем красный цвет кисти
  EsploraTFT.line(0, 10, EsploraLCD.width(), 10); // рисуем линию через весь экран
  delay(1000);

  EsploraTFT.noStroke(); // не будем рисовать контуры вокруг будущего прямоугольника
  EsploraTFT.fill(0,255,0); // устанавливаем зеленый цвет заливки
  EsploraTFT.rect(0,20,EsploraTFT.width(),20); //рисуем прямоугольник через экран
  delay(1000);

  EsploraTFT.fill(0,0,255); // устанавливаем синий цвет заливки
  EsploraTFT.stroke(255,255,255); // обводим прямоугольник белой линией
  EsploraTFT.rect(0,45,EsploraTFT.width(),50); // рисуем плоский прямоугольник
  delay(1000);

  EsploraTFT.background(0,0,0); // очищаем экран перед тем, как все нарисовать снова
  delay(1000); 
}

Перемещения по экрану

Иллюзия движения или анимация создается путем быстрого стирания и отрисовки изображения на экране. При использовании языка Processing на мощном компьютере, для очистки экрана и отрисовки картинки в новой позиции можно вызывать функцию background() перед каждым вызовом функции draw(). Однако производительность Arduino, по сравнению с настольным ПК, весьма ограничена, поэтому выполнение функции background() из библиотеки TFT занимает определенное время.

В условиях ограниченного быстродействия, для создания иллюзии движения лучше проверять положение объекта в цикле loop(). Если положение объекта изменилось, то необходимо закрасить его фоновым цветом, а затем перерисовать объект в новой позиции. Благодаря тому, что в данном случае обновляется не весь экран, а лишь некоторые его пиксели, процесс обновления картинки ускоряется и создается иллюзия движения.

В примере ниже показана программа перемещения точки по экрану. Структура программы похожа на пример, показанный в предыдущем разделе, за исключением нескольких переменных для хранения текущей и предыдущей позиций точки, а также переменных для хранения скорости и направления движения точки.

#include <TFT.h> // библиотека для работы с TFT
#include <SPI.h>

#define CS   10
#define DC   9
#define RESET  8  

// объявление выводов, работающих с экраном, для Arduino Leonardo
// #define CS   7
// #define DC   0
// #define RESET  1 

TFT myScreen = TFT(CS, DC, RESET);

// Начальная позиция точки - это середина экрана
int xPos = 80;
int yPos = 64;

// направление и скорость
int xDir = 1;
int yDir = 1;

// переменные для отслеживания позиции точки
int xPrev = xPos;
int yPrev = yPos;

void setup(){
  myScreen.begin();  
  myScreen.background(0,0,0); // очистка экрана
}

В цикле loop() мы вначале обновляем позицию точки, добавляя к переменным x и y величину направления движения. После этого проверяем, отличается ли текущее и предыдущее положение точки. Если отличается, то стираем предыдущую точку, закрашивая ее фоновым цветом, а затем рисуем новую точку в необходимой позиции. Если точка "долетает" до границы экрана - инвертируем направление движения.

void loop(){
  // обновляем позицию точки
  xPos = xPos + xDir;
  yPos = yPos + yDir;

  // проверяем, отличается ли текущее положение точки от предыдущего
  if(xPos != xPrev || yPos != yPrev){
    myScreen.stroke(0,0,0); // задаем черный цвет кисти
    myScreen.point(xPrev, yPrev); // цвет в предыдущей позиции
  }

  // рисуем точку в новой позиции
  myScreen.stroke(255,255,255);
  myScreen.point(xPos, yPos);

  // если x или позиция по x достигла границы экрана, то меняем направление на противоположное
  if(xPos >= 160 || xPos <= 0){
    xDir = xDir*-1;
  }
  if(yPos >= 128 || yPos <= 0){
    yDir = yDir*-1;
  }

  // обновляем предыдущую позицию точки
  xPrev=xPos;
  yPrev=yPos;

  // задержка в 33 мс означает, что экран обновляется 30 раз в секунду
  delay(33);

}

Версия этой программы для Arduino Esplora приведена ниже:

#include <TFT.h> // библиотека для работы с TFT
#include <SPI.h>
#include <Esplora.h>

// Начальная позиция точки - это середина экрана
int xPos = 80;
int yPos = 64;

// направление и скорость
int xDir = 1;
int yDir = 1;

// переменные для отслеживания позиции точки
int xPrev, yPrev;

void setup(){
  EsploraTFT.begin();  
  EsploraTFT.background(0,0,0);

void loop(){
  // обновляем позицию точки
  xPos = xPos + xDir;
  yPos = yPos + yDir;

  // проверяем, отличается ли текущее положение точки от предыдущего
  if(xPos != xPrev || yPos != yPrev){
    EsploraTFT.stroke(0,0,0); // задаем черный цвет кисти
    EsploraTFT.point(xPrev, yPrev); // цвет в предыдущей позиции
  }

  // рисуем точку в новой позиции
  EsploraTFT.stroke(255,255,255);
  EsploraTFT.point(xPos, yPos);

  // если x или позиция по x достигла границы экрана, то меняем направление на противоположное
  if(xPos >= 160 || xPos <= 0){
    xDir = xDir*-1;
  }
  if(yPos >= 128 || yPos <= 0){
    yDir = yDir*-1;
  }

  // обновляем предыдущую позицию точки
  xPrev=xPos;
  yPrev=yPos;

  // небольшая пауза
  delay(33);
}

 

Выводим текст

В библиотеке TFT содержится базовый шрифт для вывода текста на экран. По умолчанию, размер символов составляет 5х8 пикселей (5 - в ширину, 8 - в высоту). В библиотеке предусмотрена возможность изменения размера шрифта на 10x16, 15x24 или 20x32. Для получения дополнительной информации о шрифтах см. страницу Adafruit о работе с графическими примитивами.

Итак, в нижеследующем примере попробуем создать простой счетчик, который будет увеличиваться на единицу каждые полсекунды. Для этого, как и в предыдущих примерах, подключим необходимые библиотеки и объявим нужные переменные в блоке setup().

В этом же блоке отобразим на экране статический текст, который не будет меняться в процессе работы программы. С помощью функции setTextSize() можно увеличить размер шрифта, чтобы выделить на экране самые важные элементы. Динамический текст, который будет отображаться на экране, должен храниться в символьном массиве. Упросить работу с массивами позволяет класс String.

#include <TFT.h> // Библиотека для работы с TFT-экраном
#include <SPI.h>

#define CS   10
#define DC   9
#define RESET  8  

// объявление выводов, работающих с экраном, для Arduino Leonardo
// #define CS   7
// #define DC   0
// #define RESET  1 

TFT myScreen = TFT(CS, DC, RESET);

// переменная для хранения прошедшего времени
int counter = 0;
// массив символов для вывода времени на экран
char printout[4];

void setup(){
  myScreen.begin();  
  myScreen.background(0,0,0); // очистка экрана
  myScreen.stroke(255,0,255);
  // выводим статический текст
  myScreen.text("Running for",0,0);
  myScreen.text("seconds",0,30);  
  // увеличиваем размер шрифта для текста, выводимого в блоке loop() 
  myScreen.setTextSize(3);
}

В блоке loop() будем получать текущее время, прошедшее с момента запуска программы, и сохранять его в массив символов для последующего вывода в текстовом виде. На каждой итерации цикла будем стирать написанный ранее текст, чтобы выводимые цифры не накладывались друг на друга.

void loop(){
    // получаем текущее время, прошедшее с момента запуска программы
    counter = millis();
    // преобразовываем его в строку
    String elapsedTime = String(counter/1000);
    // добавляем в массив
    elapsedTime.toCharArray(printout,4);
    // выводим на экран и стираем
    myScreen.stroke(255,255,255);
    myScreen.text(printout,0,10);
    delay(1000);
    myScreen.stroke(0,0,0);
    myScreen.text(printout,0,10);
}

Тот же самый код для Arduino Esplora:

#include <TFT.h> // Библиотека для работы с TFT-экраном
#include <SPI.h>

// переменная для хранения прошедшего времени
int counter = 0;
// массив символов для вывода времени на экран
char printout[4];

void setup(){
  EsploraTFT.begin();  
  EsploraTFT.background(0,0,0); // очистка экрана
  EsploraTFT.stroke(255,0,255);
  // выводим статический текст
  EsploraTFT.text("Running for",0,0);
  EsploraTFT.text("seconds",0,30);   
  // увеличиваем размер шрифта для текста, выводимого в блоке loop() 
  EsploraTFT.setTextSize(3);
}

void loop(){
    // получаем текущее время, прошедшее с момента запуска программы
    counter = millis();
    // преобразовываем его в строку
    String elapsedTime = String(counter/1000);
    // добавляем в массив
    elapsedTime.toCharArray(printout,4);
    // выводим на экран и стираем
    EsploraTFT.stroke(255,255,255);
    EsploraTFT.text(printout,0,10);
    delay(1000);
    EsploraTFT.stroke(0,0,0);
    EsploraTFT.text(printout,0,10);
}

Выводим изображение из файла, находящегося на SD-карте памяти

Библиотека TFT позволяет считывать .bmp-файлы с SD-карты памяти и выводить их содержимое на экран. Причем отображаемые картинки могут не соответствовать разрешению TFT-экрана (160x128). Следует иметь ввиду, что Ардуино не может модифицировать изображения, поэтому все необходимые манипуляции с графическими файлами (такие, как масштабирование, обрезка и т.д.) необходимо сделать до их "заливки" на SD-карту.

В следующем примере показана работа с графическим файлом "arduino.bmp", расположенном в корне SD-карты памяти, и содержащим изображение размером 160x128 пикселей. В программе осуществляется считывание файла и вывод его на экран с помощью библиотеки TFT.

Помимо уже знакомых вам библиотек, в этом примере понадобится подключить еще одну библиотеку - SD. Также необходимо объявить вывод CS, связанный с разъемом SD-карты.

Класс PImage используется для загрузки изображения (этот класс может также использоваться для проверки формата графического файла на предмет его совместимости с библиотекой TFT).

После того, как файл будет прочитан, Ардуино выведет изображение в указанных вами координатах. В данном случае картинка будет выведена, начиная с левого верхнего угла экрана.

// подключаем необходимые библиотеки
#include <SPI.h>
#include <SD.h>
#include <TFT.h> // Библиотека для работы с TFT-экраном

// объявление выводов для Arduino Uno
#define SD_CS  11
#define LCD_CS 10
#define DC    9
#define RESET    8  

// объявление выводов для Leonardo
// #define SD_CS  8
// #define LCD_CS 7
// #define DC   0
// #define RESET  1

TFT myScreen = TFT(LCD_CS, DC, RESET);

// эта переменная описывает изображение, которое будет выводиться на экран
PImage image;

void setup() {
  // инициализируем последовательный интерфейс передачи данных
  Serial.begin(9600);
  while (!Serial) {
    // ожидаем готовности последовательного порта
    // - необходимо для Arduino Leonardo
  }

  // пробуем обратиться к SD-карте памяти
  Serial.print("Initializing SD card...");
  if (!SD.begin(SD_CS)) {
    Serial.println("failed!");
    return;
  }
  Serial.println("OK!");

  // инициализируем и очищаем GLCD-экран
  myScreen.begin();
  myScreen.background(255, 255, 255);

  // загружаем изображение с SD-карты
  image = myScreen.loadImage("arduino.bmp");

  // проверяем, корректно ли загружена картинка
  if (image.isValid() != true) {
    Serial.println("error while loading arduino.bmp");
  }

  //выводим изображение на экран
  myScreen.image(image, 0, 0);
}

void loop(){
// здесь ничего не делаем
}

Тот же самый код для Arduino Esplora: :

// подключаем необходимые библиотеки
#include <SPI.h>
#include <SD.h>
#include <TFT.h> // Библиотека для работы с TFT-экраном
#include <Esplora.h>

// Номер вывода для активации SD-карты
#define SD_CS    8

// эта переменная описывает изображение, которое будет выводиться на экран
PImage image;

void setup() {
  // инициализируем последовательный интерфейс передачи данных
  Serial.begin(9600);
  while (!Serial) {
    // ожидаем готовности последовательного порта
  }

  // пробуем обратиться к SD-карте памяти
  Serial.print("Initializing SD card...");
  if (!SD.begin(SD_CS)) {
    Serial.println("failed!");
    return;
  }
  Serial.println("OK!");

  // инициализируем и очищаем GLCD-экран
  EsploraTFT.begin();
  EsploraTFT.background(255, 255, 255);

  // загружаем изображение с SD-карты
  image = EsploraTFT.loadImage("arduino.bmp");

  // проверяем, корректно ли загружена картинка
  if (image.isValid() != true) {
    Serial.println("error while loading arduino.bmp");
  }

  //выводим изображение на экран
  EsploraTFT.image(image, 0, 0);
}

void loop(){
// здесь ничего не делаем
}

Что дальше?

Теперь, когда вы разобрались с принципами работы дисплея, загляните в справку по библиотеке TFT - там вы найдете информацию об API библиотеки, а также дополнительные примеры кода. Для получения дополнительной технической информации, см. страницу с описанием платы расширения Arduino TFT. Также не помешает посетить страницу с описанием графической библиотеки Adafruit - там можно найти дополнительную информацию о функциях, не освещенных в данном руководстве.