Программирование электронной бумаги EPD 203 с нуля

Как программировать цифровой дисплей epd 203

Как программировать цифровой дисплей epd 203

Электронная бумага EPD 203 от Good Display – это монохромный дисплей с разрешением 250×122 пикселя и диагональю 2,13 дюйма, работающий на контроллере SSD1680. Его ключевые особенности: низкое энергопотребление (менее 1 мА в режиме обновления), поддержка частичного обновления экрана и возможность работы без питания после отображения статичного изображения. Для начала потребуется микроконтроллер с SPI-интерфейсом (например, STM32, ESP32 или Arduino) и библиотека GxEPD2, адаптированная под этот контроллер.

Для оптимизации энергопотребления используйте режим глубокого сна между обновлениями. После вызова powerOff() дисплей сохраняет изображение без питания, но повторная инициализация занимает ~100 мс. Избегайте частых полных обновлений – они изнашивают экран. Вместо этого применяйте частичные обновления для динамических элементов (например, времени или показаний датчиков). При работе с текстом используйте моноширинные шрифты из библиотеки Adafruit GFX, так как пропорциональные шрифты могут вызывать артефакты из-за особенностей контроллера.

Типичные ошибки: неправильная полярность сигнала BUSY (активный низкий уровень), игнорирование задержек после команд (например, 10 мс после reset()) и неверная настройка тактовой частоты SPI (рекомендуется 4 МГц для стабильной работы). Для отладки подключите логический анализатор к линиям SPI и проверяйте последовательность команд с помощью даташита SSD1680. При проблемах с отображением сбросьте контроллер аппаратно (RST на 10 мс) и повторите инициализацию.

Выбор и подключение микроконтроллера для работы с EPD 203

Выбор и подключение микроконтроллера для работы с EPD 203

EPD 203 – дисплей с разрешением 250×122 пикселя и 1.54-дюймовым экраном, требующий минимальных ресурсов для управления. Оптимальный выбор микроконтроллера (МК) зависит от протокола связи, энергопотребления и доступных интерфейсов. Основные варианты: STM32 (серии F1/F4), ESP32 и Raspberry Pi Pico. STM32F103C8T6 (Blue Pill) подходит для базовых задач благодаря аппаратной поддержке SPI и низкому энергопотреблению (~20 мА в активном режиме). ESP32 выигрывает при необходимости беспроводного управления (Wi-Fi/BLE), но потребляет больше (~80 мА). Pico – компромисс с гибким программированием на C/C++ или MicroPython.

EPD 203 использует 3-проводной SPI (MOSI, SCK, CS) и дополнительные сигналы: DC (команда/данные), RST (сброс), BUSY (состояние дисплея). МК должен иметь как минимум 4 свободных GPIO для этих линий. Для STM32 рекомендуется выделять аппаратный SPI (например, SPI1 на PA5-PA7) для стабильной передачи данных на скорости до 4 МГц. ESP32 поддерживает SPI на любых пинах, но для надежности лучше использовать VSPI (GPIO 18-23). Pico предлагает два аппаратных SPI (SPI0 и SPI1), где SPI0 (GP16-GP19) удобен для макетных плат.

Объем памяти критичен для хранения буфера изображения. EPD 203 требует ~3.8 КБ (250×122 / 8) на кадр. STM32F103 с 20 КБ SRAM справляется с одной страницей, но для двойной буферизации или анимации нужен МК с большим объемом (например, STM32F401 с 96 КБ). ESP32 (520 КБ SRAM) и Pico (264 КБ) избыточны для статичных изображений, но полезны при обработке динамического контента. Flash-память важна для хранения шрифтов и графики: минимально – 64 КБ (STM32F103), оптимально – 512 КБ и выше.

Энергоэффективность критична для батарейных устройств. EPD 203 потребляет ~26 мВт в активном режиме и ~0.01 мВт в спящем. МК должен поддерживать режимы глубокого сна: STM32 (2 мкА в Standby), ESP32 (5 мкА в Deep Sleep), Pico (1 мкА). Для автономной работы выбирайте МК с RTC (STM32) или внешним таймером (ESP32 с ULP-копроцессором). Избегайте МК без аппаратного управления питанием (например, Arduino Uno), так как они не обеспечивают низкое потребление в простое.

Подключение начинайте с питания: EPD 203 требует 3.3 В, поэтому МК должен работать на том же уровне (STM32, ESP32, Pico). Используйте стабилизатор (AMS1117) при питании от 5 В. Соедините линии SPI напрямую, но добавьте резисторы 100 Ом на MOSI и SCK для защиты от помех. Сигнал BUSY подключайте к GPIO с поддержкой прерываний (например, PA0 на STM32) для асинхронного ожидания готовности дисплея. Линии DC и RST управляются программно – используйте любые свободные пины.

Пример распиновки для STM32F103 (Blue Pill):

SPI1: PA7 (MOSI), PA5 (SCK), PA4 (CS); GPIO: PA3 (DC), PA2 (RST), PA0 (BUSY).

Для ESP32 (VSPI):

GPIO23 (MOSI), GPIO18 (SCK), GPIO5 (CS); GPIO: GPIO22 (DC), GPIO21 (RST), GPIO19 (BUSY).

Pico (SPI0):

GP19 (MOSI), GP18 (SCK), GP17 (CS); GPIO: GP16 (DC), GP15 (RST), GP14 (BUSY).

Избегайте пинов с альтернативными функциями (например, UART, I2C) для SPI, чтобы исключить конфликты.

Настройка питания и распиновки дисплея EPD 203

Распиновка EPD 203: BUSY (вход, подтяжка к VCC через 10 кОм) сигнализирует о готовности дисплея к приему данных – игнорирование этого сигнала приводит к сбоям обновления. RST (активный низкий) требует импульса длительностью ≥10 мс для сброса. DC переключает режим: низкий уровень – команды, высокий – данные. SPI-интерфейс использует SCLK (до 10 МГц) и MOSI; CS (активный низкий) выбирает дисплей. Для надежной работы подтяните CS к VCC через 4.7 кОм. Избегайте длинных проводов (>15 см) для SPI – используйте экранированный кабель или сократите длину.

Установка и конфигурация библиотек для управления EPD 203

Для работы с EPD 203 на микроконтроллерах ESP32 или STM32 потребуется библиотека GxEPD2, адаптированная под контроллеры электронной бумаги Good Display. Установите её через Arduino Library Manager: откройте Скетч → Подключить библиотеку → Управлять библиотеками, введите в поиске GxEPD2 и выберите версию от ZinggJM. Альтернативный способ – ручная установка из репозитория GitHub: скачайте архив с официальной страницы, распакуйте в папку libraries Arduino IDE и переименуйте директорию в GxEPD2.

После установки подключите зависимости. Для ESP32 добавьте библиотеку SPI (входит в стандартный пакет Arduino-ESP32) и Adafruit_GFX – она необходима для отрисовки графики. Версия Adafruit_GFX должна быть не ниже 1.10.0, иначе возникнут конфликты с методами отрисовки. На STM32 используйте SPI из пакета STM32duino и дополнительно установите STM32LowPower, если планируете работу в режиме энергосбережения.

Конфигурация пинов для EPD 203 зависит от используемой платы. Для ESP32 стандартное подключение: CS=5, DC=17, RST=16, BUSY=4. На STM32 Nucleo-64 (например, F411RE) назначьте: CS=PA4, DC=PA3, RST=PA2, BUSY=PA1. В коде инициализируйте дисплей через конструктор GxEPD2_BW<GxEPD2_200, GxEPD2_200::HEIGHT> display(GxEPD2_200(/*CS=*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));. Для STM32 замените номера пинов на соответствующие.

Перед первым запуском проверьте напряжение питания. EPD 203 требует стабильных 3.3 В – отклонения более ±0.1 В могут вызвать артефакты на экране. Подключите конденсатор 10 мкФ между VCC и GND дисплея для фильтрации помех. Если используете внешний источник питания, убедитесь, что его ток не менее 500 мА, иначе дисплей может не выйти из спящего режима.

Для оптимизации скорости работы настройте тактовую частоту SPI. По умолчанию библиотека использует 4 МГц, но для EPD 203 допустимо увеличение до 8 МГц на ESP32 и до 10 МГц на STM32. Измените частоту в методе display.init(), добавив параметр: display.init(115200, true, 2, false, SPI, SPISettings(8000000, MSBFIRST, SPI_MODE0));. На STM32 используйте SPISettings(10000000, MSBFIRST, SPI_MODE0). Превышение этих значений приведёт к ошибкам передачи данных.

При возникновении ошибок display.init() failed проверьте физическое подключение. Частые причины: неправильно назначенные пины, отсутствие общего GND между микроконтроллером и дисплеем, или повреждённый кабель. Для диагностики используйте логический анализатор – он поможет выявить отсутствие сигналов на линиях CS или BUSY. Если дисплей не реагирует на команды, сбросьте его вручную, удерживая RST в низком состоянии не менее 10 мс перед инициализацией.

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

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

  • Отправьте команду 0x01 (DRIVER_OUTPUT_CONTROL) с параметрами 0xC7, 0x00, 0x00 для настройки разрешения (176×264 пикселя).
  • Установите параметры шрифта и адресации через 0x0C (BOOSTER_SOFT_START) с байтами 0xD7, 0xD6, 0x9D.
  • Задайте напряжение питания с помощью 0x04 (POWER_ON) и дождитесь завершения инициализации по BUSY.

Для отправки данных используйте режим передачи команд (DC=0) и данных (DC=1). Пример: чтобы очистить экран, отправьте команду 0x24 (WRITE_RAM) с последующей передачей массива байтов 0xFF (белый цвет) или 0x00 (чёрный). Размер буфера зависит от разрешения: 176×264 пикселей требует 5808 байт (176/8 * 264).

Ошибки инициализации часто связаны с неверными таймингами или неправильной последовательностью команд. Если дисплей не реагирует, проверьте:

  1. Наличие задержек между командами (минимум 2 мс после POWER_ON).
  2. Состояние BUSY перед каждой операцией.

После успешной инициализации дисплей готов к приёму графических данных. Для обновления экрана используйте команду 0x22 (DISPLAY_UPDATE_CONTROL2) с параметром 0xC4, затем 0x20 (MASTER_ACTIVATION). Это запускает цикл обновления, который занимает до 2 секунд. Избегайте отправки новых команд до завершения процесса.

Формирование и передача изображения на экран EPD 203

EPD 203 поддерживает монохромные изображения с разрешением 200×96 пикселей. Каждый пиксель кодируется одним битом: 0 – белый, 1 – чёрный. Для формирования изображения создайте массив байтов, где каждый байт содержит 8 пикселей в порядке от старшего бита к младшему. Например, байт 0xF0 (11110000) отобразит первые четыре пикселя чёрными, остальные – белыми.

Перед передачей данных на экран преобразуйте изображение в формат, совместимый с контроллером SSD1608. Используйте команду 0x10 (Data Start Transmission 1) для передачи чёрных пикселей и 0x13 (Data Start Transmission 2) – для красных (если используется трёхцветная версия). Для монохромной версии достаточно одной команды 0x10. Данные передаются по SPI с частотой до 4 МГц.

Контроллер требует предварительной инициализации через последовательность команд: 0x01 (Driver Output Control), 0x06 (Booster Soft Start Control), 0x04 (Power On). После этого отправьте команду 0x12 (Display Refresh) для обновления экрана. Обновление занимает ~1,5 секунды – избегайте частых перерисовок, чтобы не сократить срок службы дисплея.

Для оптимизации передачи данных используйте буферизацию. Создайте массив размером 2400 байт (200×96/8) и заполняйте его побитово. Пример для установки пикселя (x, y) в чёрный цвет: buffer[(y * 25) + (x / 8)] |= (0x80 >> (x % 8)). Убедитесь, что координаты не выходят за пределы 0–199 (x) и 0–95 (y).

EPD 203 поддерживает частичное обновление через команду 0x16 (Partial Data Start Transmission). Укажите прямоугольную область обновления командами 0x15 (Partial Window) с параметрами: [x_start, x_end, y_start, y_end]. Это сокращает время обновления до ~0,3 секунды, но требует точного расчёта границ области.

При работе с динамическим контентом (например, часы) используйте режим 0x22 (Display Update Control 2) с параметром 0xC7 для быстрого обновления без полной перерисовки. Это снижает износ экрана, но может оставлять артефакты. Для их устранения периодически выполняйте полное обновление с параметром 0xF7.

Избегайте передачи избыточных данных. Если изображение не изменилось, пропустите отправку. Контроллер SSD1608 игнорирует повторяющиеся команды, но лишние операции увеличивают энергопотребление. Для проверки изменений храните предыдущее состояние буфера и сравнивайте его с новым перед передачей.

При отладке используйте логирование SPI-команд. Записывайте отправленные байты в файл или UART для анализа последовательности. Типичная ошибка – неверный порядок байтов в массиве: данные должны следовать слева направо, сверху вниз. Проверяйте корректность заполнения буфера с помощью отладочных инструментов, например, Saleae Logic Analyzer.

Оптимизация буфера данных для быстрого обновления экрана

EPD 203 использует статический буфер кадра размером 5808 байт (200×200 пикселей, 4 градации серого на пиксель). Каждый байт хранит два пикселя, что требует точного управления битами. Основная проблема – медленная запись в контроллер через SPI (максимум 4 МГц для стабильной работы). Уменьшение объема передаваемых данных сокращает время обновления на 30–40%.

Первый шаг – минимизация изменяемых областей. Вместо полной перерисовки экрана используйте частичное обновление (partial update). Контроллер EPD 203 поддерживает передачу только измененных прямоугольных областей. Пример: если обновляется область 50×50 пикселей, объем данных сокращается с 5808 до 1250 байт. Для реализации:

  • Храните предыдущий и текущий кадры в RAM.
  • Сравнивайте их побитно через XOR.
  • Определяйте минимальный bounding box изменений.

Буфер в RAM должен быть выровнен по границе 4 байт. Это ускоряет копирование через memcpy на 15–20% за счет оптимизаций компилятора. Используйте директиву __attribute__((aligned(4))) для GCC или #pragma pack(4) для других компиляторов. Избегайте динамического выделения памяти – фиксированный буфер в .bss-секции работает быстрее.

Для 4-градационных дисплеев применяйте палитру сжатия. Вместо хранения каждого пикселя в 2 битах используйте индексированные цвета. Пример: если на экране только черный, белый и серый, достаточно 1 бита на пиксель. Реализация:

  1. Создайте массив индексов (1 байт на 8 пикселей).
  2. Храните палитру отдельно (3 байта для 4 цветов).
  3. При передаче разверните индексы в полные 2-битные значения.

Экономия памяти – до 50% при ограниченном наборе цветов.

Оптимизируйте порядок передачи данных. Контроллер EPD 203 ожидает пиксели построчно, слева направо, сверху вниз. Если ваш буфер организован иначе (например, по столбцам), пересортируйте его перед отправкой. Используйте memcpy с предвычисленными смещениями или заранее подготовленный lookup table для ускорения перестановки.

Кэшируйте неизменяемые элементы интерфейса. Разделите буфер на статическую и динамическую части. Статическая часть (логотипы, рамки) записывается один раз при инициализации и не обновляется. Динамическая часть (текст, графики) перерисовывается частично. Пример структуры буфера:

  • Статический слой: 5808 байт (полный кадр).
  • Динамический слой: 1000 байт (область 100×40 пикселей).
  • При обновлении передавайте только динамический слой.

Используйте аппаратное ускорение SPI. На микроконтроллерах STM32 или ESP32 включите DMA для передачи буфера без участия CPU. Настройте SPI на максимальную скорость (4 МГц для EPD 203) и используйте 16-битный режим передачи, если контроллер поддерживает. Пример для STM32:

SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // 4 МГц при 32 МГц PCLK
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &SPI_InitStructure);

Последний этап – сжатие данных. Алгоритмы RLE (Run-Length Encoding) эффективны для монохромных изображений. Пример: последовательность из 100 белых пикселей кодируется как 0xFF 0x64 (цвет + длина). Для 4-градационных дисплеев используйте модифицированный RLE с разделением по цветам. Ограничение: сжатие оправдано только при коэффициенте >1.5, иначе накладные расходы на распаковку съедают выигрыш.

Реализация частичного обновления содержимого дисплея

Реализация частичного обновления содержимого дисплея

Перед частичным обновлением очистите целевую область с помощью display.fillRect(), иначе останутся артефакты от предыдущего содержимого. Для монохромных дисплеев используйте цвет GxEPD_WHITE или GxEPD_BLACK. При работе с 3-цветными моделями (например, EPD 2.13″ b/w/r) учитывайте, что частичное обновление поддерживает только черный и белый цвета – красный требует полной перерисовки.

При реализации анимации или прокрутки текста разбивайте область на минимальные сегменты. Например, для горизонтальной прокрутки строки шириной 200 пикселей обновляйте по 20 пикселей за кадр с задержкой 200 мс. Это снижает нагрузку на контроллер и предотвращает мерцание. Для вертикального скроллинга используйте метод display.scroll() с последующим частичным обновлением только новой строки.

Обработка ошибок связи и восстановление работы EPD 203

Обработка ошибок связи и восстановление работы EPD 203

При возникновении ошибок связи контроллер EPD 203 возвращает коды состояния в регистре 0x0F. Значение 0x00 указывает на успешное выполнение команды, 0x01 – тайм-аут ожидания готовности, 0x02 – ошибка контрольной суммы. Для чтения регистра используйте команду 0x2F с последующим чтением одного байта. Пример кода на C для STM32:

uint8_t read_status() {
uint8_t cmd = 0x2F;
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1, &cmd, 1, HAL_MAX_DELAY);
uint8_t status;
HAL_SPI_Receive(&hspi1, &status, 1, HAL_MAX_DELAY);
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);
return status;
}

Если регистр состояния возвращает 0x01, выполните сброс контроллера командой 0x12 (SWRESET) и повторите инициализацию. При повторных сбоях проверьте конфигурацию SPI: режим 0 (CPOL=0, CPHA=0), 8-битный формат данных. Для плат на базе ESP32 используйте режим SPI_MASTER с параметрами:

Параметр Значение
clock_speed_hz 2000000
mode SPI_MODE0
spics_io_num GPIO_NUM_5
queue_size 7

При ошибках контрольной суммы (0x02) убедитесь, что данные передаются в правильном порядке: старший байт первым. EPD 203 ожидает 16-битные слова в формате big-endian. Для проверки целостности данных используйте CRC-8 с полиномом 0x07. Пример расчета контрольной суммы для массива данных:

uint8_t calculate_crc(uint8_t *data, uint16_t length) {
uint8_t crc = 0x00;
for (uint16_t i = 0; i < length; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x80) crc = (crc << 1) ^ 0x07;
else crc <<= 1;
}
}
return crc;
}

Восстановление после критических сбоев требует полной переинициализации дисплея. Последовательность команд для сброса и повторной настройки:

  1. Отправьте команду 0x12 (SWRESET) и дождитесь готовности (регистр 0x0F = 0x00).
  2. Настройте разрешение: команда 0x61 с параметрами 0x0190 (400) и 0x012C (300).
  3. Установите драйвер: команда 0x01 с параметрами 0x03 (LUT от контроллера), 0x00, 0x2B, 0x2B, 0x09.
  4. Загрузите LUT через команду 0x32 с массивом из 159 байт (стандартный LUT для полного обновления).

При частых сбоях добавьте программный тайм-аут на операции чтения/записи. Для STM32 используйте HAL_SPI_Transmit_IT с тайм-аутом 100 мс. Если операция не завершилась, выполните сброс SPI через __HAL_SPI_DISABLE и __HAL_SPI_ENABLE. Для ESP32 аналогично используйте spi_device_polling_end с тайм-аутом 50 мс.

Питание EPD 203 критично для стабильной работы. При использовании батарейного питания добавьте конденсатор 100 мкФ между VCC и GND для сглаживания пульсаций. Если дисплей подключен через длинные провода, установите ферритовые кольца на линии питания и SPI. При работе в условиях электромагнитных помех снизьте тактовую частоту SPI до 1 МГц и увеличьте задержки между командами до 5 мс.

Для диагностики аппаратных проблем используйте логический анализатор на линиях SPI. Проверьте сигналы на соответствие спецификации: длительность импульсов CLK не менее 50 нс, фронты сигналов не более 10 нс. При обнаружении "плавающих" уровней на линиях MISO/MOSI добавьте подтягивающие резисторы 10 кОм к VCC. Если ошибки сохраняются, замените контроллер EPD 203 – деградация чипа после 10 000 циклов обновления может вызывать нестабильную работу.

Создание пользовательских шрифтов и графических элементов

Для EPD 203 с разрешением 200×96 пикселей оптимальны шрифты с высотой символов 8–16 пикселей. Используйте инструменты FontForge или Glyphs Mini для редактирования глифов в формате BDF или PCF, затем конвертируйте в массив байтов через bdf2c или fontconvert из библиотеки GxEPD. Пример структуры шрифта для латиницы: каждый символ кодируется 1-битным массивом (1 – пиксель включён), где первый байт задаёт ширину, а последующие – строки растра. Для кириллицы увеличьте ширину до 12 пикселей, чтобы избежать наложения символов при отрисовке.

Графические элементы (иконки, разделители) храните в виде статических массивов const uint8_t с предварительным сжатием через RLE или PackBits. Для EPD 203 критично минимизировать объём данных: иконка 16×16 пикселей в несжатом виде занимает 32 байта, после сжатия – 10–15 байт. При проектировании учитывайте особенности дисплея: избегайте тонких линий (менее 2 пикселей), так как они могут исчезать при обновлении экрана. Для динамических элементов используйте заранее подготовленные спрайты с альфа-каналом, реализованным через битовые маски.

Интеграция шрифтов и графики в код требует прямого обращения к буферу дисплея. Для шрифтов напишите функцию drawChar(), которая принимает координаты, код символа и указатель на шрифт, затем последовательно отрисовывает байты растра в буфер. Для графики используйте drawBitmap() с параметрами смещения и прозрачности. Пример оптимизации: кешируйте часто используемые элементы в RAM, если контроллер позволяет, – это сократит время обновления на 30–40%. Тестируйте каждый элемент на реальном устройстве: EPD 203 может искажать контраст при отрисовке мелких деталей.

Тестирование и отладка кода на реальном устройстве

Тестирование и отладка кода на реальном устройстве

Первым шагом после загрузки прошивки на EPD 203 проверьте инициализацию дисплея через логи UART. Используйте команду Serial.begin(115200) в setup() и отправляйте отладочные сообщения перед каждым критическим этапом: сброс контроллера (EPD_2IN9_V2_Reset()), настройка регистров (EPD_2IN9_V2_SendCommand(0x01)), передача данных изображения. Для EPD 203 характерны задержки при обновлении – добавьте delay(500) после EPD_2IN9_V2_Display(), чтобы избежать артефактов из-за преждевременного перехода в спящий режим. Если экран остаётся белым, проверьте питание: напряжение на VCC должно быть стабильно 3.3В, а ток потребления в момент обновления – не ниже 20 мА.

Для диагностики проблем с отображением используйте тестовые паттерны. Создайте массив uint8_t testPattern[5000], заполните его чередующимися байтами 0xAA и 0x55 (шахматная доска), и передайте через EPD_2IN9_V2_SendData(). Если на экране видны горизонтальные полосы – проблема в синхронизации SPI (увеличьте делитель частоты до 8 МГц) или повреждён кабель. При искажении изображения проверьте порядок байтов: EPD 203 ожидает данные в формате LSB-first для каждого пикселя. Для отладки таймингов подключите логический анализатор к линиям SPI и сравните сигналы с даташитом – задержка между командами 0x10 (запись данных) и 0x13 (обновление) должна быть не менее 2 мс.

Ссылка на основную публикацию