Андрей Смирнов
Время чтения: ~15 мин.
Просмотров: 495

Работа с цветными графическими дисплеями TFT (библиотека UTFT)

Для Arduino есть очень много модулей , датчиков. Но все это скучно без дисплея )) В этой статье мы с вами подключим TFT дисплей с драйвером ILI9341 к контролеру.

В руки мне попал Китайский брат с  маркировкой KMRTM24024-SPI. Это TFT дисплей с диагональю 2.4″ и SPI интерфейсом.

Характеристики :

  • Диагональ: 2,4 .
  • Цвет: 18-бит, 262 000 оттенков.
  • Разрешение: 320 х 240.
  • Соотношение сторон экрана: 4 : 3 .
  • Питание : 3.3В/5 В.
  • Интерфейс : SPI .

Самое интересное, что логика работы драйвера 3.3 В . По этому нам потребуется согласовать наше Arduino с логикой 5 В и дисплей.

Выводы :

  • VCC = +5v (+5 вольт).
  • GND = GND (земля).
  • LED = +3.3v (подсветка дисплея).
  • SCK = SPI.
  • SDI/SD (MOSI) = SPI.
  • SDO(MISO) = SPI.
  • CS = выбор устройства.
  • D/C = Команда/Данные.

Схема подключения :

Так как логика работу у дисплея и контролера разная нам надо их согласовать. Тут есть два варианта:

  • Использовать делитель напряжения на резисторах, нам потребуется резисторы 20 кОм и 10 кОм.
  • Использовать микросхему CD4050B non-inverting hex buffers,logiclevel conversion, собственно что я и выбрал.
  • Vss = питание минус.
  • Vcc = +3.3В питание логики.

Когда на вход A подается +5 вольт, на выходе G будет +3.3 В. Думаю принцип работы понятен.

Соединение дисплея с Arduino Nano:

SCK —— pin D8 ( через делитель ).SDI (MOSI) —— pin D9 ( через делитель ).D/C —— pin D10 ( через делитель ).RESET —— pinD 11 ( через делитель ).CS —— pin D12 ( через делитель ).VCC —— +5v (+5 вольт,ВНИМАНИЕ ваш дисплей может питаться 3.3В)GND —— GND (земля).LED —— +3.3v (подсветка дисплея).

Кодинг :

Для работы с дисплеем есть много разных библиотек. Я использую библиотеку UTFT которую скачаем с GitHab или с нашего сайта. Загрузим готовый  скетч  из примеров с нашим разрешение :

// библиотека для работы с дисплеем #include   // создаём объект класса UTFT // и передаём идентификатор модели дисплея и номера пинов // к которым подключаются линии SCK, SDI (MOSI), D/C, RESET, CS  //  UTFT myGLCD(TFT01_22SP, SDI (MOSI),SCK ,CS ,RESET , D/C); UTFT myGLCD(TFT01_22SP, 9, 8, 12, 11, 10);  // объявления встроенных шрифтов extern uint8_t SmallFont[]; extern uint8_t BigFont[]; extern uint8_t SevenSegNumFont[];  void setup() { }  void loop() {  // инициализируем дисплей с вертикальной ориентацией  myGLCD.InitLCD(0);  // очищаем экран  myGLCD.clrScr();  // выбираем большой шрифт  myGLCD.setFont(BigFont);  // печатаем строку в центре верхней строки дисплея  myGLCD.print("TFT01_22SP", CENTER, 0);  // выбираем большой шрифт  myGLCD.setFont(SmallFont);  // печатаем строку в указанной строке позиции  myGLCD.print("Hello from Amperka!", CENTER, 50);  // выбираем сесисегментный шрифт  myGLCD.setFont(SevenSegNumFont);  // печатаем строку в указанной строке позиции  myGLCD.print("12345", CENTER, 100);  // ждём 1 секунду  delay(10000);  // инициализируем дисплей с горизонтальной ориентацией  myGLCD.InitLCD(1);  // очищаем экран  myGLCD.clrScr();  // выбираем большой шрифт  myGLCD.setFont(BigFont);  // печатаем строку в центре верхней строки дисплея  myGLCD.print("Hello, user!", CENTER, 0);  // выбираем большой шрифт  myGLCD.setFont(SmallFont);  // печатаем строку в указанной строке позиции  myGLCD.print("The screen is 2.2 diagonal", CENTER, 50);  // выбираем сесисегментный шрифт  myGLCD.setFont(SevenSegNumFont);  // печатаем строку в указанной строке позиции  myGLCD.print("67890", CENTER, 100);  // ждём 1 секунду  delay(10000); }

Этот пример поможет вам с конвертацией типа float в string:

Arduino-FloatToString  #include<stdlicluded for="" floattostring="" function="" string="" x="" byte="" precision="2)" char="" tmp="" dtostrf="" return="" void="" setup="" float="" f="-17.06f;" some="" number="" str="floatToString(f);" conversion="" call="" print="" over="" serial="" serial.begin="" serial.println="" loop="">

Вот собственно и все . Дальше все ограничено только вашей фантазией.

Поддерживаемые дисплеи

Дисплеи Инициализация
Цветной графический дисплей 2.8 TFT 320х240
55f461d32d20cd6ec6006696600b1e1c.jpg
Данный дисплей совместим с любыми Arduino.

UTFT myGLCD(TFT01_24SP, 6, 5, 4, 3, 2);

Дисплей можно подключать к любым выводам Arduino указав № выводов при объявлении объекта myGLCD библиотеки UTFT:UTFT myGLCD(TFT01_24SP, SDI/MOSI, SCK, CS, RESET, DC/RS);

Описание работы с сенсорным экраном находится в разделе Wiki работа с TouchScreen

Цветной графический дисплей 3.5 TFT 480×320 MEGAtft480320_2.jpg

Цветной графический дисплей 3.2 TFT 480×320 MEGA.

tft480320_2.jpg
Данный дисплей совместим только с Arduino Mega.

UTFT myGLCD(TFT32MEGA, 38, 39, 40, 41); // дисплей на чипе ILI9341.илиUTFT myGLCD(TFT32MEGA_2, 38, 39, 40, 41); // дисплей на чипе HX8357C.

Дисплеи поставляются на базе чипа ILI9341 или HX8357C. Если изображение на дисплее отображается зеркально, то измените тип дисплея: укажите либо TFT32MEGA, либо TFT32MEGA_2.

Если Вы не планируете использовать SD карту, то выводы 50-53 можно использовать для подключения других модулей.

Выводы не подписанные на рисунке, не используются дисплеем.

ccf67326622b7aa25021997bc4667a81.jpg

Цветной графический дисплей 2.8 TFT 320×240 UNO2.8-uno-_4.png Данный дисплей совместим только с Arduino Uno.

UTFT myGLCD(TFT28UNO, A2, A1, A3, A4, A0);

Если Вы не планируете использовать SD карту, то выводы 10-13 можно использовать для подключения других модулей.

Выводы не подписанные на рисунке, не используются дисплеем.

Описание работы с сенсорным экраном находится в разделе Wiki работа с TouchScreen

4de01cb7f52c63f2fb8eea10aa401e36.jpg

Цветной графический дисплей 2.4 TFT 240×32055c9cdace46dfa87a91aa5ca92b07a3c.jpg Данный дисплей совместим с любыми Arduino.

UTFT myGLCD(TFT01_24SP, 5, 4, 8, 7, 6);

Дисплей можно подключать к любым выводам Arduino указав № выводов при объявлении объекта myGLCD библиотеки UTFT:UTFT myGLCD(TFT01_24SP, SDI/MOSI, SCK, CS, RESET, DC/RS);

f7a8bad2a7576d3fecd3cd2aca2a9312.jpg

При питании от 3,3 В необходимо замкнуть перемычку J1 на обратной стороне платы дисплея.

Если Вы желаете использовать SD-карту, то выводы SD_CS, SD_MOSI, SD_MISO и SD_SCK необходимо подключить к Arduino по аппаратной шине SPI:

cf591794db2c4a17be392dd6a269d1d5.jpg

Если аппаратный вывод CS(SS) Arduino занят, то вывод SD_CS можно подключить к любому другому выводу Arduino, указав его номер в скетче (см пример в файле image_SD библиотеки UTFT).

TouchScreen можно подключать к любым выводам Arduino указав № выводов при объявлении объекта myTouch библиотеки URTouch:URTouch myTouch( T_CLK, T_CS, T_DIN, T_OUT, T_IRQ);Например: URTouch myTouch(13, 12, 11, 10, 9);

7e04a808b1ce853dc234af1145657a5a.jpg

Указанные в примере выводы Arduino для подключения TouchScreen пересекаются с выводами аппаратной шины SPI на платах Arduino Uno, Pro Mini, Nano и т.д. Если Вы желаете использовать на этих платах и TouchScreen, и SD-карту, то для TouchScreen нужно выбрать другие выводы Arduino, например, аналоговые выводы A0-A4, указав их в скетче при объявлении объекта:URTouch myTouch(A0, A1, A2, A3, A4);

Описание работы с сенсорным экраном со встроенным контроллером функций TouchScreen находится в разделе Wiki работа с TouchScreen по последовательной шине данных.

Цветной графический дисплей 2.2 TFT 320×240saddsf1.jpg

Цветной графический дисплей 1.8 TFT 128×160

215da784e57b5342cb91f0913ac0af1e.jpg
Данный дисплей совместим с любыми Arduino.

UTFT myGLCD(TFT01_22SP, 5, 4, 8, 7, 6);

Дисплей можно подключать к любым выводам Arduino указав № выводов при объявлении объекта myGLCD библиотеки UTFT:UTFT myGLCD(TFT01_22SP, SDI/MOSI, SCK, CS, RESET, DC/RS);

d72e30bd1f9c6a0c9c378b5f45ff4c11.jpg

Если Вы желаете использовать SD-карту, то выводы SD_CS, SD_MOSI, SD_MISO и SD_SCK необходимо подключить к Arduino по аппаратной шине SPI:

cf591794db2c4a17be392dd6a269d1d5.jpg

Если аппаратный вывод CS(SS) Arduino занят, то вывод SD_CS можно подключить к любому другому выводу Arduino, указав его номер в скетче (см пример в файле image_SD библиотеки UTFT).

Если Вы собираетесь использовать библиотеку UTFT для работы с другими дисплеями, то закомментируйте строку с названием Вашего дисплея в файле «memorysaver.h». А для экономии памяти, раскомментируйте остальные строки кода файла «memorysaver.h».

#1 Пример

Выводим на дисплей текст тремя базовыми шрифтами:

#2 Пример

Заливаем весь дисплей различными цветами:

#3 Пример

Рисуем различные графические элементы:

Базовые функции:

Все функции:

  • InitLCD([положение]); – Инициирует начало работы с дисплеем. Необязательный параметр может принимать одно из двух значений: PORTRAIT (вертикальная ориентация) или LANDSCAPE (горизонтальная ориентация — по умолчанию).
  • clrScr(); – Очищает дисплей, стирая всю отображаемую на дисплее информацию и заливая дисплей черным цветом.
  • fillScr(color); – Очищает дисплей, стирая всю отображаемую на дисплее информацию и заливая его указанным в качестве параметра цветом фона.
  • getDisplayXSize(); – Возвращает количество пикселей дисплея по горизонтали, число типа int.
  • getDisplayYSize(); – Возвращает количество пикселей дисплея по вертикали, число типа int.
  • setColor(color); – Выбор цвета для текста и фигур, выводимых после данной функции.
  • getColor(); – Возвращает установленный цвет для текста и фигур в формате RGB565, число типа word.
  • setBackColor(color); – Выбор цвета для фона текста, выводимого после данной функции.
  • getBackColor(); – Возвращает установленный цвет для фона текста в формате RGB565, число типа word.
  • setFont(fontName); – Выбор шрифта для текста выводимого после данной функции.
  • getFont(); – Возвращает указатель на выбранный шрифт.
  • getFontXsize(); – Возвращает количество пикселей в одном символе шрифта, по ширине.
  • getFontYsize(); – Возвращает количество пикселей в одном символе шрифта, по высоте.
  • print(str,x,y[,r]); – Вывод на дисплей строк или содержимого строковых переменных.
  • printNumI(int,x,y[,len[,sym]]); – Вывод на дисплей целого числа или содержимого целочисленной переменной.
  • printNumF(float,dec,x,y[,sym1[,len[,sym2]]]); – Вывод на дисплей вещественного числа или содержимого переменной вещественного типа
  • drawPixel(x,y); – Вывод на дисплей точки. Цвет точки определяется текущим значением цвета, устанавливаемым командой setColor().
  • drawLine(x1,y1,x2,y2); – Вывод на дисплей линии, заданной координатами двух точек.
  • drawRect(x1,y1,x2,y2); – Вывод на дисплей прямоугольника, противоположные углы которого заданы координатами двух точек.
  • drawRoundRect(x1,y1,x2,y2); – Вывод на дисплей прямоугольника со скругленными углами.
  • fillRect(x1,y1,x2,y2); – Вывод на дисплей закрашенного прямоугольника.
  • drawCircle(x,y,R); – Вывод на дисплей окружности, определяемую координатами центра и радиусом.
  • fillCircle(x,y,R); – Вывод на дисплей закрашенной окружности.
  • drawBitmap(x1,y1,x2,y2,data[,scale]); – Вывод на дисплей картинки из массива.
  • Для вывода на дисплей картинки из файла с SD-карты нужно вызвать функцию load(x1,y1,x2,y2,data); объекта библиотеки UTFT_SdRaw.Для работы функции load, нужно установить и подключить библиотеки: UTFT_SdRaw и SdFat.

Инициализация работы с дисплеем:

InitLCD( [положение] ); Инициализация работы с дисплеем, с указанием его положения. Параметр:
  • Положение может быть горизонтальным или вертикальным:
  • положение: PORTRAIT — вертикальное
  • положение: LANDSCAPE — горизонтальное (по умолчанию)

Очистка экрана:

clrScr();Очистка экрана с заливкой дисплея чёрным цветом Параметр: Без параметров.
fillScr( color ); Очистка экрана с заливкой заданным цветом. Параметр:
  • Цет можно задать тремя способами:
  • color: По названию цвета — VGA_RED
  • color: В формате RGB565 — 0x001F
  • color: В формате RGB — 255,100,0

Выбор цвета:

setColor( color );Выбор цвета для текста и фигур, выводимых после данной функции. Параметр:
  • Цет можно задать тремя способами:
  • color: По названию цвета — VGA_RED
  • color: В формате RGB565 — 0x001F
  • color: В формате RGB — 255,100,0
setBackColor( color );Выбор цвета для фона текста, выводимого после данной функции. Параметр:
  • Цет можно задать тремя способами:
  • color: По названию цвета — VGA_RED
  • color: В формате RGB565 — 0x001F
  • color: В формате RGB — 255,100,0

Выбор шрифта:

setFont( fontName );Выбор шрифта для текста выводимого после данной функции. Параметр:
  • По умолчанию в библиотеке есть 3 шрифта:
  • fontName: SmallFont — маленький шрифт
  • fontName: BigFont — большой шрифт
  • fontName: SevenSegNumFont — шрифт имитирующий семисегментный индикатор

Вывод текста:

print( str , x , y [, r] );Выводит на дисплей строки или содержимое строковых переменных. Параметры:
  • str: строка или содержимое строковой переменной
  • x: координата X
  • y: координата Y координаты верхнего левого угла области печати(

x можно указать как число или LEFT / RIGHT / CENTER) r: поворот текста в градусах, вокруг точки x,yr — необязательный параметр</li></ul>

printNumI( int , x , y [, len [, sym ] ] );Выводит на дисплей целые числа или содержимое целочисленных переменных. Параметры:
  • int: целое число или содержимое целочисленной переменной
  • x: координата X
  • y: координата Y координаты верхнего левого угла области печати(

x можно указать как число или LEFT / RIGHT / CENTER) len: количество выводимых разрядов числа int.игнорируется если len меньше количества разрядов int.необязательный параметр, по умолчанию: 0</li>sym: символ заменяющий недостающие разряды.необязательный параметр, по умолчанию: ‘ ‘(если len больше чем количество разрядов числа int, то недостающие разряды перед числом будут заменены на sym.)</li></ul>

printNumF( float , dec, x , y [, sym1 [, len [, sym2 ] ] ] );Выводит на дисплей вещественные числа или содержимое переменных вещественного типа. Параметры:
  • float: вещественное число или содержимое переменной вещественного типа.
  • dec: количество выводимых знаков после запятой.допускается только значение больше 0
  • x: координата X
  • y: координата Y координаты верхнего левого угла области печати.(

x можно указать как число или LEFT / RIGHT / CENTER) sym1: символ заменяющий запятую при выводе.необязательный параметр, по умолчанию: ‘.'</li>len: количество всех выводимых знаков и символов числа int.игнорируется если len меньше количества знаков и символов.необязательный параметр, по умолчанию: 0</li>sym2: символ заменяющий недостающие разряды.необязательный параметр, по умолчанию: ‘ ‘(если len больше чем количество знаков и символов в числе int, то недостающие разряды перед числом будут заменены на sym2.)</li></ul>

Графические функции:

drawPixel( x , y );Выводит на дисплей точку. Параметры:
  • x: координата X
  • y: координата Y
drawLine( x1 , y1 , x2 , y2 );Выводит на дисплей линию заданную координатами двух точек. Параметры:
  • x1: координата X, первой точки
  • y1: координата Y, первой точки
  • x2: координата X, второй точки
  • y2: координата Y, второй точки
drawRect( x1 , y1 , x2 , y2 );Выводит на дисплей прямоугольник, заданный координатами двух противоположных углов. Параметры:
  • x1: координата X, первого угла
  • y1: координата Y, первого угла
  • x2: координата X, второго угла
  • y2: координата Y, второго угла
drawRoundRect( x1 , y1 , x2 , y2 );Выводит на дисплей прямоугольник со скругленными углами, заданный координатами двух противоположных углов. Параметры:
  • x1: координата X, первого угла
  • y1: координата Y, первого угла
  • x2: координата X, второго угла
  • y2: координата Y, второго угла
fillRect( x1 , y1 , x2 , y2 );Выводит на дисплей закрашенный прямоугольник, заданный координатами двух противоположных углов. Параметры:
  • x1: координата X, первого угла
  • y1: координата Y, первого угла
  • x2: координата X, второго угла
  • y2: координата Y, второго угла
drawCircle( x , y , R );Выводит на дисплей окружность, определяемую координатами центра и радиусом. Параметры:
  • x: координата X, центра окружности
  • y: координата Y, центра окружности
  • R: радиус окружности
fillCircle( x , y , R );Выводит на дисплей закрашенный текущим цветом круг, определяемый координатами центра и радиусом. Параметры:
  • x: координата X, центра окружности
  • y: координата Y, центра окружности
  • R: радиус окружности

Вывод изображений

Выводим на дисплей картинки из массивов:

  • Картинки необходимо конвертировать с помощью специальной программы ImageConverter565, которая находится в папке Tools библиотеки UTFT, при сохранении выбрать тип файла «.c» под микроконтроллер AVR.
  • Сохранённый файл «Название.c» нужно поместить в папку со скетчем использующим этот файл. Название массива будет совпадать с названием файла.
  • Файл с массивом используемым в нашем примере вы можете найти в папке examples/дисплей/image_Arrayбиблиотеки UTFT.
drawBitmap( x1 , y1 , x2 , y2 , Name );Вывод на дисплей картинки из массива. Параметры:
  • x1: координата X, левого верхнего угла дисплея
  • y1: координата Y, левого верхнего угла дисплея
  • x2: размер картинки по оси X
  • y2: размер картинки по оси Y
  • Name: Название массива который содержит изображение Изображение выводиться в прямоугольную область, верхний левый угол которой задан точкой с координатами x1,y1.

Выводим на дисплей картинки с SD карты:

  • Для вывода картинок, в дополнении к библиотеке UTFT, понадобится установить и подключить библиотеки: и: UTFT_SdRaw и SdFat.
  • Библиотека SdFat предназначена для работы с SD-картами. Поддерживаются SD-карты отформатированные под файловую систему FAT32 (максимальный объем SD-карты 32 ГГб) и FAT16 (максимальный объем SD-карты 2 ГГб).
  • Библиотека UTFT_SdRaw предназначена для вывода изображений на дисплей.
  • Картинки необходимо конвертировать с помощью специальной программы ImageConverter565, которая находится в папке Toolsбиблиотеки UTFT, при сохранении выбрать тип файла «.raw». Сохранённый файл нужно записать на SD-карту.
  • Картинки используемые в нашем примере вы можете найти в папке imageбиблиотеки UTFT.
load( x1 , y1 , x2 , y2 , «fileName.raw» );Вывод на дисплей картинки из файла на SD карте.Функция относится к объекту библиотеки UTFT_SdRaw а не UTFT. Параметры:
  • x1: координата X, левого верхнего угла дисплея
  • y1: координата Y, левого верхнего угла дисплея
  • x2: размер картинки по оси X
  • y2: размер картинки по оси Y
  • NameFile: Название файла изображения на SD карте Изображение выводиться в прямоугольную область, верхний левый угол которой задан точкой с координатами x1,y1.

Ссылки:

  • Цветной графический дисплей 3.95 TFT 480×320 UNO.
  • Цветной графический дисплей 3.5 TFT 480×320 MEGA.
  • Цветной графический дисплей 3.2 TFT 480×320 MEGA.
  • Цветной графический дисплей 2.8 TFT 320×240 UNO.
  • Цветной графический дисплей 2.8 TFT 320×240.
  • Цветной графический дисплей 2.4 TFT 240×320.
  • Цветной графический дисплей 2.2 TFT 320×240.
  • Цветной графический дисплей 1.8 TFT 128×160.
  • Цветной графический дисплей 2.8 TFT 320×240.
  • Библиотека UTFT для работы с цветными графическими дисплеями.
  • Библиотека UTFT_SdRaw для загрузки изображений в дисплей.
  • Библиотека SdFat для работы с SD-картами.
  • Библиотека TouchScreen для работы с сенсорными экранами (используются аналоговые данные).
  • Библиотека URTouch для работы с сенсорными экранами оснащёнными контроллерами функций TouchScreen.
  • Wiki — Установка библиотек в Arduino IDE.
  • Wiki — Работа с TouchScreen по данным считанным с аналоговых входов.
  • Wiki — Работа с TouchScreen по последовательной шине данных.

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

podklyuchenie-tft-displeya-1-8-k-arduino-1.jpg

Технические параметры

Общие сведения

TFT дисплей цветной с диагональю 1.8 дюйма и расширением 128 на 160 точек, за обработку данный отвечает контроллер ST7735R, который может отобразить до 18-бит цвета (262144 оттенков), работает данный контроллер (дисплей) от 3.3В и для работы от плат arduino предусмотрен стабилизатор напряжения на 3.3В, но если необходимо работать от 3.3В просто замыкаем перемычку (как показывает опыт, модуль может работать и от 5В логики). Так-же, на модуле установлен держатель карты SD для хранения и загрузки изображения на TFT дисплей. Подключение осуществляется по ISP интерфейсу (4-х проводному), все выводы выведены на боковую группу контактов, на другой стороне платы, выведены вывода SD карты.

podklyuchenie-tft-displeya-1-8-k-arduino-2.jpg

Группа контактов 1LED — управление подсветкой, напряжение не более 3.3 В► SCK — линия синхронизации► SDA — линия данных (Serial Data)► A0RESET — сброс► CS — выбор устройства► GND — «-» питание модуля► VCC — «+» питание модуля

Группа контактов 2SD_CS — выбор устройства► SD_MOSI — прием данных► SD_MISO — передача данных► SD_SCK —  линия синхронизации

Подключение TFT дисплея к Arduino

Необходимые детали:► Цветной TFT-дисплей 1.8, 128×160, SPI x 1 шт.► Arduino UNO R3 (DCCduino, CH340G) x 1 шт.► Провод DuPont 10x, 2,54 мм, 20 см, F-F (Female — Female) x 1 шт.

podklyuchenie-tft-displeya-1-8-k-arduino-4.jpg

Таблица подключения TFT дисплея

podklyuchenie-tft-displeya-1-8-k-arduino-3.jpg

Как говорил выше, дисплей работает по интерфейсу SPI, поэтому необходимо включить в проект библиотеку SPI, а так же библиотеку TFT, все они входят в стандартные библиотеки среды разработки IDE Arduino.

Используемые источники:

  • https://xn--90aeniddllys.xn--p1ai/podklyuchenie-tft-displeya-s-drajverom-ili9341-k-arduino/
  • https://wiki.iarduino.ru/page/rabota-s-cvetnym-graficheskim-displeem
  • https://robotchip.ru/podklyuchenie-tft-displeya-1-8-k-arduino/

Рейтинг автора
5
Подборку подготовил
Андрей Ульянов
Наш эксперт
Написано статей
168
Ссылка на основную публикацию
Похожие публикации