Из ценного, в Uno нет только исключений, т.к. этот процессор не имеет необходимых для этого аппаратных возможностей. В более продвинутых ардуинах (тех, что на ARM) вроде есть, но я сам не проверял.
Не знаю о чём вы дискутируете, но если просто заменить ширину высотой, а высоту шириной ничего с изображением не сделается кроме его усечения при 90 градусах (якобы поворота :). Авторы библиотеки схалтурили. В остальном как у всех правильно
чб картинка выводится поточечно.
В общем, если не материться как вы, а читать стоны и неудобства работы с ST7789 на форумах, то становится ясно рано или поздно, что у авторов этого ПО надо найти строки
writecommand(0x36);
writedata(0x00);
и заменить на
writecommand(0x36);
writedata(0x80);//ЗДЕСЬ ИСПРАВЛЕНО !!! БЫЛО 0x00
… а по человечески надо делать по подобию:
void Arduino_ST7789::setRotation(uint8_t m) {
writecommand(ST7789_MADCTL);
rotation = m % 4; // can't be higher than 3
switch (rotation) {
case 0:
writedata(ST7789_MADCTL_MX | ST7789_MADCTL_MY | ST7789_MADCTL_RGB);
_xstart = _colstart;
_ystart = 80;//_rowstart;
break;
case 1:
writedata(ST7789_MADCTL_MY | ST7789_MADCTL_MV | ST7789_MADCTL_RGB);
_ystart = _colstart;
_xstart = 80;//_rowstart;
break;
case 2:
writedata(ST7789_MADCTL_RGB);
_xstart = _colstart;
_ystart = _rowstart;
break;
case 3:
writedata(ST7789_MADCTL_MX | ST7789_MADCTL_MV | ST7789_MADCTL_RGB);
_ystart = _colstart;
_xstart = _rowstart;
break;
}
}
Видно, что у авторов отсутствуют две мысли напрочь.
void ERGFX::setRotation(uint8_t x) {
rotation = (x & 3);
switch(rotation) {
case 0:
case 2:
_width = WIDTH;
_height = HEIGHT;
break;
case 1:
case 3:
_width = HEIGHT;
_height = WIDTH;
break;
}
}
… да, забыл
даташиты зло, их читать не надо, они для некрасивых.
вот не надо, я тебе сразу сказал, открываешь библиотеку бодмера (TFT_eSPI) и видишь:
// This is the command sequence that rotates the ST7789 driver coordinate frame
writecommand(TFT_MADCTL);
rotation = m % 4;
switch (rotation) {
case 0: // Portrait
#ifdef CGRAM_OFFSET
if (_init_width == 135)
{
colstart = 52;
rowstart = 40;
}
else if(_init_height == 280)
{
colstart = 0;
rowstart = 20;
}
else if(_init_width == 172)
{
colstart = 34;
rowstart = 0;
}
else if(_init_width == 170)
{
colstart = 35;
rowstart = 0;
}
else
{
colstart = 0;
rowstart = 0;
}
#endif
writedata(TFT_MAD_COLOR_ORDER);
_width = _init_width;
_height = _init_height;
break;
case 1: // Landscape (Portrait + 90)
#ifdef CGRAM_OFFSET
if (_init_width == 135)
{
colstart = 40;
rowstart = 53;
}
else if(_init_height == 280)
{
colstart = 20;
rowstart = 0;
}
else if(_init_width == 172)
{
colstart = 0;
rowstart = 34;
}
else if(_init_width == 170)
{
colstart = 0;
rowstart = 35;
}
else
{
colstart = 0;
rowstart = 0;
}
#endif
writedata(TFT_MAD_MX | TFT_MAD_MV | TFT_MAD_COLOR_ORDER);
_width = _init_height;
_height = _init_width;
break;
case 2: // Inverter portrait
#ifdef CGRAM_OFFSET
if (_init_width == 135)
{
colstart = 53;
rowstart = 40;
}
else if(_init_height == 280)
{
colstart = 0;
rowstart = 20;
}
else if(_init_width == 172)
{
colstart = 34;
rowstart = 0;
}
else if(_init_width == 170)
{
colstart = 35;
rowstart = 0;
}
else
{
colstart = 0;
rowstart = 80;
}
#endif
writedata(TFT_MAD_MX | TFT_MAD_MY | TFT_MAD_COLOR_ORDER);
_width = _init_width;
_height = _init_height;
break;
case 3: // Inverted landscape
#ifdef CGRAM_OFFSET
if (_init_width == 135)
{
colstart = 40;
rowstart = 52;
}
else if(_init_height == 280)
{
colstart = 20;
rowstart = 0;
}
else if(_init_width == 172)
{
colstart = 0;
rowstart = 34;
}
else if(_init_width == 170)
{
colstart = 0;
rowstart = 35;
}
else
{
colstart = 80;
rowstart = 0;
}
#endif
writedata(TFT_MAD_MV | TFT_MAD_MY | TFT_MAD_COLOR_ORDER);
_width = _init_height;
_height = _init_width;
break;
}
Согласен. На досуге может попробую исправить ПО авторов по образу и подобию.
…Уточнил, надо всё же для поворота на 180 градусов, без отзеркаливания писать не 0х80, а 0хС0. Прикольно, это число получается как результат 0х40|0х80|0х00, типа логическое сложение трёх команд, не знаю что они значат, но догадываюсь
Конечно начинающий ни разу в эти дебри не войдёт. Особенно интересно - а чего не написать в библиотеке
writedata(ST7789_MADCTL_MX | ST7789_MADCTL_MY | ST7789_MADCTL_RGB| ST7789_MADCTL_RGB| ST7789_MADCTL_RGB| ST7789_MADCTL_RGB.....);
чтоб уже никто не догадался.
Пришли экранчики, общее число 6. К сожалению не заработал вариант коллективной работы. Авторы ПО явно накосячили и тут, экран не инициализируется с подключённым к GND выводом CS. Есть обходной путь, аппаратный, с 2 диодами и резистором на каждый экран, по выводу SDA, но пока лень делать. Пробую вариант игры на старой версии, для ST7735.

Затык явно в этом файле, кто знает подскажите-подправьте с CS и нулём.
Спойлер
/***************************************************
www.buydisplay.com
****************************************************/
#include "TFTM2.25-1.h"
#include <limits.h>
#include "pins_arduino.h"
#include "wiring_private.h"
#include <SPI.h>
#include "Arduino.h"
// Constructor when using software SPI. All output pins are configurable.
ST7789::ST7789(int8_t cs, int8_t dc, int8_t mosi,
int8_t sclk, int8_t rst) : ERGFX(ST7789_TFTWIDTH, ST7789_TFTHEIGHT) {
_cs = cs;
_dc = dc;
_mosi = mosi;
_sclk = sclk;
_rst = rst;
hwSPI = false;
}
// Constructor when using hardware SPI. Faster, but must use SPI pins
// specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.)
ST7789::ST7789(int8_t cs, int8_t dc, int8_t rst) : ERGFX(ST7789_TFTWIDTH, ST7789_TFTHEIGHT) {
_cs = cs;
_dc = dc;
_rst = rst;
hwSPI = true;
_mosi = _sclk = 0;
}
void ST7789::spiwrite(uint8_t c) {
//Serial.print("0x"); Serial.print(c, HEX); Serial.print(", ");
if (hwSPI) {
#if defined (__AVR__)
uint8_t backupSPCR = SPCR;
SPCR = mySPCR;
SPDR = c;
while(!(SPSR & _BV(SPIF)));
SPCR = backupSPCR;
#elif defined(ESP32)|| defined(TEENSYDUINO)
SPI.transfer(c);
#elif defined (__arm__)
SPI.setClockDivider(11); // 8-ish MHz (full! speed!)
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.transfer(c);
#endif
} else {
// Fast SPI bitbang swiped from LPD8806 library
for(uint8_t bit = 0x80; bit; bit >>= 1) {
if(c & bit) {
//digitalWrite(_mosi, HIGH);
*mosiport |= mosipinmask;
} else {
//digitalWrite(_mosi, LOW);
*mosiport &= ~mosipinmask;
}
//digitalWrite(_sclk, LOW);
*clkport &= ~clkpinmask;
//digitalWrite(_sclk, HIGH);
*clkport |= clkpinmask;
}
}
}
void ST7789::writecommand(uint8_t c) {
*dcport &= ~dcpinmask;
//digitalWrite(_dc, LOW);
//*clkport &= ~clkpinmask; // clkport is a NULL pointer when hwSPI==true
//digitalWrite(_sclk, LOW);
*csport &= ~cspinmask;
//digitalWrite(_cs, LOW);
spiwrite(c);
*csport |= cspinmask;
//digitalWrite(_cs, HIGH);
}
void ST7789::writedata(uint8_t c) {
*dcport |= dcpinmask;
//digitalWrite(_dc, HIGH);
//*clkport &= ~clkpinmask; // clkport is a NULL pointer when hwSPI==true
//digitalWrite(_sclk, LOW);
*csport &= ~cspinmask;
//digitalWrite(_cs, LOW);
spiwrite(c);
//digitalWrite(_cs, HIGH);
*csport |= cspinmask;
}
/*
// If the SPI library has transaction support, these functions
// establish settings and protect from interference from other
// libraries. Otherwise, they simply do nothing.
#ifdef SPI_HAS_TRANSACTION
static inline void spi_begin(void) __attribute__((always_inline));
static inline void spi_begin(void) {
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
}
static inline void spi_end(void) __attribute__((always_inline));
static inline void spi_end(void) {
SPI.endTransaction();
}
#else
#define spi_begin()
#define spi_end()
#endif
*/
void ST7789::begin(void) {
if (_rst > 0) {
pinMode(_rst, OUTPUT);
digitalWrite(_rst, LOW);
}
pinMode(_dc, OUTPUT);
pinMode(_cs, OUTPUT);
csport = portOutputRegister(digitalPinToPort(_cs));
cspinmask = digitalPinToBitMask(_cs);
dcport = portOutputRegister(digitalPinToPort(_dc));
dcpinmask = digitalPinToBitMask(_dc);
if(hwSPI) { // Using hardware SPI
#if defined (__AVR__)
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!)
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
mySPCR = SPCR;
#elif defined(ESP32)
SPI.begin();
SPI.beginTransaction(SPISettings(40000000, MSBFIRST, SPI_MODE0));
// SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!)
// SPI.setBitOrder(MSBFIRST);
// SPI.setDataMode(SPI_MODE0);
#elif defined(TEENSYDUINO)
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!)
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
#elif defined (__arm__)
SPI.begin();
SPI.setClockDivider(11); // 8-ish MHz (full! speed!)
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
#endif
} else {
pinMode(_sclk, OUTPUT);
pinMode(_mosi, OUTPUT);
clkport = portOutputRegister(digitalPinToPort(_sclk));
clkpinmask = digitalPinToBitMask(_sclk);
mosiport = portOutputRegister(digitalPinToPort(_mosi));
mosipinmask = digitalPinToBitMask(_mosi);
*clkport &= ~clkpinmask;
*mosiport &= ~mosipinmask;
}
// toggle RST low to reset
if (_rst > 0) {
digitalWrite(_rst, HIGH);
delay(5);
digitalWrite(_rst, LOW);
delay(20);
digitalWrite(_rst, HIGH);
delay(150);
}
if (hwSPI) SPI.begin();
writecommand(0xB2);
writedata(0x0C);
writedata(0x0C);
writedata(0x00);
writedata(0x33);
writedata(0x33);
writecommand(0xB0);
writedata(0x00);
writedata(0xE0);
writecommand(0x36);
// writedata(0x40|0x80|0x00);//ЗДЕСЬ ИСПРАВЛЕНО !!! БЫЛО 0x00
writedata(0xC0);//тоже самое (0x40|0x80|0x00)
writecommand(0x3A);
writedata(0x05);
writecommand(0xB7);
writedata(0x45);
writecommand(0xBB);
writedata(0x1D);
writecommand(0xC0);
writedata(0x2C);
writecommand(0xC2);
writedata(0x01);
writecommand(0xC3);
writedata(0x19);
writecommand(0xC4);
writedata(0x20);
writecommand(0xC6);
writedata(0x0F);
writecommand(0xD0);
writedata(0xA4);
writedata(0xA1);
writecommand(0xD6);
writedata(0xA1);
writecommand(0xE0);
writedata(0xD0);
writedata(0x10);
writedata(0x21);
writedata(0x14);
writedata(0x15);
writedata(0x2D);
writedata(0x41);
writedata(0x44);
writedata(0x4F);
writedata(0x28);
writedata(0x0E);
writedata(0x0C);
writedata(0x1D);
writedata(0x1F);
writecommand(0xE1);
writedata(0xD0);
writedata(0x0F);
writedata(0x1B);
writedata(0x0D);
writedata(0x0D);
writedata(0x26);
writedata(0x42);
writedata(0x54);
writedata(0x50);
writedata(0x3E);
writedata(0x1A);
writedata(0x18);
writedata(0x22);
writedata(0x25);
writecommand(0x11); //Exit Sleep
// if (hwSPI) spi_end();
delay(120);
// if (hwSPI) spi_begin();
writecommand(0x29); //Display on
// if (hwSPI) spi_end();
}
void ST7789::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1,
uint16_t y1) {
x0+=0x52; x1+=0x52; y0+=0x12; y1+=0x12;
writecommand(ST7789_CASET); // Column addr set
writedata(x0 >> 8);
writedata(x0); // XSTART
writedata(x1 >> 8);
writedata(x1); // XEND
writecommand(ST7789_PASET); // Row addr set
writedata(y0>>8);
writedata(y0); // YSTART
writedata(y1>>8);
writedata(y1); // YEND
writecommand(ST7789_RAMWR); // write to RAM
}
void ST7789::pushColor(uint16_t color) {
//if (hwSPI) spi_begin();
//digitalWrite(_dc, HIGH);
*dcport |= dcpinmask;
//digitalWrite(_cs, LOW);
*csport &= ~cspinmask;
spiwrite(color >> 8);
spiwrite(color);
*csport |= cspinmask;
//digitalWrite(_cs, HIGH);
// if (hwSPI) spi_end();
}
void ST7789::drawPixel(int16_t x, int16_t y, uint16_t color) {
if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
//if (hwSPI) spi_begin();
setAddrWindow(x,y,x+1,y+1);
//digitalWrite(_dc, HIGH);
*dcport |= dcpinmask;
//digitalWrite(_cs, LOW);
*csport &= ~cspinmask;
spiwrite(color >> 8);
spiwrite(color);
*csport |= cspinmask;
//digitalWrite(_cs, HIGH);
// if (hwSPI) spi_end();
}
void ST7789::drawFastVLine(int16_t x, int16_t y, int16_t h,
uint16_t color) {
// Rudimentary clipping
if((x >= _width) || (y >= _height)) return;
if((y+h-1) >= _height)
h = _height-y;
//if (hwSPI) spi_begin();
setAddrWindow(x, y, x, y+h-1);
uint8_t hi = color >> 8, lo = color;
*dcport |= dcpinmask;
//digitalWrite(_dc, HIGH);
*csport &= ~cspinmask;
//digitalWrite(_cs, LOW);
while (h--) {
spiwrite(hi);
spiwrite(lo);
}
*csport |= cspinmask;
//digitalWrite(_cs, HIGH);
// if (hwSPI) spi_end();
}
void ST7789::drawFastHLine(int16_t x, int16_t y, int16_t w,
uint16_t color) {
// Rudimentary clipping
if((x >= _width) || (y >= _height)) return;
if((x+w-1) >= _width) w = _width-x;
//if (hwSPI) spi_begin();
setAddrWindow(x, y, x+w-1, y);
uint8_t hi = color >> 8, lo = color;
*dcport |= dcpinmask;
*csport &= ~cspinmask;
//digitalWrite(_dc, HIGH);
//digitalWrite(_cs, LOW);
while (w--) {
spiwrite(hi);
spiwrite(lo);
}
*csport |= cspinmask;
//digitalWrite(_cs, HIGH);
//if (hwSPI) spi_end();
}
void ST7789::fillScreen(uint16_t color) {
fillRect(0, 0, _width, _height, color);
}
// fill a rectangle
void ST7789::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color) {
// rudimentary clipping (drawChar w/big text requires this)
if((x >= _width) || (y >= _height)) return;
if((x + w - 1) >= _width) w = _width - x;
if((y + h - 1) >= _height) h = _height - y;
// if (hwSPI) spi_begin();
setAddrWindow(x, y, x+w-1, y+h-1);
uint8_t hi = color >> 8, lo = color;
*dcport |= dcpinmask;
//digitalWrite(_dc, HIGH);
*csport &= ~cspinmask;
//digitalWrite(_cs, LOW);
for(y=h; y>0; y--) {
for(x=w; x>0; x--) {
spiwrite(hi);
spiwrite(lo);
}
}
//digitalWrite(_cs, HIGH);
*csport |= cspinmask;
//if (hwSPI) spi_end();
}
void ST7789::bmp16(uint16_t x, uint16_t y, const uint8_t *pBmp, uint16_t chWidth, uint16_t chHeight) {
uint16_t i, j;
uint16_t hwColor;
uint8_t hi , lo ;
// rudimentary clipping (drawChar w/big text requires this)
if((x >= _width) || (y >= _height)) return;
if((x + chWidth - 1) >= _width) chWidth = _width - x;
if((y + chHeight - 1) >= _height) chHeight = _height - y;
// if (hwSPI) SPI.begin();
setAddrWindow(x, y, x+chWidth-1, y+chHeight-1);
*dcport |= dcpinmask;
//digitalWrite(_dc, HIGH);
*csport &= ~cspinmask;
//digitalWrite(_cs, LOW);
for(j = 0; j < chHeight; j++) {
for(i = 0; i < chWidth; i++) {
hi= pgm_read_byte(pBmp++);lo= pgm_read_byte(pBmp++);
spiwrite(hi);
spiwrite(lo);
}
}
//digitalWrite(_cs, HIGH);
*csport |= cspinmask;
// if (hwSPI) SPI.end();
}
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t ST7789::color565(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
…ещё можно счёт времени выполнения задания добавить…это когда просто играть уже надоедает и тянет на статистику.
Хотите реальную “мозголомку” на эту игру?
Управление переводится на простое - кнопки лево-право для выбора колбы, кнопка активации для перехода (взять шарик - положить шарик).
А вот дисплеи… Либо дисплеи, либо светодиодные матрицы, но с нюансом. Подключение по последовательной шине шлейфом - стыкуется произвольное количество одинаковых колб. Каждый девайс (дисплей или матричный блок) - это колба (или две). МК разнюхивает подключенную конфигурацию сам аппаратно и играет в собранной конфигурации. Естественно, размер в пределах разумного - сколько позволяет максимальная память, тут не рвемся в бесконечность.
Энкодер с кнопкой можно попробовать (купить и попробовать ![]()
Но тогда нужен будет курсор положения.
Моргающая колба (все шары в ней) при выборе колбы, моргающий верхний шарик при позиционировании его в колбу для переноса.
А зачем CS к GND подключать? Приведенный ниже код управляет CS сам, ничего заранее подключать никуда не надо.
Для реализации многодисплейности есть два пути, программный и аппаратный. В библиотеках, как я понял, авторы не предусматривают её в принципе. Поэтому есть аппаратный ход, переключаем сами CS вне библиотеки (она думает, что работает с одним дисплеем). Но ей должно быть фиолетово куда подключен CS на пин или сразу к GND.
Пришла мысль попробовать джойстик с али. Он дубовый и может определять толком только 8 крайних положений своих.
Не стоит обощать. В хороших библиотеках есть управление CS. В приведенном Вами коде как раз именно так.
Нет, я пробовал для смеха вводить два дисплея в программу, она компилируется, но не работает. Именно это управление скорее всего и не даёт управлять CS снаружи. Для ST7735 код вроде очень похож, но там это работает с CS на GND, а тут нет. Видимо авторы не чуют какую то тонкость.
…пробовал дисплей библиотекой для ST7789 240х240 там инициализируется и кривое изображение (как и должно быть) выводит при соединении CS и GND. Значит это вопрос не аппаратный, а программный.
Спойлер
/***************************************************
This is a library for the Adafruit 1.8" SPI display.
This library works with the Adafruit 1.8" TFT Breakout w/SD card
----> http://www.adafruit.com/products/358
The 1.8" TFT shield
----> https://www.adafruit.com/product/802
The 1.44" TFT breakout
----> https://www.adafruit.com/product/2088
as well as Adafruit raw 1.8" TFT display
----> http://www.adafruit.com/products/618
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include "Adafruit_ST7735.h"
#include <limits.h>
#include "pins_arduino.h"
#include "wiring_private.h"
#include <SPI.h>
inline uint16_t swapcolor(uint16_t x)
{
return (x << 11) | (x & 0x07E0) | (x >> 11);
}
#if defined (SPI_HAS_TRANSACTION)
static SPISettings mySPISettings;
#elif defined (__AVR__) || defined(CORE_TEENSY)
static uint8_t SPCRbackup;
static uint8_t mySPCR;
#endif
// Constructor when using software SPI. All output pins are configurable.
Adafruit_ST7735::Adafruit_ST7735(int8_t cs, int8_t dc, int8_t sid, int8_t sclk, int8_t rst)
: Adafruit_GFX(ST7735_TFTWIDTH_128, ST7735_TFTHEIGHT_160)
{
_cs = cs;
_dc = dc;
_sid = sid;
_sclk = sclk;
_rst = rst;
hwSPI = false;
}
// Constructor when using hardware SPI. Faster, but must use SPI pins
// specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.)
Adafruit_ST7735::Adafruit_ST7735(int8_t cs, int8_t dc, int8_t rst)
: Adafruit_GFX(ST7735_TFTWIDTH_128, ST7735_TFTHEIGHT_160)
{
_cs = cs;
_dc = dc;
_rst = rst;
hwSPI = true;
_sid = _sclk = -1;
}
inline void Adafruit_ST7735::spiwrite(uint8_t c)
{
//Serial.println(c, HEX);
if (hwSPI)
{
#if defined (SPI_HAS_TRANSACTION)
SPI.transfer(c);
#elif defined (__AVR__) || defined(CORE_TEENSY)
SPCRbackup = SPCR;
SPCR = mySPCR;
SPI.transfer(c);
SPCR = SPCRbackup;
#elif defined (__arm__)
SPI.setClockDivider(21); //4MHz
SPI.setDataMode(SPI_MODE0);
SPI.transfer(c);
#endif
} else
{
// Fast SPI bitbang swiped from LPD8806 library
for(uint8_t bit = 0x80; bit; bit >>= 1)
{
#if defined(USE_FAST_IO)
if(c & bit) *dataport |= datapinmask;
else *dataport &= ~datapinmask;
*clkport |= clkpinmask;
*clkport &= ~clkpinmask;
#else
if(c & bit) digitalWrite(_sid, HIGH);
else digitalWrite(_sid, LOW);
digitalWrite(_sclk, HIGH);
digitalWrite(_sclk, LOW);
#endif
}
}
}
void Adafruit_ST7735::writecommand(uint8_t c)
{
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.beginTransaction(mySPISettings);
#endif
DC_LOW();
CS_LOW();
spiwrite(c);
CS_HIGH();
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.endTransaction();
#endif
}
void Adafruit_ST7735::writedata(uint8_t c)
{
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.beginTransaction(mySPISettings);
#endif
DC_HIGH();
CS_LOW();
spiwrite(c);
CS_HIGH();
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.endTransaction();
#endif
}
// Rather than a bazillion writecommand() and writedata() calls, screen
// initialization commands and arguments are organized in these tables
// stored in PROGMEM. The table may look bulky, but that's mostly the
// formatting -- storage-wise this is hundreds of bytes more compact
// than the equivalent code. Companion function follows.
#define DELAY 0x80
static const uint8_t PROGMEM
Bcmd[] =
{ // Initialization commands for 7735B screens
18, // 18 commands in list:
ST7735_SWRESET, DELAY, // 1: Software reset, no args, w/delay
50, // 50 ms delay
ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, no args, w/delay
255, // 255 = 500 ms delay
ST7735_COLMOD , 1+DELAY, // 3: Set color mode, 1 arg + delay:
0x05, // 16-bit color
10, // 10 ms delay
ST7735_FRMCTR1, 3+DELAY, // 4: Frame rate control, 3 args + delay:
0x00, // fastest refresh
0x06, // 6 lines front porch
0x03, // 3 lines back porch
10, // 10 ms delay
ST7735_MADCTL , 1 , // 5: Memory access ctrl (directions), 1 arg:
0x08, // Row addr/col addr, bottom to top refresh
ST7735_DISSET5, 2 , // 6: Display settings #5, 2 args, no delay:
0x15, // 1 clk cycle nonoverlap, 2 cycle gate
// rise, 3 cycle osc equalize
0x02, // Fix on VTL
ST7735_INVCTR , 1 , // 7: Display inversion control, 1 arg:
0x0, // Line inversion
ST7735_PWCTR1 , 2+DELAY, // 8: Power control, 2 args + delay:
0x02, // GVDD = 4.7V
0x70, // 1.0uA
10, // 10 ms delay
ST7735_PWCTR2 , 1 , // 9: Power control, 1 arg, no delay:
0x05, // VGH = 14.7V, VGL = -7.35V
ST7735_PWCTR3 , 2 , // 10: Power control, 2 args, no delay:
0x01, // Opamp current small
0x02, // Boost frequency
ST7735_VMCTR1 , 2+DELAY, // 11: Power control, 2 args + delay:
0x3C, // VCOMH = 4V
0x38, // VCOML = -1.1V
10, // 10 ms delay
ST7735_PWCTR6 , 2 , // 12: Power control, 2 args, no delay:
0x11, 0x15,
ST7735_GMCTRP1,16 , // 13: Magical unicorn dust, 16 args, no delay:
0x09, 0x16, 0x09, 0x20, // (seriously though, not sure what
0x21, 0x1B, 0x13, 0x19, // these config values represent)
0x17, 0x15, 0x1E, 0x2B,
0x04, 0x05, 0x02, 0x0E,
ST7735_GMCTRN1,16+DELAY, // 14: Sparkles and rainbows, 16 args + delay:
0x0B, 0x14, 0x08, 0x1E, // (ditto)
0x22, 0x1D, 0x18, 0x1E,
0x1B, 0x1A, 0x24, 0x2B,
0x06, 0x06, 0x02, 0x0F,
10, // 10 ms delay
ST7735_CASET , 4 , // 15: Column addr set, 4 args, no delay:
0x00, 0x02, // XSTART = 2
0x00, 0x81, // XEND = 129
ST7735_RASET , 4 , // 16: Row addr set, 4 args, no delay:
0x00, 0x02, // XSTART = 1
0x00, 0x81, // XEND = 160
ST7735_NORON , DELAY, // 17: Normal display on, no args, w/delay
10, // 10 ms delay
ST7735_DISPON , DELAY, // 18: Main screen turn on, no args, w/delay
255
}, // 255 = 500 ms delay
Rcmd1[] =
{ // Init for 7735R, part 1 (red or green tab)
15, // 15 commands in list:
ST7735_SWRESET, DELAY, // 1: Software reset, 0 args, w/delay
150, // 150 ms delay
ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, 0 args, w/delay
255, // 500 ms delay
ST7735_FRMCTR1, 3 , // 3: Frame rate ctrl - normal mode, 3 args:
0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
ST7735_FRMCTR2, 3 , // 4: Frame rate control - idle mode, 3 args:
0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
ST7735_FRMCTR3, 6 , // 5: Frame rate ctrl - partial mode, 6 args:
0x01, 0x2C, 0x2D, // Dot inversion mode
0x01, 0x2C, 0x2D, // Line inversion mode
ST7735_INVCTR , 1 , // 6: Display inversion ctrl, 1 arg, no delay:
0x07, // No inversion
ST7735_PWCTR1 , 3 , // 7: Power control, 3 args, no delay:
0xA2,
0x02, // -4.6V
0x84, // AUTO mode
ST7735_PWCTR2 , 1 , // 8: Power control, 1 arg, no delay:
0xC5, // VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD
ST7735_PWCTR3 , 2 , // 9: Power control, 2 args, no delay:
0x0A, // Opamp current small
0x00, // Boost frequency
ST7735_PWCTR4 , 2 , // 10: Power control, 2 args, no delay:
0x8A, // BCLK/2, Opamp current small & Medium low
0x2A,
ST7735_PWCTR5 , 2 , // 11: Power control, 2 args, no delay:
0x8A, 0xEE,
ST7735_VMCTR1 , 1 , // 12: Power control, 1 arg, no delay:
0x0E,
ST7735_INVOFF , 0 , // 13: Don't invert display, no args, no delay
ST7735_MADCTL , 1 , // 14: Memory access control (directions), 1 arg:
0xC8, // row addr/col addr, bottom to top refresh
ST7735_COLMOD , 1 , // 15: set color mode, 1 arg, no delay:
0x05
}, // 16-bit color
Rcmd2green[] =
{ // Init for 7735R, part 2 (green tab only)
2, // 2 commands in list:
ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
0x00, 0x02, // XSTART = 0
0x00, 0x7F+0x02, // XEND = 127
ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
0x00, 0x01, // XSTART = 0
0x00, 0x9F+0x01
}, // XEND = 159
Rcmd2red[] =
{ // Init for 7735R, part 2 (red tab only)
2, // 2 commands in list:
ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
0x00, 0x00, // XSTART = 0
0x00, 0x7F, // XEND = 127
ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
0x00, 0x00, // XSTART = 0
0x00, 0x9F
}, // XEND = 159
Rcmd2green144[] =
{ // Init for 7735R, part 2 (green 1.44 tab)
2, // 2 commands in list:
ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
0x00, 0x00, // XSTART = 0
0x00, 0x7F, // XEND = 127
ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
0x00, 0x00, // XSTART = 0
0x00, 0x7F
}, // XEND = 127
Rcmd2green160x80[] =
{ // Init for 7735R, part 2 (mini 160x80)
2, // 2 commands in list:
ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay:
0x00, 0x00, // XSTART = 0
0x00, 0x7F, // XEND = 79
ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay:
0x00, 0x00, // XSTART = 0
0x00, 0x9F
}, // XEND = 159
Rcmd3[] =
{ // Init for 7735R, part 3 (red or green tab)
4, // 4 commands in list:
ST7735_GMCTRP1, 16 , // 1: Magical unicorn dust, 16 args, no delay:
0x02, 0x1c, 0x07, 0x12,
0x37, 0x32, 0x29, 0x2d,
0x29, 0x25, 0x2B, 0x39,
0x00, 0x01, 0x03, 0x10,
ST7735_GMCTRN1, 16 , // 2: Sparkles and rainbows, 16 args, no delay:
0x03, 0x1d, 0x07, 0x06,
0x2E, 0x2C, 0x29, 0x2D,
0x2E, 0x2E, 0x37, 0x3F,
0x00, 0x00, 0x02, 0x10,
ST7735_NORON , DELAY, // 3: Normal display on, no args, w/delay
10, // 10 ms delay
ST7735_DISPON , DELAY, // 4: Main screen turn on, no args w/delay
100
}; // 100 ms delay
// Companion code to the above tables. Reads and issues
// a series of LCD commands stored in PROGMEM byte array.
void Adafruit_ST7735::commandList(const uint8_t *addr)
{
uint8_t numCommands, numArgs;
uint16_t ms;
numCommands = pgm_read_byte(addr++); // Number of commands to follow
while(numCommands--)
{ // For each command...
writecommand(pgm_read_byte(addr++)); // Read, issue command
numArgs = pgm_read_byte(addr++); // Number of args to follow
ms = numArgs & DELAY; // If hibit set, delay follows args
numArgs &= ~DELAY; // Mask out delay bit
while(numArgs--)
{ // For each argument...
writedata(pgm_read_byte(addr++)); // Read, issue argument
}
if(ms)
{
ms = pgm_read_byte(addr++); // Read post-command delay time (ms)
if(ms == 255) ms = 500; // If 255, delay for 500 ms
delay(ms);
}
}
}
// Initialization code common to both 'B' and 'R' type displays
void Adafruit_ST7735::commonInit(const uint8_t *cmdList)
{
ystart = xstart = colstart = rowstart = 0; // May be overridden in init func
pinMode(_dc, OUTPUT);
pinMode(_cs, OUTPUT);
#if defined(USE_FAST_IO)
csport = portOutputRegister(digitalPinToPort(_cs));
dcport = portOutputRegister(digitalPinToPort(_dc));
cspinmask = digitalPinToBitMask(_cs);
dcpinmask = digitalPinToBitMask(_dc);
#endif
if(hwSPI)
{ // Using hardware SPI
#if defined (SPI_HAS_TRANSACTION)
SPI.begin();
mySPISettings = SPISettings(8000000, MSBFIRST, SPI_MODE0);
#elif defined (__AVR__) || defined(CORE_TEENSY)
SPCRbackup = SPCR;
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV4);
SPI.setDataMode(SPI_MODE0);
mySPCR = SPCR; // save our preferred state
//Serial.print("mySPCR = 0x"); Serial.println(SPCR, HEX);
SPCR = SPCRbackup; // then restore
#elif defined (__SAM3X8E__)
SPI.begin();
SPI.setClockDivider(21); //4MHz
SPI.setDataMode(SPI_MODE0);
#endif
} else
{
pinMode(_sclk, OUTPUT);
pinMode(_sid , OUTPUT);
digitalWrite(_sclk, LOW);
digitalWrite(_sid, LOW);
#if defined(USE_FAST_IO)
clkport = portOutputRegister(digitalPinToPort(_sclk));
dataport = portOutputRegister(digitalPinToPort(_sid));
clkpinmask = digitalPinToBitMask(_sclk);
datapinmask = digitalPinToBitMask(_sid);
#endif
}
// toggle RST low to reset; CS low so it'll listen to us
CS_LOW();
if (_rst != -1)
{
pinMode(_rst, OUTPUT);
digitalWrite(_rst, HIGH);
delay(500);
digitalWrite(_rst, LOW);
delay(500);
digitalWrite(_rst, HIGH);
delay(500);
}
if(cmdList) commandList(cmdList);
}
// Initialization for ST7735B screens
void Adafruit_ST7735::initB(void)
{
commonInit(Bcmd);
setRotation(0);
}
// Initialization for ST7735R screens (green or red tabs)
void Adafruit_ST7735::initR(uint8_t options)
{
commonInit(Rcmd1);
if(options == INITR_GREENTAB)
{
commandList(Rcmd2green);
colstart = 2;
rowstart = 1;
} else if(options == INITR_144GREENTAB)
{
_height = ST7735_TFTHEIGHT_128;
_width = ST7735_TFTWIDTH_128;
commandList(Rcmd2green144);
colstart = 2;
rowstart = 3;
} else if(options == INITR_MINI160x80)
{
_height = ST7735_TFTHEIGHT_160;
_width = ST7735_TFTWIDTH_80;
commandList(Rcmd2green160x80);
colstart = 24;
rowstart = 0;
} else
{
// colstart, rowstart left at default '0' values
commandList(Rcmd2red);
}
commandList(Rcmd3);
// if black, change MADCTL color filter
if ((options == INITR_BLACKTAB) || (options == INITR_MINI160x80))
{
writecommand(ST7735_MADCTL);
writedata(0xC0);
}
tabcolor = options;
setRotation(0);
}
void Adafruit_ST7735::setAddrWindow(uint8_t x0, uint8_t y0, uint8_t x1,
uint8_t y1)
{
writecommand(ST7735_CASET); // Column addr set
writedata(0x00);
writedata(x0+xstart); // XSTART
writedata(0x00);
writedata(x1+xstart); // XEND
writecommand(ST7735_RASET); // Row addr set
writedata(0x00);
writedata(y0+ystart); // YSTART
writedata(0x00);
writedata(y1+ystart); // YEND
writecommand(ST7735_RAMWR); // write to RAM
}
void Adafruit_ST7735::pushColor(uint16_t color)
{
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.beginTransaction(mySPISettings);
#endif
DC_HIGH();
CS_LOW();
spiwrite(color >> 8);
spiwrite(color);
CS_HIGH();
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.endTransaction();
#endif
}
void Adafruit_ST7735::drawPixel(int16_t x, int16_t y, uint16_t color)
{
if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
setAddrWindow(x,y,x+1,y+1);
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.beginTransaction(mySPISettings);
#endif
DC_HIGH();
CS_LOW();
spiwrite(color >> 8);
spiwrite(color);
CS_HIGH();
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.endTransaction();
#endif
}
void Adafruit_ST7735::drawFastVLine(int16_t x, int16_t y, int16_t h,
uint16_t color)
{
// Rudimentary clipping
if((x >= _width) || (y >= _height)) return;
if((y+h-1) >= _height) h = _height-y;
setAddrWindow(x, y, x, y+h-1);
uint8_t hi = color >> 8, lo = color;
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.beginTransaction(mySPISettings);
#endif
DC_HIGH();
CS_LOW();
while (h--)
{
spiwrite(hi);
spiwrite(lo);
}
CS_HIGH();
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.endTransaction();
#endif
}
void Adafruit_ST7735::drawFastHLine(int16_t x, int16_t y, int16_t w,
uint16_t color)
{
// Rudimentary clipping
if((x >= _width) || (y >= _height)) return;
if((x+w-1) >= _width) w = _width-x;
setAddrWindow(x, y, x+w-1, y);
uint8_t hi = color >> 8, lo = color;
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.beginTransaction(mySPISettings);
#endif
DC_HIGH();
CS_LOW();
while(w--)
{
spiwrite(hi);
spiwrite(lo);
}
CS_HIGH();
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.endTransaction();
#endif
}
void Adafruit_ST7735::fillScreen(uint16_t color)
{
fillRect(0, 0, _width, _height, color);
}
// fill a rectangle
void Adafruit_ST7735::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color)
{
// rudimentary clipping (drawChar w/big text requires this)
if((x >= _width) || (y >= _height)) return;
if((x + w - 1) >= _width) w = _width - x;
if((y + h - 1) >= _height) h = _height - y;
setAddrWindow(x, y, x+w-1, y+h-1);
uint8_t hi = color >> 8, lo = color;
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.beginTransaction(mySPISettings);
#endif
DC_HIGH();
CS_LOW();
for(y=h; y>0; y--)
{
for(x=w; x>0; x--)
{
spiwrite(hi);
spiwrite(lo);
}
}
CS_HIGH();
#if defined (SPI_HAS_TRANSACTION)
if (hwSPI) SPI.endTransaction();
#endif
}
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t Adafruit_ST7735::Color565(uint8_t r, uint8_t g, uint8_t b)
{
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
#define MADCTL_MY 0x80
#define MADCTL_MX 0x40
#define MADCTL_MV 0x20
#define MADCTL_ML 0x10
#define MADCTL_RGB 0x00
#define MADCTL_BGR 0x08
#define MADCTL_MH 0x04
// Поворот экрана
void Adafruit_ST7735::setRotation(uint8_t m)
{
writecommand(ST7735_MADCTL);
rotation = m % 4; // can't be higher than 3 => Не больше 3-х, т.е.: 0 - 0°, 1 - 90°, 2 - 180°, 3 - 270° и т.д.
switch (rotation)
{
case 0:
if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80))
{
writedata(MADCTL_MX | MADCTL_MY | MADCTL_RGB);
} else
{
writedata(MADCTL_MX | MADCTL_MY | MADCTL_BGR);
}
if (tabcolor == INITR_144GREENTAB)
{
_height = ST7735_TFTHEIGHT_128;
_width = ST7735_TFTWIDTH_128;
} else if (tabcolor == INITR_MINI160x80)
{
_height = ST7735_TFTHEIGHT_160;
_width = ST7735_TFTWIDTH_80;
} else
{
_height = ST7735_TFTHEIGHT_160;
_width = ST7735_TFTWIDTH_128;
}
xstart = colstart;
ystart = rowstart;
break;
case 1:
if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80))
{
writedata(MADCTL_MY | MADCTL_MV | MADCTL_RGB);
} else
{
writedata(MADCTL_MY | MADCTL_MV | MADCTL_BGR);
}
if (tabcolor == INITR_144GREENTAB)
{
_width = ST7735_TFTHEIGHT_128;
_height = ST7735_TFTWIDTH_128;
} else if (tabcolor == INITR_MINI160x80)
{
_width = ST7735_TFTHEIGHT_160;
_height = ST7735_TFTWIDTH_80;
} else
{
_width = ST7735_TFTHEIGHT_160;
_height = ST7735_TFTWIDTH_128;
}
ystart = colstart;
xstart = rowstart;
break;
case 2:
if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80))
{
writedata(MADCTL_RGB);
} else
{
writedata(MADCTL_BGR);
}
if (tabcolor == INITR_144GREENTAB)
{
_height = ST7735_TFTHEIGHT_128;
_width = ST7735_TFTWIDTH_128;
} else if (tabcolor == INITR_MINI160x80)
{
_height = ST7735_TFTHEIGHT_160;
_width = ST7735_TFTWIDTH_80;
} else
{
_height = ST7735_TFTHEIGHT_160;
_width = ST7735_TFTWIDTH_128;
}
xstart = colstart;
ystart = rowstart;
break;
case 3:
if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80))
{
writedata(MADCTL_MX | MADCTL_MV | MADCTL_RGB);
} else
{
writedata(MADCTL_MX | MADCTL_MV | MADCTL_BGR);
}
if (tabcolor == INITR_144GREENTAB)
{
_width = ST7735_TFTHEIGHT_128;
_height = ST7735_TFTWIDTH_128;
} else if (tabcolor == INITR_MINI160x80)
{
_width = ST7735_TFTHEIGHT_160;
_height = ST7735_TFTWIDTH_80;
} else
{
_width = ST7735_TFTHEIGHT_160;
_height = ST7735_TFTWIDTH_128;
}
ystart = colstart;
xstart = rowstart;
break;
}
}
void Adafruit_ST7735::invertDisplay(boolean i)
{
writecommand(i ? ST7735_INVON : ST7735_INVOFF);
}
/******** low level bit twiddling **********/
inline void Adafruit_ST7735::CS_HIGH(void)
{
#if defined(USE_FAST_IO)
*csport |= cspinmask;
#else
digitalWrite(_cs, HIGH);
#endif
}
inline void Adafruit_ST7735::CS_LOW(void)
{
#if defined(USE_FAST_IO)
*csport &= ~cspinmask;
#else
digitalWrite(_cs, LOW);
#endif
}
inline void Adafruit_ST7735::DC_HIGH(void)
{
#if defined(USE_FAST_IO)
*dcport |= dcpinmask;
#else
digitalWrite(_dc, HIGH);
#endif
}
inline void Adafruit_ST7735::DC_LOW(void)
{
#if defined(USE_FAST_IO)
*dcport &= ~dcpinmask;
#else
digitalWrite(_dc, LOW);
#endif
}
////////// stuff not actively being used, but kept for posterity
/*
uint8_t Adafruit_ST7735::spiread(void) {
uint8_t r = 0;
if (_sid > 0) {
r = shiftIn(_sid, _sclk, MSBFIRST);
} else {
//SID_DDR &= ~_BV(SID);
//int8_t i;
//for (i=7; i>=0; i--) {
// SCLK_PORT &= ~_BV(SCLK);
// r <<= 1;
// r |= (SID_PIN >> SID) & 0x1;
// SCLK_PORT |= _BV(SCLK);
//}
//SID_DDR |= _BV(SID);
}
return r;
}
void Adafruit_ST7735::dummyclock(void) {
if (_sid > 0) {
digitalWrite(_sclk, LOW);
digitalWrite(_sclk, HIGH);
} else {
// SCLK_PORT &= ~_BV(SCLK);
//SCLK_PORT |= _BV(SCLK);
}
}
uint8_t Adafruit_ST7735::readdata(void) {
*portOutputRegister(rsport) |= rspin;
*portOutputRegister(csport) &= ~ cspin;
uint8_t r = spiread();
*portOutputRegister(csport) |= cspin;
return r;
}
uint8_t Adafruit_ST7735::readcommand8(uint8_t c) {
digitalWrite(_rs, LOW);
*portOutputRegister(csport) &= ~ cspin;
spiwrite(c);
digitalWrite(_rs, HIGH);
pinMode(_sid, INPUT); // input!
digitalWrite(_sid, LOW); // low
spiread();
uint8_t r = spiread();
*portOutputRegister(csport) |= cspin;
pinMode(_sid, OUTPUT); // back to output
return r;
}
uint16_t Adafruit_ST7735::readcommand16(uint8_t c) {
digitalWrite(_rs, LOW);
if (_cs)
digitalWrite(_cs, LOW);
spiwrite(c);
pinMode(_sid, INPUT); // input!
uint16_t r = spiread();
r <<= 8;
r |= spiread();
if (_cs)
digitalWrite(_cs, HIGH);
pinMode(_sid, OUTPUT); // back to output
return r;
}
uint32_t Adafruit_ST7735::readcommand32(uint8_t c) {
digitalWrite(_rs, LOW);
if (_cs)
digitalWrite(_cs, LOW);
spiwrite(c);
pinMode(_sid, INPUT); // input!
dummyclock();
dummyclock();
uint32_t r = spiread();
r <<= 8;
r |= spiread();
r <<= 8;
r |= spiread();
r <<= 8;
r |= spiread();
if (_cs)
digitalWrite(_cs, HIGH);
pinMode(_sid, OUTPUT); // back to output
return r;
}
*/
// image must be uint16_t[h][w]
Попробовал простенький энкодер первый раз. На удивление работает без внешних резисторов, конденсаторов, библиотек, без подавления дребезга, без прерываний и прочей атрибутики. Пример первый брал тут:
https://www.joyta.ru/13065-kak-rabotaet-povorotnyj-enkoder-vzaimodejstvie-s-arduino/
Но управление становится медленным, в сравнении с кнопками, тратится много на движение курсора 1. Зато печатать нужно только ручку 3.
…джойстиком наверное будет также медленно.
… можно попробовать голосом через приложение, но это уже баловство.
Всё таки сделал ещё одну попытку, взял адафрутовскую библиотеку. Конечно при CS на GND тоже не заработало, зато пошла бегущая строка, но с косяком библиотеки. Видимо из-за отсутствия инициализации варианта размера 76Х284.

void loop() {
for(int i=300;i>-500;i=i-2){
tft.setCursor(i, 20);
tft.print(utf8rus("Фамилия Имя Отчество "));
delay(50);
}
}
Не ясно, откуда кривая строка-дублёр.
…тем не менее аппаратная добавка вывела на многодисплейность, при сохранности концепции кода управления как с ST7735.
Работает на наших, на советских диодах.

Это не дублер, а перенос строки




