Введите текст заголовка

Страница на этапе разработки
В данном уроке мы с Вами будем использовать плату Raspberry Pi Pico RP2040 c 32МБ.

Подключим к ней TFT экран на драйвере R61520:
У нас уже был урок по подключению данного экрана: Урок №10 по STM32
Мы полностью его скопируем, переопределим ножки и немного изменим некоторые функции.
Что на каких ножках мы сразу пропишем в программе, писать будем среде программирования Arduino IDE.

#define RST 17
#define CS  18
#define RS  19
#define WR  20
#define RD  21
#define D2  15
#define D3  14
#define D4  13
#define D5  12
#define D6  11
#define D7  10
#define D0  7
#define D1  6

#define HL3 26
#define HL2 27
#define HL1 28

#define SWRESET 0x01 // программный сброс
#define DISPOFF 0x28 // выключение дисплея
#define DISPON 0x29 // включение дисплея
#define CASET 0x2A // выбор первого и последнего пикселя по оси X
#define PASET 0x2B // выбор первого и последнего пикселя по оси Y
#define RAMWR 0x2C // запись пикселя в дисплей
#define PWCTR1 0xC0 // настройка питания
#define SLPIN 0x10 // перевод дисплея в режим сна
#define SLPOUT 0x11 // пробуждение
#define PIXFMT 0x3A // установка формата пикселя
#define MADCTL 0x36 // настройки порядка вывода пикселей на экран
#define TRANSFER 0xB0 // Управление режимом интерфейса
#define WBCONTROL 0x55 // настройка параметров управления яркостью

// reset
#define RESET_IDLE        digitalWrite(RST, HIGH);
#define RESET_ACTIVE      digitalWrite(RST, LOW);
// chip select
#define CS_IDLE           digitalWrite(CS, HIGH);
#define CS_ACTIVE         digitalWrite(CS, LOW);
// command/data
#define RS_IDLE           digitalWrite(RS, HIGH);
#define RS_ACTIVE         digitalWrite(RS, LOW);
//read
#define RD_IDLE           digitalWrite(RD, HIGH);
#define RD_ACTIVE         digitalWrite(RD, LOW);
//write
#define WR_IDLE           digitalWrite(WR, HIGH);
#define WR_ACTIVE         digitalWrite(WR, LOW);
//write strobe
#define WR_STROBE          {WR_ACTIVE; WR_IDLE;}

#defineswap(a,b) {int16_t t=a;a=b;b=t;}

void TFT1520_SendCommand(uint16_t index);
void TFT1520_Reset();
void TFT1520_init();
void pushData(unsigned char data);
void TFT1520_SendCommand(uint16_t index);
void TFT1520_SendData(uint16_t data);
void TFT1520_InvertDisplay(uint8_t i);
void TFT1520_SetRotation(uint8_t r);

void TFT1520_SetAddrWindow(uint16_t x, uint16_t y, uint16_t x1, uint16_t y1);
void TFT1520_SetAddrWindow(uint16_t x, uint16_t y, uint16_t x1, uint16_t y1);
void TFT9341_DrawLine(uint16_t color, uint16_t x1, uint16_t y1,uint16_t x2, uint16_t y2);
void TFT9341_DrawRect(uint16_t color, uint16_t x1, uint16_t y1,uint16_t x2, uint16_t y2);
void vivod_char(uint8_t g,uint8_t x, uint8_t y, uint16_t color, uint16_t fon);

uint16_t x = 0;
uint16_t y = 0;

void TFT1520_Reset() {
     CS_IDLE ; RD_IDLE ; WR_IDLE ;
     RESET_IDLE ;
     delay(1);
     RESET_ACTIVE ;
     delay(1);
     RESET_IDLE ;
     delay(1);
}

void TFT1520_init() {
    TFT1520_Reset();
    TFT1520_SendCommand(SWRESET);
    delay(3);
    TFT1520_SendCommand(DISPOFF);
    TFT1520_SendCommand(TRANSFER );
    TFT1520_SendData(0x00); //40 ?
    TFT1520_SendCommand(PWCTR1);
    TFT1520_SendData(0x0A);
    TFT1520_SendCommand(SLPOUT);
    delay(2);
    TFT1520_SendCommand(DISPON);
    TFT1520_SendCommand(PIXFMT);
    TFT1520_SendData(WBCONTROL);
    TFT1520_SetRotation(0);
    TFT1520_InvertDisplay(0);
}

// Формирование команды на порту
void pushData(unsigned char data) {
   // LCD_IOP->ODR = (int)((int)data << 8);
    int t=0;
    int fdata=data;
    if((fdata&0x01)==1){
      digitalWrite(D0, HIGH);
    }else{
      digitalWrite(D0, LOW);
    }
    fdata=data>>1;
     if((fdata&0x01)==1){
      digitalWrite(D1, HIGH);
    }else{
      digitalWrite(D1, LOW);
    }
     fdata=data>>2;
     if((fdata&0x01)==1){
      digitalWrite(D2, HIGH);
    }else{
      digitalWrite(D2, LOW);
    }
    fdata=data>>3;
     if((fdata&0x01)==1){
      digitalWrite(D3, HIGH);
    }else{
      digitalWrite(D3, LOW);
    }
     fdata=data>>4;
     if((fdata&0x01)==1){
      digitalWrite(D4, HIGH);
    }else{
      digitalWrite(D4, LOW);
    }
     fdata=data>>5;
     if((fdata&0x01)==1){
      digitalWrite(D5, HIGH);
    }else{
      digitalWrite(D5, LOW);
    }
     fdata=data>>6;
     if((fdata&0x01)==1){
      digitalWrite(D6, HIGH);
    }else{
      digitalWrite(D6, LOW);
    }
     fdata=data>>7;
     if((fdata&0x01)==1){
      digitalWrite(D7, HIGH);
    }else{
      digitalWrite(D7, LOW);
    }
    WR_STROBE;
}

void TFT1520_SendCommand(uint16_t index) {
   CS_ACTIVE;
   RS_ACTIVE;
   pushData(index);
   CS_IDLE;
}

void TFT1520_SendData(uint16_t data) {
   CS_ACTIVE;
   RS_IDLE;
   pushData(data);
   CS_IDLE;
}

void TFT1520_InvertDisplay(uint8_t i) {
   TFT1520_SendCommand(i ? 0x21 : 0x20);
}

uint16_t X_SIZE = 0;
uint16_t Y_SIZE = 0;
void TFT1520_SetRotation(uint8_t r) {
    TFT1520_SendCommand(0x36);
    switch(r) {
          case 0:
                     TFT1520_SendData(0x48);
                     X_SIZE = 240;
                     Y_SIZE = 320;
                     break;
         case 1:
                    TFT1520_SendData(0x28);
                    X_SIZE = 320;
                    Y_SIZE = 240;
                    break;
        case 2:
                   TFT1520_SendData(0x88);
                   X_SIZE = 240;
                   Y_SIZE = 320;
                   break;
        case 3:
                  TFT1520_SendData(0xE8);
                  X_SIZE = 320;
                  Y_SIZE = 240;
                 break;
     }
}

void TFT1520_SetAddrWindow(uint16_t x, uint16_t y, uint16_t x1, uint16_t y1) {
   TFT1520_SendCommand(0x2A);
   TFT1520_SendData(x >> 8);
   TFT1520_SendData(x);
   TFT1520_SendData(x1 >> 8);
   TFT1520_SendData(x1);
   TFT1520_SendCommand(0x2B);
   TFT1520_SendData(y >> 8);
    TFT1520_SendData(y);
    TFT1520_SendData(y1 >> 8);
    TFT1520_SendData(y1);
}

void TFT1520_DrawPixel(uint16_t x, uint16_t y, uint16_t color) {
   if((x<0)||(y<0)||(x>=X_SIZE)||(y>=Y_SIZE))
       return;
   TFT1520_SetAddrWindow(x, y, x, y);
   TFT1520_SendCommand(0x2C);
   TFT1520_SendData(color >> 8);
   TFT1520_SendData(color & 0xFF);
}

void TFT9341_DrawLine(uint16_t color, uint16_t x1, uint16_t y1,uint16_t x2, uint16_t y2){
  int steep = abs(y2-y1)>abs(x2-x1);
  if (steep){
      swap(x1,y1);
      swap(x2,y2);
   }
 if(x1>x2){
    swap(x1,x2);
    swap(y1,y2);
  }
  int dx,dy;
  dx=x2-x1;
  dy=abs(y2-y1);
  int err=dx/2;
  int ystep;
  if(y1<y2) ystep = 1;
     else ystep = -1;
 for (;x1<=x2;x1++){
              if (steep) TFT1520_DrawPixel(y1,x1,color);
                   else TFT1520_DrawPixel(x1,y1,color);
    err-=dy;
    if (err<0){
            y1 += ystep;
            err+=dx;
       }
   }
}

void TFT9341_DrawRect(uint16_t color, uint16_t x1, uint16_t y1,uint16_t x2, uint16_t y2){
   TFT9341_DrawLine(color,x1,y1,x2,y1);
   TFT9341_DrawLine(color,x2,y1,x2,y2);
   TFT9341_DrawLine(color,x1,y1,x1,y2);
   TFT9341_DrawLine(color,x1,y2,x2,y2);
}

void TFT9341_DrawCircle(uint16_t x0, uint16_t y0, int r, uint16_t color){
  int f = 1-r;
  int ddF_x=1;
  int ddF_y=-2*r;
  int x = 0;
  int y = r;
  TFT1520_DrawPixel(x0,y0+r,color);
  TFT1520_DrawPixel(x0,y0-r,color);
  TFT1520_DrawPixel(x0+r,y0,color);
  TFT1520_DrawPixel(x0-r,y0,color);
  while (x<y){
      if (f>=0){
           y—;
           ddF_y+=2;
          f+=ddF_y;
     }
 x++;
ddF_x+=2;
f+=ddF_x;
TFT1520_DrawPixel(x0+x,y0+y,color);
TFT1520_DrawPixel(x0-x,y0+y,color);
TFT1520_DrawPixel(x0+x,y0-y,color);
TFT1520_DrawPixel(x0-x,y0-y,color);
TFT1520_DrawPixel(x0+y,y0+x,color);
TFT1520_DrawPixel(x0-y,y0+x,color);
TFT1520_DrawPixel(x0+y,y0-x,color);
TFT1520_DrawPixel(x0-y,y0-x,color);
}
}
 
void setup() {
    TFT1520_init();
    delay(1000);
    TFT1520_SetRotation(1);
    for(x = 0; x < 320; x++) {
      for(y = 0; y < 240; y++) {
          TFT1520_DrawPixel(x, y, 0x0000);
        }
   }
   for(x = 0; x < 320; x++) {
         for(y = 0; y < 240; y++) {
             // заполнение дисплея белым по пиксельно
            TFT1520_DrawPixel(x, y, 0xFFFF);
            }
     }
    for(x = 0; x < 320; x++) {
          for(y = 0; y < 240; y++) {
         // заполнение дисплея чёрным по пиксельно
         TFT1520_DrawPixel(x, y, 0x0000);
       }
   }
   for(x = 0; x < 320; x++) {
       for(y = 0; y < 240; y++) {
       // заполнение дисплея чёрным по пиксельно
       TFT1520_DrawPixel(x, y, 0x00FF);
        }
   }
  for(x = 0; x < 320; x++) {
       for(y = 0; y < 240; y++) {
       // заполнение дисплея чёрным по пиксельно
       TFT1520_DrawPixel(x, y, 0xFF00);
      }
   }
}

void loop() {
 
delay(2000);  
}

Так как мы уже разбирали работу данного экрана в уроке по STM32, я думаю в понимании данного кода проблем не должно быть. Единственно, что в код немного добавлены строчки которые мы будем использовать дальше (кнопка и светодиоды).
Вкратце по подключению: питание TFT экрана я беру прям с платы (контакт 3,3V), на саму плату подаем 5В (контакт Vin). 5В формирую через DC/DC,  тем самым обеспечиваю себе стандартный уровень питания на входе 12В. 
Залив данный программный код, Вы должны увидеть как плавно заливается экран по очереди одним цветом.
Теперь немного улучшим наш код добавим еще несколько функций:

 

static inline void TFT1520_WriteColor16(uint16_t color){
pushData((uint8_t)(color >> 8));
pushData((uint8_t)(color & 0xFF));
}

void TFT1520_FillRect(uint16_t x, uint16_t y,uint16_t w, uint16_t h,uint16_t color){
if (w == 0 || h == 0)
return;

if (x >= X_SIZE || y >= Y_SIZE)
return;

if ((uint32_t)x + w > X_SIZE)
w = X_SIZE — x;

if ((uint32_t)y + h > Y_SIZE)
h = Y_SIZE — y;

TFT1520_SetAddrWindow(x, y, x + w — 1, y + h — 1);

TFT1520_SendCommand(RAMWR);

CS_ACTIVE;
RS_IDLE;

uint32_t pixels = (uint32_t)w * h;

while (pixels—)
{
TFT1520_WriteColor16(color);
}

CS_IDLE;
}

void TFT1520_FillScreen(uint16_t color)
{
TFT1520_FillRect(0, 0, X_SIZE, Y_SIZE, color);
}

А в основном коде напишем:
TFT1520_FillScreen(0xFFFF); // белый экран
TFT1520_FillScreen(0x0000); //чёрный
delay(500);
TFT1520_FillScreen(0xF800); // красный
delay(500);
TFT1520_FillScreen(0x07E0); // зелёный
delay(500);
TFT1520_FillScreen(0x001F); // синий
delay(500);

Теперь добавляем файл R61520_Text.ino, где прописываем  вывод текста на экран:

#include <Arduino.h>


/*
8×16 bitmap font for RP2040 / R61520.
Bit 7 is the left pixel, bit 0 is the right pixel.
Supported:
ASCII U+0020..U+007E
Cyrillic А..Я U+0410..U+042F
Cyrillic а..я U+0430..U+044F
Ё U+0401, ё U+0451
Degree sign ° U+00B0
*/
static const uint8_t FONT8X16_ASCII[95][16] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0020 ‘ ‘
{ 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00 }, // U+0021 ‘!’
{ 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0022 ‘»‘
{ 0x00, 0x00, 0x00, 0x00, 0x14, 0x24, 0x7E, 0x28, 0x28, 0xFC, 0x48, 0x50, 0x00, 0x00, 0x00, 0x00 }, // U+0023 ‘#’
{ 0x00, 0x00, 0x00, 0x10, 0x38, 0x54, 0x50, 0x70, 0x1C, 0x14, 0x54, 0x38, 0x10, 0x10, 0x00, 0x00 }, // U+0024 ‘$’
{ 0x00, 0x00, 0x00, 0x60, 0x90, 0x90, 0x64, 0x18, 0x6C, 0x12, 0x12, 0x0C, 0x00, 0x00, 0x00, 0x00 }, // U+0025 ‘%’
{ 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x30, 0x30, 0x4A, 0x4E, 0x64, 0x3A, 0x00, 0x00, 0x00, 0x00 }, // U+0026 ‘&’
{ 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0027 ‘\»
{ 0x00, 0x00, 0x0C, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x0C, 0x00, 0x00, 0x00 }, // U+0028 ‘(‘
{ 0x00, 0x00, 0x30, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x30, 0x00, 0x00, 0x00 }, // U+0029 ‘)’
{ 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+002A ‘*’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xFE, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00 }, // U+002B ‘+’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00 }, // U+002C ‘,’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+002D ‘-‘
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00 }, // U+002E ‘.’
{ 0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x00, 0x00, 0x00 }, // U+002F ‘/’
{ 0x00, 0x00, 0x00, 0x3C, 0x24, 0x42, 0x42, 0x4A, 0x42, 0x42, 0x24, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0030 ‘0’
{ 0x00, 0x00, 0x00, 0x70, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7C, 0x00, 0x00, 0x00, 0x00 }, // U+0031 ‘1’
{ 0x00, 0x00, 0x00, 0x3C, 0x42, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x00, 0x00, 0x00, 0x00 }, // U+0032 ‘2’
{ 0x00, 0x00, 0x00, 0x3C, 0x42, 0x02, 0x02, 0x1C, 0x02, 0x02, 0x42, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0033 ‘3’
{ 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x14, 0x34, 0x24, 0x44, 0x7E, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 }, // U+0034 ‘4’
{ 0x00, 0x00, 0x00, 0x7C, 0x40, 0x40, 0x7C, 0x06, 0x02, 0x02, 0x46, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0035 ‘5’
{ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x40, 0x5C, 0x66, 0x42, 0x42, 0x26, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0036 ‘6’
{ 0x00, 0x00, 0x00, 0x7E, 0x06, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00 }, // U+0037 ‘7’
{ 0x00, 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x3C, 0x42, 0x42, 0x42, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0038 ‘8’
{ 0x00, 0x00, 0x00, 0x3C, 0x64, 0x42, 0x42, 0x46, 0x3A, 0x02, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00 }, // U+0039 ‘9’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00 }, // U+003A ‘:’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00 }, // U+003B ‘;’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1C, 0x60, 0x60, 0x1C, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+003C ‘<‘
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+003D ‘=’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x38, 0x06, 0x06, 0x38, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+003E ‘>’
{ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x0C, 0x18, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00 }, // U+003F ‘?’
{ 0x00, 0x00, 0x00, 0x00, 0x1C, 0x26, 0x42, 0x4E, 0x52, 0x52, 0x4E, 0x60, 0x20, 0x1C, 0x00, 0x00 }, // U+0040 ‘@’
{ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24, 0x3C, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00 }, // U+0041 ‘A’
{ 0x00, 0x00, 0x00, 0x7C, 0x42, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x42, 0x7C, 0x00, 0x00, 0x00, 0x00 }, // U+0042 ‘B’
{ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x40, 0x40, 0x40, 0x40, 0x40, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00 }, // U+0043 ‘C’
{ 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00 }, // U+0044 ‘D’
{ 0x00, 0x00, 0x00, 0x7E, 0x40, 0x40, 0x40, 0x7E, 0x40, 0x40, 0x40, 0x7E, 0x00, 0x00, 0x00, 0x00 }, // U+0045 ‘E’
{ 0x00, 0x00, 0x00, 0x7E, 0x40, 0x40, 0x40, 0x7E, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00 }, // U+0046 ‘F’
{ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x40, 0x40, 0x46, 0x42, 0x42, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00 }, // U+0047 ‘G’
{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00 }, // U+0048 ‘H’
{ 0x00, 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7C, 0x00, 0x00, 0x00, 0x00 }, // U+0049 ‘I’
{ 0x00, 0x00, 0x00, 0x1C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00 }, // U+004A ‘J’
{ 0x00, 0x00, 0x00, 0x42, 0x44, 0x48, 0x50, 0x70, 0x48, 0x4C, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00 }, // U+004B ‘K’
{ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00, 0x00, 0x00, 0x00 }, // U+004C ‘L’
{ 0x00, 0x00, 0x00, 0x42, 0x66, 0x66, 0x5A, 0x5A, 0x5A, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00 }, // U+004D ‘M’
{ 0x00, 0x00, 0x00, 0x62, 0x62, 0x52, 0x52, 0x5A, 0x4A, 0x4A, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00 }, // U+004E ‘N’
{ 0x00, 0x00, 0x00, 0x3C, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+004F ‘O’
{ 0x00, 0x00, 0x00, 0x7C, 0x42, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00 }, // U+0050 ‘P’
{ 0x00, 0x00, 0x00, 0x3C, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x26, 0x3C, 0x04, 0x04, 0x00, 0x00 }, // U+0051 ‘Q’
{ 0x00, 0x00, 0x00, 0x7C, 0x42, 0x42, 0x42, 0x7C, 0x44, 0x42, 0x42, 0x41, 0x00, 0x00, 0x00, 0x00 }, // U+0052 ‘R’
{ 0x00, 0x00, 0x00, 0x3C, 0x42, 0x40, 0x60, 0x3C, 0x02, 0x02, 0x42, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0053 ‘S’
{ 0x00, 0x00, 0x00, 0xFE, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00 }, // U+0054 ‘T’
{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0055 ‘U’
{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x24, 0x24, 0x24, 0x24, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }, // U+0056 ‘V’
{ 0x00, 0x00, 0x00, 0x82, 0x92, 0x92, 0xAA, 0xAA, 0xAA, 0x6C, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00 }, // U+0057 ‘W’
{ 0x00, 0x00, 0x00, 0x42, 0x24, 0x24, 0x18, 0x18, 0x18, 0x24, 0x24, 0x42, 0x00, 0x00, 0x00, 0x00 }, // U+0058 ‘X’
{ 0x00, 0x00, 0x00, 0x82, 0x44, 0x28, 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00 }, // U+0059 ‘Y’
{ 0x00, 0x00, 0x00, 0x7E, 0x06, 0x04, 0x08, 0x18, 0x10, 0x20, 0x60, 0x7E, 0x00, 0x00, 0x00, 0x00 }, // U+005A ‘Z’
{ 0x00, 0x00, 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x18, 0x00, 0x00, 0x00 }, // U+005B ‘[‘
{ 0x00, 0x00, 0x00, 0x40, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x00, 0x00, 0x00 }, // U+005C ‘\\’
{ 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x30, 0x00, 0x00, 0x00 }, // U+005D ‘]’
{ 0x00, 0x00, 0x00, 0x30, 0x48, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+005E ‘^’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00 }, // U+005F ‘_’
{ 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0060 ‘`’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x04, 0x3C, 0x44, 0x44, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0061 ‘a’
{ 0x00, 0x00, 0x40, 0x40, 0x40, 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00 }, // U+0062 ‘b’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x64, 0x40, 0x40, 0x40, 0x60, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0063 ‘c’
{ 0x00, 0x00, 0x04, 0x04, 0x04, 0x3C, 0x44, 0x44, 0x44, 0x44, 0x44, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0064 ‘d’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x64, 0x44, 0x7C, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00 }, // U+0065 ‘e’
{ 0x00, 0x00, 0x0C, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00 }, // U+0066 ‘f’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x24, 0x18, 0x00 }, // U+0067 ‘g’
{ 0x00, 0x00, 0x40, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00 }, // U+0068 ‘h’
{ 0x00, 0x00, 0x10, 0x00, 0x00, 0x70, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7C, 0x00, 0x00, 0x00, 0x00 }, // U+0069 ‘i’
{ 0x00, 0x00, 0x08, 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x30, 0x00 }, // U+006A ‘j’
{ 0x00, 0x00, 0x40, 0x40, 0x40, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, 0x00 }, // U+006B ‘k’
{ 0x00, 0x00, 0x70, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0C, 0x00, 0x00, 0x00, 0x00 }, // U+006C ‘l’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00, 0x00 }, // U+006D ‘m’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00 }, // U+006E ‘n’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00 }, // U+006F ‘o’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00 }, // U+0070 ‘p’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x04, 0x00 }, // U+0071 ‘q’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00 }, // U+0072 ‘r’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00 }, // U+0073 ‘s’
{ 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1C, 0x00, 0x00, 0x00, 0x00 }, // U+0074 ‘t’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0075 ‘u’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x28, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00 }, // U+0076 ‘v’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x82, 0x54, 0x54, 0x6C, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00 }, // U+0077 ‘w’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x28, 0x10, 0x28, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00 }, // U+0078 ‘x’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x28, 0x28, 0x28, 0x30, 0x10, 0x10, 0x20, 0x60, 0x00 }, // U+0079 ‘y’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, 0x00, 0x00, 0x00 }, // U+007A ‘z’
{ 0x00, 0x00, 0x1C, 0x10, 0x10, 0x10, 0x10, 0x60, 0x10, 0x10, 0x10, 0x10, 0x1C, 0x00, 0x00, 0x00 }, // U+007B ‘{‘
{ 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00 }, // U+007C ‘|’
{ 0x00, 0x00, 0x70, 0x10, 0x10, 0x10, 0x10, 0x0C, 0x10, 0x10, 0x10, 0x10, 0x70, 0x00, 0x00, 0x00 }, // U+007D ‘}’
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+007E ‘~’
};

static const uint8_t FONT8X16_CYR_UPPER[32][16] = {
{ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24, 0x3C, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00 }, // U+0410 А
{ 0x00, 0x00, 0x00, 0x7E, 0x40, 0x40, 0x40, 0x7C, 0x42, 0x42, 0x42, 0x7C, 0x00, 0x00, 0x00, 0x00 }, // U+0411 Б
{ 0x00, 0x00, 0x00, 0x7C, 0x42, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x42, 0x7C, 0x00, 0x00, 0x00, 0x00 }, // U+0412 В
{ 0x00, 0x00, 0x00, 0x7E, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00 }, // U+0413 Г
{ 0x00, 0x00, 0x00, 0x7C, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xFE, 0x82, 0x82, 0x00, 0x00 }, // U+0414 Д
{ 0x00, 0x00, 0x00, 0x7E, 0x40, 0x40, 0x40, 0x7E, 0x40, 0x40, 0x40, 0x7E, 0x00, 0x00, 0x00, 0x00 }, // U+0415 Е
{ 0x00, 0x00, 0x00, 0xD6, 0x54, 0x54, 0x38, 0x38, 0x54, 0x54, 0x54, 0x92, 0x00, 0x00, 0x00, 0x00 }, // U+0416 Ж
{ 0x00, 0x00, 0x00, 0x3C, 0x42, 0x02, 0x02, 0x1C, 0x02, 0x02, 0x42, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0417 З
{ 0x00, 0x00, 0x00, 0x46, 0x46, 0x4A, 0x4A, 0x5A, 0x52, 0x52, 0x62, 0x62, 0x00, 0x00, 0x00, 0x00 }, // U+0418 И
{ 0x24, 0x18, 0x00, 0x46, 0x46, 0x4A, 0x4A, 0x5A, 0x52, 0x52, 0x62, 0x62, 0x00, 0x00, 0x00, 0x00 }, // U+0419 Й
{ 0x00, 0x00, 0x00, 0x42, 0x44, 0x48, 0x50, 0x70, 0x48, 0x4C, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00 }, // U+041A К
{ 0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x62, 0xC2, 0x00, 0x00, 0x00, 0x00 }, // U+041B Л
{ 0x00, 0x00, 0x00, 0x42, 0x66, 0x66, 0x5A, 0x5A, 0x5A, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00 }, // U+041C М
{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00 }, // U+041D Н
{ 0x00, 0x00, 0x00, 0x3C, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+041E О
{ 0x00, 0x00, 0x00, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00 }, // U+041F П
{ 0x00, 0x00, 0x00, 0x7C, 0x42, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00 }, // U+0420 Р
{ 0x00, 0x00, 0x00, 0x1C, 0x22, 0x40, 0x40, 0x40, 0x40, 0x40, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00 }, // U+0421 С
{ 0x00, 0x00, 0x00, 0xFE, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00 }, // U+0422 Т
{ 0x00, 0x00, 0x00, 0x42, 0x64, 0x24, 0x24, 0x28, 0x18, 0x10, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00 }, // U+0423 У
{ 0x00, 0x00, 0x00, 0x10, 0x7C, 0xD6, 0x92, 0x92, 0x92, 0xD6, 0x7C, 0x10, 0x00, 0x00, 0x00, 0x00 }, // U+0424 Ф
{ 0x00, 0x00, 0x00, 0x42, 0x24, 0x24, 0x18, 0x18, 0x18, 0x24, 0x24, 0x42, 0x00, 0x00, 0x00, 0x00 }, // U+0425 Х
{ 0x00, 0x00, 0x00, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0xFE, 0x02, 0x02, 0x00, 0x00 }, // U+0426 Ц
{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3E, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00 }, // U+0427 Ч
{ 0x00, 0x00, 0x00, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x7C, 0x00, 0x00, 0x00, 0x00 }, // U+0428 Ш
{ 0x00, 0x00, 0x00, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xFC, 0x04, 0x04, 0x00, 0x00 }, // U+0429 Щ
{ 0x00, 0x00, 0x00, 0xE0, 0x20, 0x20, 0x3C, 0x26, 0x22, 0x22, 0x26, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+042A Ъ
{ 0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0xF2, 0x9A, 0x8A, 0x8A, 0x9A, 0xF2, 0x00, 0x00, 0x00, 0x00 }, // U+042B Ы
{ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x42, 0x42, 0x42, 0x7C, 0x00, 0x00, 0x00, 0x00 }, // U+042C Ь
{ 0x00, 0x00, 0x00, 0x38, 0x44, 0x02, 0x02, 0x3E, 0x02, 0x02, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00 }, // U+042D Э
{ 0x00, 0x00, 0x00, 0x4C, 0x52, 0x52, 0x52, 0x72, 0x52, 0x52, 0x52, 0x4C, 0x00, 0x00, 0x00, 0x00 }, // U+042E Ю
{ 0x00, 0x00, 0x00, 0x7C, 0x84, 0x84, 0x84, 0x7C, 0x44, 0x44, 0x44, 0x84, 0x00, 0x00, 0x00, 0x00 }, // U+042F Я
};

static const uint8_t FONT8X16_CYR_LOWER[32][16] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x04, 0x3C, 0x44, 0x44, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0430 а
{ 0x00, 0x00, 0x18, 0x20, 0x40, 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00 }, // U+0431 б
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00 }, // U+0432 в
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00 }, // U+0433 г
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x24, 0x24, 0x24, 0x24, 0x24, 0x7E, 0x42, 0x42, 0x00, 0x00 }, // U+0434 д
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x64, 0x44, 0x7C, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00 }, // U+0435 е
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x38, 0x7C, 0x54, 0x54, 0x92, 0x00, 0x00, 0x00, 0x00 }, // U+0436 ж
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00 }, // U+0437 з
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x4C, 0x4C, 0x54, 0x54, 0x64, 0x44, 0x00, 0x00, 0x00, 0x00 }, // U+0438 и
{ 0x00, 0x00, 0x24, 0x18, 0x00, 0x44, 0x4C, 0x4C, 0x54, 0x54, 0x64, 0x44, 0x00, 0x00, 0x00, 0x00 }, // U+0439 й
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, 0x00 }, // U+043A к
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x44, 0x44, 0x44, 0x44, 0x44, 0x84, 0x00, 0x00, 0x00, 0x00 }, // U+043B л
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x66, 0x66, 0x5A, 0x5A, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00 }, // U+043C м
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00 }, // U+043D н
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00 }, // U+043E о
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00 }, // U+043F п
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00 }, // U+0440 р
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x64, 0x40, 0x40, 0x40, 0x60, 0x3C, 0x00, 0x00, 0x00, 0x00 }, // U+0441 с
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00 }, // U+0442 т
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x28, 0x28, 0x28, 0x30, 0x10, 0x10, 0x20, 0x60, 0x00 }, // U+0443 у
{ 0x00, 0x00, 0x10, 0x10, 0x10, 0x38, 0x54, 0x54, 0x54, 0x54, 0x54, 0x38, 0x10, 0x10, 0x10, 0x00 }, // U+0444 ф
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x28, 0x10, 0x28, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00 }, // U+0445 х
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x7E, 0x02, 0x02, 0x00, 0x00 }, // U+0446 ц
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00 }, // U+0447 ч
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x7C, 0x00, 0x00, 0x00, 0x00 }, // U+0448 ш
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x7E, 0x02, 0x02, 0x00, 0x00 }, // U+0449 щ
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x40, 0x40, 0x7C, 0x42, 0x42, 0x7C, 0x00, 0x00, 0x00, 0x00 }, // U+044A ъ
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x72, 0x4A, 0x4A, 0x72, 0x00, 0x00, 0x00, 0x00 }, // U+044B ы
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x78, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00 }, // U+044C ь
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x4C, 0x04, 0x3C, 0x04, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00 }, // U+044D э
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x52, 0x52, 0x72, 0x52, 0x52, 0x4C, 0x00, 0x00, 0x00, 0x00 }, // U+044E ю
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x3C, 0x24, 0x24, 0x44, 0x00, 0x00, 0x00, 0x00 }, // U+044F я
};

static const uint8_t FONT8X16_YO_UPPER[16] = { 0x00, 0x28, 0x00, 0x7E, 0x40, 0x40, 0x40, 0x7E, 0x40, 0x40, 0x40, 0x7E, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t FONT8X16_YO_LOWER[16] = { 0x00, 0x00, 0x00, 0x28, 0x00, 0x38, 0x64, 0x44, 0x7C, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t FONT8X16_DEGREE[16] = { 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };


static inline const uint8_t *Font8x16_GetGlyph(uint32_t codepoint)
{
if (codepoint >= 0x20 && codepoint <= 0x7E)
return FONT8X16_ASCII[codepoint — 0x20];

if (codepoint == 0x0401)
return FONT8X16_YO_UPPER;

if (codepoint >= 0x0410 && codepoint <= 0x042F)
return FONT8X16_CYR_UPPER[codepoint — 0x0410];

if (codepoint >= 0x0430 && codepoint <= 0x044F)
return FONT8X16_CYR_LOWER[codepoint — 0x0430];

if (codepoint == 0x0451)
return FONT8X16_YO_LOWER;

if (codepoint == 0x00B0)
return FONT8X16_DEGREE;

return FONT8X16_ASCII[‘?’ — 0x20];
}

 

// ————————————————————
// Чтение одного символа UTF-8
// ————————————————————
static uint32_t TFT1520_UTF8_Next(const char **text)
{
const uint8_t *s = (const uint8_t *)(*text);

if (*s == 0)
return 0;

// ASCII
if (s[0] < 0x80)
{
uint32_t c = s[0];
*text += 1;
return c;
}

// UTF-8: 2 байта
if ((s[0] & 0xE0) == 0xC0 && s[1] != 0)
{
uint32_t c =
((uint32_t)(s[0] & 0x1F) << 6) |
((uint32_t)(s[1] & 0x3F));

*text += 2;
return c;
}

// UTF-8: 3 байта
if ((s[0] & 0xF0) == 0xE0 &&
s[1] != 0 &&
s[2] != 0)
{
uint32_t c =
((uint32_t)(s[0] & 0x0F) << 12) |
((uint32_t)(s[1] & 0x3F) << 6) |
((uint32_t)(s[2] & 0x3F));

*text += 3;
return c;
}

// Некорректный символ
*text += 1;
return ‘?’;
}


// ————————————————————
// Передача одного RGB565 цвета
// ————————————————————
static inline void TFT1520_TextWriteColor(uint16_t color)
{
pushData((uint8_t)(color >> 8));
pushData((uint8_t)(color & 0xFF));
}


// ————————————————————
// Вывод одного символа
//
// x, y — координаты
// codepoint — Unicode код символа
// color — цвет символа RGB565
// background — цвет фона RGB565
// scale — масштаб: 1 = 8×16, 2 = 16×32 и т.д.
// ————————————————————
void TFT1520_DrawChar(uint16_t x,
uint16_t y,
uint32_t codepoint,
uint16_t color,
uint16_t background,
uint8_t scale)
{
if (scale == 0)
scale = 1;

uint16_t charWidth = 8U * scale;
uint16_t charHeight = 16U * scale;

if (x >= X_SIZE || y >= Y_SIZE)
return;

if ((uint32_t)x + charWidth > X_SIZE)
return;

if ((uint32_t)y + charHeight > Y_SIZE)
return;

const uint8_t *glyph = Font8x16_GetGlyph(codepoint);

TFT1520_SetAddrWindow(
x,
y,
x + charWidth — 1,
y + charHeight — 1
);

TFT1520_SendCommand(RAMWR);

CS_ACTIVE;
RS_IDLE;

for (uint8_t row = 0; row < 16; row++)
{
uint8_t bits = glyph[row];

// Вертикальное увеличение строки
for (uint8_t sy = 0; sy < scale; sy++)
{
for (uint8_t col = 0; col < 8; col++)
{
uint16_t pixelColor;

if (bits & (0x80 >> col))
pixelColor = color;
else
pixelColor = background;

// Горизонтальное увеличение пикселя
for (uint8_t sx = 0; sx < scale; sx++)
{
TFT1520_TextWriteColor(pixelColor);
}
}
}
}

CS_IDLE;
}


// ————————————————————
// Вывод UTF-8 строки
//
// Пример:
// TFT1520_Print(10, 20,
// u8″Температура: 25°С»,
// 0xFFFF,
// 0x0000,
// 1);
// ————————————————————
void TFT1520_Print(uint16_t x0,
uint16_t y0,
const char *text,
uint16_t color,
uint16_t background,
uint8_t scale)
{
if (scale == 0)
scale = 1;

uint16_t x = x0;
uint16_t y = y0;

const uint16_t charWidth = 8U * scale;
const uint16_t charHeight = 16U * scale;

while (*text)
{
uint32_t cp = TFT1520_UTF8_Next(&text);

// CR
if (cp == ‘\r’)
continue;

// LF
if (cp == ‘\n’)
{
x = x0;
y += charHeight;

if ((uint32_t)y + charHeight > Y_SIZE)
break;

continue;
}

// Автоматический перенос строки
if ((uint32_t)x + charWidth > X_SIZE)
{
x = x0;
y += charHeight;
}

if ((uint32_t)y + charHeight > Y_SIZE)
break;

TFT1520_DrawChar(
x,
y,
cp,
color,
background,
scale
);

x += charWidth;
}
}

Вывод текста на экран:
TFT1520_Print(
                               10, 20, // X, Y
                               u8″Температура: 25°С», // текст
                              0xFFFF, // цвет текста
                              0x0000, // цвет фона
                              1 // масштаб
);