Запускаем вывод текста и изображений на OLED-дисплеи JIRUN через UART и SPI

24 июня

системы безопасностиавтоматизациялабораторные приборыинтернет вещейJIRUNстатьяоптоэлектроникаUARTSPIДисплейOLED

Александр Калачев (г. Барнаул)

Подробная иллюстрированная практическая инструкция (включающая примеры кода) по работе с недорогими и качественными OLED-дисплеями и дисплейными модулями с последовательными интерфейсами SPI/UART производства китайской компании Jirun.

Современные технологии отображения информации используют как миниатюрные устройства, так и информационные табло в несколько десятков квадратных метров. Это стало возможным благодаря развитию светодиодов и  средств управления ими, в числе которых – контроллеры, светодиоды с интегрированными контроллерами, панели и матрицы. В качестве общей тенденции можно отметить общее повышение степени интеграции в связке «матрица отображения + контроллер», а также увеличение функциональности контроллеров.

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

OLED-дисплеи выгодно отличаются от LCD большей контрастностью («истинный черный») и возможностью выбора цветового решения при сравнимом энергопотреблении. Изображение на  OLED дисплее хорошо читаемо под любым углом без потери качества.

Для OLED-дисплеев заметен тренд на упрощение вывода информации (изображения/текста) – встроенные знакогенераторы, переход на последовательные интерфейсы и упрощенное управление.

Дисплеи Jirun 

Одной из компаний, активно разрабатывающей OLED-дисплеи и открытой к сотрудничеству с РФ является китайская fabless-компания Shenzhen Jirun Industrial Co., Ltd. (Jirun), [1].

Рис. 1. OLED-дисплей Jirun

Рис. 1. OLED-дисплей Jirun

Компания предлагает OLED-дисплеи  и OLED-модули (рисунок 1) семи базовых моделей с диагоналями от 1,54 до 5,5 дюймов (от 128×32 до 256×64 пикселя) в двух вариантах – стандартные для промышленного использования и интеллектуальные с микроконтроллерным управлением – таблица 1.

Таблица 1. Дисплеи JIRUN

Наименование Внешний вид Характеристики
Интеллектуальные символьно-графические дисплеи
JR25664-1A_SPI_Green_3.3V
  • Цвет зеленый
  • Диагональ 5,5 дюйма
  • Разрешение 256х64 точки
  • Питание 3,3 В
  • Размеры 159х50х8 мм
  • Контроллер GT30L32S4W
  • Поддержка кириллицы
  • Интерфейс SPI
JR25664-1A_UART_Green_5V
  • Цвет зеленый
  • Диагональ 5,5 дюйма
  • Разрешение 256х64 точки
  • Питание 5 В
  • Размеры 159х50х8 мм
  • Контроллер GT30L32S4W
  • Поддержка кириллицы
  • Интерфейс UART
JR12832-1A_SPI_Blue_3.3V
  • Цвет синий
  • Диагональ 2,23 дюйма
  • Разрешение 128х32 точки
  • Питание 3,3 В
  • Размеры 67х35х8 мм
  • Контроллер GT30L32S4W
  • Поддержка кириллицы
  • Интерфейс SPI
JR12864-2A_UART_White_5V
  • Цвет белый
  • Диагональ 2,23 дюйма
  • Разрешение 128х64 точки
  • Питание 5 В
  • Размеры 67х35х8 мм
  • Контроллер GT30L32S4W
  • Поддержка кириллицы
  • Интерфейс UART
JR12864-2A_SPI_Yellow_3.3V
  • Цвет желтый
  • Диагональ 2,7 дюйма
  • Разрешение 128х64 точки
  • Питание 3,3 В
  • Размеры 85х58х8 мм
  • Контроллер GT30L32S4W
  • Поддержка кириллицы
  • Интерфейс SPI
JR25664-2A_White
  • Цвет белый
  • Диагональ 3,12 дюйма
  • Разрешение 256х64 точки
  • Питание 5 В
  • Размеры 101х34х8 мм
  • Контроллер GT30L32S4W
  • Поддержка кириллицы
  • Интерфейс UART
JR25664-2A_Green
  • Цвет зеленый
  • Диагональ 3,12 дюйма
  • Разрешение 256х64 точки
  • Питание 3,3 В
  • Размеры 101х34х8 мм
  • Контроллер GT30L32S4W
  • Поддержка кириллицы
  • Интерфейс SPI
Графические дисплеи
JR12864-3
  • Цвет желтый
  • Диагональ 2,42 дюйма
  • Разрешение 128х64 точки
  • Размеры 71х50х7 мм
  • Питание 3,3…5 В
  • Контроллер SSD1309
  • Интерфейсы 8080, 6800, SPI, I2C
  • Замена для WEX012864 и WEO012864

В отличие от традиционных OLED, представленные в таблице модели относятся к классу так называемых интеллектуальных дисплеев – для получения изображения или символа их не требуется программировать, использовать многочисленные регистры или формировать изображение попиксельно.

Особенностями дисплеев Jirun являются поддержка множества шрифтов, что возможно благодаря встроенному знакогенератору GT30L32S4W (относится только к моделям «интеллектуальных» символьно-графических дисплеев, в которых есть кириллица, латиница и китайские иероглифы). Более того, набор управляющих команд позволяет легко отображать и графические объекты, в частности, такие графические примитивы, как линии, многоугольники, окружности, а также менять цвет пера и фона, выбирать текущую страницу символов («выбирать язык»).

Jirun OLED – теория операций

Если не брать во внимание размеры диагоналей и отличия в цветах, дисплеи Jirun представлены размерами 128х32, 128х64 и 256х64 точки и построены на базе графического контроллера GT30L32S4W, работающего под управлением встроенного 32-битного микроконтроллера, который в свою очередь, предоставляет простой внешний программно-аппаратный интерфейс.

Аппаратная часть

Аппаратно дисплеи могут быть подключены по последовательным интерфейсам UART/RS232 или SPI. Текущий активный интерфейс определяется перемычками  на печатной плате модуля – контакт S1 замыкается в случае выбора интерфейса SPI, и разомкнут в случае, если используется интерфейс UART (рисунки 2, 3).

Важно! Для корректной работы по интерфейсу UART перемычка должна быть замкнута перемычка в месте, отмеченном на печатной плате модуля надписью 232/TTL(см. рисунок 3).

Интерфейс UART использует следующие опции: полнодуплексный асинхронный последовательный порт (UART), режим 8N1 (1 начальный бит, 1 конечный бит, 8 бит данных, бит четности отсутствует), скорость передачи данных в диапазоне 1200-921600 бит/с. По умолчанию – скорость передачи данных составляет 115200 бит/с.

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

Запаяв перемычку рядом с надписью 9600 на плате, можно принудительно установить скорость работы UART-интерфейса 9600 бит/с, что и было сделано для дальнейших примеров.

Рис. 2. Дисплей JR12832-1A – с SPI-интерфейсом

Рис. 2. Дисплей JR12832-1A – с SPI-интерфейсом

Рис. 3. Дисплей JR25664-2A – с UART-интерфейсом (и с TTL-уровнями интерфейса)

Рис. 3. Дисплей JR25664-2A – с UART-интерфейсом (и с TTL-уровнями интерфейса)

Режим SPI – 8-разрядный синхронный интерфейс с максимальной тактовой частотой (SCK) 18 мбит/с – рисунок 4.

Рис. 4. Временные диаграммы одной транзакции SPI-интерфейса SPI-OLED дисплея. (режим SPI_MODE0)

Рис. 4. Временные диаграммы одной транзакции SPI-интерфейса SPI-OLED дисплея.
(режим SPI_MODE0)

Все представленные модели дисплеев имеют две группы контактов, расположенных в два или в один ряд на некотором расстоянии друг от друга и принадлежащих UART- или SPI-интерфейсу (таблицы 2, 3, рисунок 5).

Таблица 2. Выводы UART/RS232-интерфейса

Номер контакта Название вывода Тип вывода Описание
Для однорядных разъемов Для двурядных разъемов
1 2 GND Питание Общий вывод питания
2 4 GND Питание Общий вывод питания
3 6 DIN Вход Вывод RXD – вход UART
4 8 DOUT Выход Вывод TXD – выход UART
5 10 NC nc не используется
6 12 BUSY Выход Сигнал занятости устройства* (активный уровень – высокий)
7 14 VIN Питание Плюс питания (3.3/5В)
8 16 VIN Питание Плюс питания (3.3/5В)

Таблица 3. Выводы SPI-интерфейса

Номер контакта Название вывода Тип вывода Описание
Для однорядных разъемов Для двурядных разъемов
1 1 GND Питание Общий вывод питания
2 3 CS Вход Сигнал выбора устройства (chips_elect)
3 5 SCK Вход Входной тактовый сигнал
4 7 DO Выход Последовательный выход данных
5 9 DI Вход Последовательный вход данных
6 11 BUSY Выход Сигнал занятости устройства* (активный уровень – высокий)
7 13 RST Вход Сброс
8 15 VIN Питание Плюс питания (3.3/5В)

* – Поскольку внутри имеется буфер данных емкостью 6 кБ, в обычных приложениях пользователям не нужно отслеживать сигнал занятости, поэтому чаще всего его можно игнорировать/не подключать.

Рис. 5. Распиновка выводов для моделей с двурядным и однорядными расположениями контактов

Рис. 5. Распиновка выводов для моделей с двурядным и однорядными расположениями контактов

Программная часть

Рассмотрим простые примеры работы с SPI/UART-дисплеями Jurin. Для демонстрации взяты дисплеи JR12832-1A_SPI_Blue_3.3V и JR25664-2A_White – первый управляется по SPI, второй по UART. В качестве управляющего контроллера возьмем одну из отладочных плат семейства Arduino – Arduino Due (помимо более чем достаточного количества портов, данная плата имеет выходы питания для подключения как 3,3 В устройств, так и 5 В (Приложение 2). В частности, можно будет одновременно подключить оба дисплея и работать с ними параллельно.

В среде Arduino поддержка последовательных (UART) портов идет непосредственно в ядре системы/среды, для работы с SPI требуется подключить библиотеку:

#include <SPI.h>
Arduino

Схема подключения дисплеев представлена на рисунке 6 .

Рис. 6. Схема подключения дисплеев к Arduino Due

Рис. 6. Схема подключения дисплеев к Arduino Due

Настройка интерфейсов Arduino Due:

Serial.begin(115200);

Serial1.begin(9600);

//========SPI_OLED_INIT=============

pinMode(oled_cs, OUTPUT);

pinMode(oled_reset, OUTPUT);

pinMode(oled_busy, INPUT);

digitalWrite(oled_reset, HIGH);

digitalWrite(oled_reset, LOW);

delay(10);

digitalWrite(oled_reset, HIGH);

SPI.setBitOrder(MSBFIRST);

SPI.begin(oled_cs);

SPI.setClockDivider(oled_cs, 10);
Arduino

UART-дисплей работает на скорости 9600 бит/с и в данном примере дисплей подключен к UART1 платы (Serial1).

Управление дисплеем осуществляется через последовательный порт с помощью  относительно простых команд, которые реализуют функции рисования и отображения символов. При этом, что особенно приятно, формат команд и для SPI- и для UART-интерфейсов одинаков.

Основные возможности интеллектуальных OLED-дисплеев:

  1. Библиотека шрифтов предварительно настроена на заводе-изготовителе и поддерживает набор шрифтов GB2312 (китайские иероглифы – возможно не очень актуальны для РФ, но могут и пригодиться) размерами 12×12,16×16, 24×24 и 32×32 пикселя, и ASCII-символы размерами 6×12, 8×16,12×24,16×32 пикселей;
  2. Встроенные операции управления дисплеем — включение и выключение дисплея, регулировка яркости;
  3. Пользователям необходимо всего лишь отправить простые инструкции на терминал для отображения иероглифов, рисунков, точек, линий, прямоугольников, кругов и других графических примитивов.

Структура команд дисплеев

Протокол управления дисплеями относительно прост, достаточно следовать рекомендациям и соблюдать структуру команд (таблица 4):

[0xFE 0xFD] [Код команды] [Длина данных] [Данные] [0xDD 0xCC 0xBB 0xAA]
Arduino

Компоненты команды:

1) Заголовок команды – 0xFD 0xFE длина поля – 2 байта, должен быть отправлен перед отправкой любой команды.

2) Код команды – длина 1 байт. Выделяют четыре типа команд:

  1. Системные – первая тетрада (старшая) равна – 0x1;
  2. Графические – первая тетрада – 0x2;
  3. Текстовая – первая тетрада – 0x3;
  4. Отображения изображения — первая тетрада равна 0x4.

Вторая тетрада байта кода – номер команды.

3) Длина данных: количество байт данных, длина поля 2 байта, [старший байт длины] + [младший байт длины данных]. Максимальный размер данных равен 2000 байт, таким образом, длина данных находится в диапазоне от [0x00][0x00] до [0x07][0xd0] в зависимости от объема данных.

4) Данные: все байты между кодом команды и кодом завершения в совокупности называются данными. Конкретное определение каждого байта в данных зависит от различных кодов команд. Для некоторых команд данные не требуются.

5) Поле завершения команды («хвостовик»/код завершения) – 4 байта – 0xDD 0xCC 0хBB 0xAA: конечный код,  Только после получения дисплеем 4 байт заголовка команда может считаться завершенной.

Таблица 4. Системные команды

Команда Код команды Данные команды Описание
Тест связи 0х11 Нет Если подключение к дисплею успешно, он вернет два байта – номер версии прошивки и текущую скорость передачи данных
Команда:
fe fd 11 00 00 dd cc bb aa
Ответ:
0a 0a
– 0а – номер версии (текущая реальная 0х01)– 0а – скорость передачи данных терминала – соответствует 115200 кбит/с
Установка скорости передачи данных 0х12 Код скорости передачи данных После успешной настройки через последовательный порт будет возвращен код скорости передачи данных в бодах. Скорость передачи данных по умолчанию составляет 115200 бит/с.
Коды скоростей:
0x01-1200, 0x02-2400, 0x03-4800, 0x04-9600, 0x05-14400, 0x06-19200, 0x07-38400, 0x08-56000, 0x09-57600, 0x0a-115200, 0x0b-230400, 0x0c-460800, 0x0d-921600
Команда:
fe fd 12 00 01 0a dd cc bb aa
Ответ:
0a
Установка таймаута 0х13 Таймаут Значение таймаута равно одному байту и находится в диапазоне от 20 до 255. Если передача данных прекращается более чем на указанное время, буфер очищается. Значение по умолчанию – 50 мс, единица измерения – мс.
Команда:
fe fd 13 00 01 ff dd cc bb aa
Включить дисплей 0х14 Нет Включение дисплея.
Команда:
fe fd 14 00 00 dd cc bb aa
Выключить дисплей 0х15 Нет Выключение дисплея.
Команда:
fe fd 15 00 00 dd cc bb aa
Настройка яркости 0х16 Уровень яркости Установка текущей яркости дисплея, длина – один байт, диапазон 0x00-0xff.
0x00 – минимальная яркость
0x7f – среднее значение яркости
0xff – максимальное значение яркости
Команда:
fe fd 16 00 01 80 dd cc bb aa

Работа с дисплеями Jirun – немного кода 

Для большего комфорта зададим символьное представление команд дисплеям:

byte cmd_link_test = 0x11;

byte cmd_speed = 0x12;

byte cmd_timeout = 0x13;

byte cmd_dspl_on = 0x14;

byte cmd_dspl_off = 0x15;

byte cmd_dspl_bright = 0x16;

byte empty[]={};
Arduino

Массивы с префиксом и суффиксом (окончанием) команд:

byte prefix[] = {0xFE, 0xFD};

byte suffix[] = {0xDD, 0xCC, 0xBB, 0xAA};
Arduino

Для управления потоком команд/данных и сигнализации состояния дисплея можно использовать его выводы занятости (BUSY) и сброса (RESET). В нормальном режиме работы на вывод RESET можно или не подавать сигнал совсем, или подавать высокий уровень. В случае слишком быстрой подачи команд или их неверной последовательности, а также в случае зависания встроенной прошивки дисплея он выдает высокий уровень на BUSY. При слишком длительном его присутствии на линии (более 3…5 секунд) чаще всего речь идет о том, что встроенный контроллер дисплея находится в нештатном режиме работы. Перевод дисплея в исходное состояние осуществляется кратковременной подачей низкого уровня на его линию сброса (RESET). Вывод RESET доступен в ряду выводов дисплея, ответственных за SPI-интерфейс (дисплеи чувствительны к сигналу на RESET вне зависимости от того, в каком режиме SPI/UART-дисплей работает.

В текущем примере распределение выводов следующее:

//для SPI-дисплея

int oled_cs = 10;

int oled_busy = 9;

int oled_reset = 8;

//для UART-дисплея

int oled_uart_busy = 7;
Arduino

Базовый принцип управления дисплеями – пересылка префикса, передача кода команды, передача длины данных команды, передача данных команды («тела»). Само тело команды формируется заранее, как массив данных (массив байт) – можно, в принципе, оперировать и типом string (строками), но поскольку команды не имеют представления в виде текстовых строк, в примере в основном используются массивы байт. После передачи каждого байта команды необходимо выдерживать паузу (примерно 1 мс – но не более значения таймаута 50 мс по умолчанию). Полный код примера приведен в приложении 3.

Унифицированный код посылки команды

SPI
// for commands and vector drawing

void SPI_send_cmd(byte command, unsigned int data_len, byte data[])

{

byte len[]={byte(data_len>>8),

byte(data_len & 0xFF)};

byte ack;

for(int i=0;i<sizeof(prefix);i++){

ack=SPI.transfer(oled_cs, prefix[i]);

delay(pause);

}

ack=SPI.transfer(oled_cs, command); delay(pause);

for(int i=0;i<sizeof(len);i++){

ack=SPI.transfer(oled_cs, len[i]); delay(pause);

}

for(int i=0;i<data_len;i++){

ack=SPI.transfer(oled_cs, data[i]); delay(pause);

}

for(int i=0;i<sizeof(suffix);i++){

ack=SPI.transfer(oled_cs, suffix[i]); delay(pause);

}

}
Arduino
UART
//for commands and vector drawing

void UART_send_cmd(byte command, unsigned int data_len, byte data[])

{

byte len[]={byte(data_len>>8),

byte(data_len & 0xFF)};

byte ack;

for(int i=0;i<sizeof(prefix);i++){

ack=Serial1.write(prefix[i]); delay(pause);

}

ack=Serial1.write(command); delay(pause);

for(int i=0;i<sizeof(len);i++){

ack=Serial1.write(len[i]); delay(pause);

}

for(int i=0;i<data_len;i++){

ack=Serial1.write(data[i]); delay(pause);

}

for(int i=0;i<sizeof(suffix);i++){

ack=Serial1.write(suffix[i]); delay(pause);

}

}
Arduino

Пример: Установка значения яркости и очистка экрана (точнее – заполнение экрана фоновым значением):

SPI_send_cmd(cmd_dspl_bright, sizeof(bright), bright);

SPI_send_cmd(clear_screen, sizeof(empty), empty);

UART_send_cmd(cmd_dspl_bright, sizeof(bright), bright);

UART_send_cmd(clear_screen, sizeof(empty), empty);
Arduino

Аналогично формируются команды на управление питанием матрицы OLED-дисплея:

SPI_send_cmd(cmd_dspl_off, sizeof(empty), empty);

UART_send_cmd(cmd_dspl_off, sizeof(empty), empty);

delay(5000);

SPI_send_cmd(cmd_dspl_on, sizeof(empty), empty);

UART_send_cmd(cmd_dspl_on, sizeof(empty), empty);
Arduino

Вывод текста

Система экранных координат – традиционная для всех графических устройств вывода: начало координат в левом верхнем углу (рисунок 7). Она едина для вывода текста и для вывода графических элементов.

Рис. 7. Система экранных координат дисплеев Jirun

Рис. 7. Система экранных координат дисплеев Jirun

Отображение текста также выполняется достаточно простой операцией – в командах указываются экранные координаты для вывода символов и сама текстовая строка. Цвета переднего плана и фона текста настраиваются с помощью инструкции настройки палитры. Фон по умолчанию равен 0x0, а цвет переднего плана – 0xf после запуска.

Команды вывода текста показаны в таблице 5.

Таблица 5. Команды вывода текста

Команда Код инструкции Данные команды Описание
Отобразить текст 0х31 X+Y+String Отображение строки ASCII в виде решетки размером 6х12 на половину ширины или отображение внутреннего кода GB2312 (иероглифы) на всю ширину решетки размером 12х12.
(X, Y) – это начальная позиция первого символа. Когда заполнится одна строка, она будет автоматически перенесена и отображена.
0х32 Аналогично, но с символами 8х16 ASCII и 16х16 для GB2312
0х33 Аналогично, но с символами 12х24 ASCII и 12х24 для GB2312
0х34 Аналогично, но с символами 16х32 ASCII и 32х32 для GB2312
Отобразить текст в инверсном виде (цвет фона – это цвет шрифта, а базовый цвет – это цвет переднего плана) 0х35 Отображение строки ASCII в виде решетки размером 6х12 на половину ширины или отображение внутреннего кода GB2312 (иероглифы) на всю ширину решетки размером 12х12.
(X, Y) – это начальная позиция первого символа. Когда заполнится одна строка, она будет автоматически перенесена и отображена.
0х36 Аналогично, но с символами 8х16 ASCII и 16х16 для GB2312
0х37 Аналогично, но с символами 12х24 ASCII и 12х24 для GB2312
0х38 Аналогично, но с символами 16х32 ASCII и 32х32 для GB2312
Пример:
Вывод строки «Jirun Industry»: шрифтом 16х16 с координат (0, 0) – координаты представлены двумя байтами:
fe fd 32 00 12 00 00 00 00 4a 69 72 75 6e 20 49 6e 64 75 73 74 72 79 dd cc bb aa

Символьные обозначения команд:

byte text_6_12 = 0x31;

byte text_8_16 = 0x32;

byte text_12_24 = 0x33;

byte text_32_32 = 0x34;

byte inv_text_6_12 = 0x35;

byte inv_text_8_16 = 0x36;

byte inv_text_12_24 = 0x37;

byte inv_text_32_32 = 0x38;
Arduino

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

Строки могут состоять исключительно из ASCII символов, тогда их удобнее задавать именно, как строки (тип string). Строки могут состоять из расширенных наборов символов, при этом символы задаются двумя байтами – кодовая страница и символ, в этом случае их проще задавать как байтовые массивы, причем могут чередоваться расширенные символы и ASCII (единственное замечание – пиксельные размеры символов не совпадают по ширине, что может сказываться на внешнем виде отображаемой строки.

Вывод ASCII-строк

SPI
void SPI_send_ASCII_text(byte command, unsigned int x, unsigned int y,
unsigned int data_len, String data){

//unsigned int data_len = sizeof(data);

data_len += 4;

byte len[]={byte(data_len>>8), byte(data_len & 0xFF)};

byte ack;

//--------send prefix-------------------------------

for(int i=0;i<sizeof(prefix);i++){

ack=SPI.transfer(oled_cs, prefix[i]); delay(pause);

}

//--------send cmd-------------------------------

ack=SPI.transfer(oled_cs, command); delay(pause);

//--------send lenght-------------------------------

for(int i=0;i<sizeof(len);i++){

ack=SPI.transfer(oled_cs, len[i]); delay(pause);

}

//-------send coordinates-------------------------

ack=SPI.transfer(oled_cs, byte(x>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(x & 0xff)); delay(pause);

ack=SPI.transfer(oled_cs, byte(y>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(y & 0xff)); delay(pause);

//-------send text----------------------------------------

for(int i=0;i<data_len;i++){

ack=SPI.transfer(oled_cs, data[i]); delay(pause);

}

//--------send suffix-------------------------------

for(int i=0;i<sizeof(suffix);i++){

ack=SPI.transfer(oled_cs, suffix[i]); delay(pause);

}

}
Arduino

 

UART
void UART_send_ASCII_text(byte command, unsigned int x, unsigned int y,
unsigned int data_len, String data){

//unsigned int data_len = sizeof(data);

data_len += 4;

byte len[]={byte(data_len>>8), byte(data_len & 0xFF)};

byte ack;

//--------send prefix-------------------------------

for(int i=0;i<sizeof(prefix);i++){

ack=Serial1.write(prefix[i]); delay(pause);

}

//--------send cmd-------------------------------

ack=Serial1.write(command); delay(pause);

//--------send lenght-------------------------------

for(int i=0;i<sizeof(len);i++){

ack=Serial1.write(len[i]); delay(pause);

}

//-------send coordinates-------------------------

ack=Serial1.write(byte(x>>8)); delay(pause);

ack=Serial1.write(byte(x & 0xff)); delay(pause);

ack=Serial1.write(byte(y>>8)); delay(pause);

ack=Serial1.write(byte(y & 0xff)); delay(pause);

//-------send text----------------------------------------

for(int i=0;i<data_len;i++){

ack=Serial1.write(data[i]); delay(pause);

}

//--------send suffix-------------------------------

for(int i=0;i<sizeof(suffix);i++){

ack=Serial1.write(suffix[i]); delay(pause);

}

}
Arduino

 

Пример: выведем строку ASCII-символов самым мелким шрифтом, начиная с координат (1; 1):

String str_text1="This is just ASCII string for test. We put it from x=1;
y=1 coordinates";//18

// ASCII text

SPI_send_ASCII_text(text_6_12, 1, 1, str_text1.length(), str_text3);

UART_send_ASCII_text(text_6_12, 1, 1, str_text1.length(), str_text1);
Arduino

В случае, если текст строки не вмещается в ширину экрана, он будет автоматически перенесен на следующую строку в позицию по координате х, как и задано в команде вывода строки, и на высоту символа ниже по координате y – рисунок 8.

Рис. 8. Пример вывода ASCII-строк

Рис. 8. Пример вывода ASCII-строк

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

Символы расширенного набора выводятся также командой текстового вывода (коды – 0х31_0х38), при этом указываются начальные координаты вывода (в контексте этой команды они не экранные/пиксельные, а символьные, в зависимости от размера шрифта). Если коды символов менее 0х80, дисплей выводит обычные ASCII-символы, и код символа имеет длину один байт. Если после координат в поле данных команды начинаются значения 0xA1 и более, код символа обрабатывается, как двухбайтный. Для упрощения можно считать, что первый байт символа – номер символьной страницы/таблицы, второй, собственно – код символа в ней (см. приложение 1).

Встроенный контроллер GB2312 имеет достаточно богатый набор символьных таблиц (таблица 6) – ASCII-символы, специальные символы, несколько языковых таблиц, таблицы иероглифов (ввиду их специфичности, а также относительно редкого интереса к ним в РФ, заострять внимание на них не будем) – обозначим их все, как «символы расширенного набора».

Таблица 6. Доступные шрифты и наборы символов

Шрифт Набор символов Количество
символов
Номер рисунка с кодами и внешним видом (из приложения 1)
8×16 ASCII ASCII 96 1
12×24 ASCII ASCII 96 1
16×32 ASCII ASCII 96 1
12×12 GB2312 Расширенный набор символов GB2312 6763+846 2-8
15×16 GB2312 Расширенный набор символов GB2312 6763+846 2-8
24×24 GB2312 Расширенный набор символов GB2312 6763+846 2-8
32×32 GB2312 Расширенный набор символов GB2312 6763+846 2-8

Вывод строк из произвольного набора символов абсолютно аналогичен выводу ASCII, только в качестве данных передается массив байт, а не строка.

SPI
void SPI_send_text(byte command, unsigned int x, unsigned int y, unsigned int data_len,
byte data[]){}
Arduino
UART
void SPI_send_text(byte command, unsigned int x, unsigned int y, unsigned int data_len,
byte data[]){}
Arduino

Сформируем классическую строку «Привет, мир!» – в данной строке есть русские символы и обычные ASCII. Для вывода данной строки надо сформировать байтовый массив, содержащий смесь символов расширенного набора (для русского алфавита кодовая страница – A7) и символов “,”, “ ” и “!”.

Массив байт формируется согласно кодовой таблице (рисунок 9).

Рис. 9. Формирование массива для строки русского текста со знаками препинания (символы ASCII)

Рис. 9. Формирование массива для строки русского текста со знаками препинания (символы ASCII)

byte text1[]={0xA7,0xB1, 0xA7,0xE2, 0xA7,0xDA, 0xA7,0xD3, 0xA7,0xD6, 0xA7,0xE4,

',', ' ',

0xA7,0xDE, 0xA7,0xDA, 0xA7,0xE2, '!'

};
Arduino

Выведем ее более крупным шрифтом, чем предыдущие строки (рисунок 10).

// common text

SPI_send_text(text_8_16, 10, 1, sizeof(text1), text1);

UART_send_text(text_8_16, 10, 10, sizeof(text1), text1);
Arduino

Рис. 10. Вывод расширенного набора символов

Рис. 10. Вывод расширенного набора символов

Следует отметить, что знакоместа символов из расширенных наборов относительно широкие – поэтому текст из них выглядит несколько разреженным. Сочетание ASCII и расширенных символов выглядит приемлемо только для мелких и средних шрифтов – для более крупных возможны заметные смещения.

Пример заполнения поля дисплеев длинной строкой – на рисунке 11.

byte alf1[]={

0xa7,0xd1, 0xa7,0xd2, 0xa7,0xd3, 0xa7,0xd4, 0xa7,0xd5, 0xa7,0xd6, 0xa7,0xd7, 0xa7,0xd8,
0xa7,0xd9, 0xa7,0xda,

0xa7,0xdb, 0xa7,0xdc, 0xa7,0xdd, 0xa7,0xde, 0xa7,0xdf, 0xa7,0xe0, 0xa7,0xe1, 0xa7,0xe2,
0xa7,0xe3, 0xa7,0xe4,

0xa7,0xe5, 0xa7,0xe6, 0xa7,0xe7, 0xa7,0xe8, 0xa7,0xe9, 0xa7,0xea, 0xa7,0xeb, 0xa7,0xec,
0xa7,0xed, 0xa7,0xee,

0xa7,0xef, 0xa7,0xf0, 0xa7,0xf1

};

SPI_send_text(text_6_12, 0, 0, sizeof(alf1), alf1);

UART_send_text(text_6_12, 0, 00, sizeof(alf1), alf1);
Arduino

и т.д.

Рис. 11. Пример заполнения поля дисплеев длинной строкой (сСтрока всех символов русского алфавита)

Рис. 11. Пример заполнения поля дисплеев длинной строкой (строка всех символов русского алфавита)

Несколько уплотнить вывод символов можно «вручную» – выводя символы по одному с программной коррекцией координат вывода следующего символа строки, со смещением на пустые пиксели символов (для такой операции проще переписать функцию вывода текста на работу с массивами типа unsigned int. На рисунке 12 – пример попытки такого «уплотнения» со шрифтами 16*16 (первая строка – обычный вывод, вторая строка – вывод символов по одному со сдвигом на 4 пикселя влево) и со шрифтом 12*12 (первая строка – обычный вывод, вторая строка – вывод символов по одному со сдвигом на 2 пикселя влево):

UART_send_text(text_8_16, 0, 0, sizeof(text1), text1);

UART_send_symbol(text_8_16, (16-4)*0, 16, 1, text3[0]);

UART_send_symbol(text_8_16, (16-4)*1, 16, 1, text3[1]);

UART_send_symbol(text_8_16, (16-4)*2, 16, 1, text3[2]);

UART_send_symbol(text_8_16, (16-4)*3, 16, 1, text3[3]);

UART_send_symbol(text_8_16, (16-4)*4-1, 16, 1, text3[4]);

UART_send_symbol(text_8_16, (16-4)*5-2, 16, 1, text3[5]);

UART_send_text(text_6_12, 0, 32, sizeof(text1), text1);

UART_send_symbol(text_6_12, (13-2)*0, 48, 1, text3[0]);

UART_send_symbol(text_6_12, (13-2)*1, 48, 1, text3[1]);

UART_send_symbol(text_6_12, (13-2)*2, 48, 1, text3[2]);

UART_send_symbol(text_6_12, (13-2)*3, 48, 1, text3[3]);

UART_send_symbol(text_6_12, (13-2)*4, 48, 1, text3[4]);

UART_send_symbol(text_6_12, (13-2)*5, 48, 1, text3[5]);
Arduino

Рис. 12. Уплотнение при выводе символов расширенного набора

Рис. 12. Уплотнение при выводе символов расширенного набора

Но подобный метод, особенно для мелкого шрифта, требует для некоторых символов индивидуальной коррекции координат вывода символа.

Вывод графики

Векторная графика

Дисплеи поддерживают вывод как векторной, так и пиксельной графики. Группа команд векторной графики представлена в таблице 7.

Таблица 7. Графические команды

Команда Код инструкции Данные команды Описание
Настройка цветовой палитры 0х21 FColor + BColor FColor – это оттенки серого переднего плана, а BColor – оттенки серого фона, оба имеют размер 1 байт.
Цвет, заданный этой командой, будет использоваться в качестве оттенков серого переднего плана и фона для таких команд, как отображение строк и рисование. Диапазон значений 0…15.
Установка для палитры оттенков серого фона – значение (0x00), а для палитры оттенков серого переднего плана – значение (0x0f).
Команда:
fe fd 21 00 02 0f 00  dd cc bb aa
Очистка экрана 0х22 Нет Заполняет весь экран фоновым цветом.
Команда:
fe fd 22 00 00 dd cc bb aa
Отрисовать точки 0х23 (x0+y0)+(x1+y1)+…+(xn+yn) Отрисовывает последовательность точек, заданных координатами (x0+y0)+(x1+y1)+…+(xn+yn) с заданным оттенком переднего плана.
Пример:
– отрисовать точки с координатами — (00 05, 00 30), (00 10, 00 20), (00 15, 00 39):
fe fd 23 00 0c (00 05 00 30) (00 10 00 20) (00 15 00 39) dd cc bb aa
Нарисовать полилинию 0х24 (x0+y0)+(x1+y1)+…+(xn+yn) Рисует полилинию/ломанную линию, узлы которой заданы последовательностью координат (x0+y0)+(x1+y1)+…+(xn+yn) , может быть также использована для отрисовки многоугольников.
Пример:
Треугольник с координатами (00 14,00 14), (00 50,00 3a), (00 32,00 2a), (00 14,00 14)
fe fd 24 00 10 [(00 14 00 14) [(00 50 00 3a) [(00 32 00 2a) (00 14 00 14)] dd cc bb aa
Нарисовать треугольник или заполненную фоновым цветом треугольную область 0х25

Мх1+(x0+y0)+(x1+y1)+ (x2+y2) +…
+ Мхn+(x0n+y0n)+(x1n+y1n)+ (x2n+y2n)

Рисует треугольник или треугольную область (или несколько), заданную последовательностью координат.
Байты «Мх» задают, будет ли отрисован только контур треугольника (0х0), или треугольная область (0х1).
Пример:
Нарисовать треугольную рамку с (00 14, 00 0c) в качестве первой точки, (00 5e, 00 20) в качестве второй точки и (00 30, 00 38) в качестве конечной точки.
fe fd 25 00 0d [00 (00 14 00 0c) (00 5e 00 20) (00 30 00 38)] dd cc bb aa
Нарисовать прямоугольник или заполненную фоновым цветом прямоугольную область 0х26

(M1+Xs1+Ys1+Xe1+Ye1)+…… +
(Mn+Xsn+Ysn+Xen+Yen)

Рисует прямоугольную рамку или область (или несколько), верхняя левая вершина которой равна (Xsi, Ysi), а нижняя правая вершина равна (Xei, Yei), способом, указанным в байте Mi, где M – 1 байт:
M=0x00 прямоугольная рамка;
M=0x01 построение прямоугольная область.
Нарисовать прямоугольник с верхней левой вершиной (00 50,00 20) и нижней правой вершиной (00 90,00 30):
fe fd 26 00 12 [00 (00 30 00 10) (00 90 00 20)] [01 (00 50 00 20) (00 90 00 30)] dd cc bb aa
Нарисовать окружность или круг заполненный фоновым цветом 0х27

(M1+X1+Y1+R1)+…… + (Mn+Xn+Yn+Rn)

Рисует окружность или круг с центром в (Xi, Yi) и радиусом Ri (M и Ri имеют размерность один байт):
M=0x00 – рисует окружность;
M=0x01 – рисует круг
Пример:
Нарисовать круг с центром по координатам (00 95, 00 24) и радиусом 5 и окружность с центром в точке (00 14,00 15) и радиусом 5:
fe fd 27 00 0c [01 (00 95 00 24) 05 ] [00 (00 14 00 15) 05] dd cc bb aa
Нарисовать эллипс или эллиптическую область заполненную фоновым цветом 0х28

(M1+Xs1+Ys1+Xe1+Ye1)+…… + (Mn+Xsn+Ysn+Xen+Yen)

Рисует эллипс (контур или заполненную эллиптическую область) с верхней левой вершиной (Xsi, Ysi), нижней правой вершиной (Xei, Yei). Mi (один байт) определяет стиль:
M=0x00 рисует контур эллипса;
M=0x01 рисует закрашенную эллиптическую область.
Пример:
Эллипс с (00 30,00 10) в качестве верхней левой точки, (00 90,00 20) в качестве нижней правой точки, закрашенный эллипс с (00 50,00 20) в качестве верхней левой точки и (00 90,00 30) в качестве нижней правой точки: fe fd 28 00 12 [00 (00 30 00 10) (00 90 00 20)] [01 (00 50 00 20) (00 90 00 30)] dd cc bb aa

Символьные обозначения для группы команд векторной графики:

byte palette = 0x21;

byte clear_screen = 0x22;

byte points = 0x23;

byte polyline = 0x24;

byte triangle = 0x25;

byte rectangle = 0x26;

byte circle = 0x27;

byte ellips = 0x28;
Arduino

Переменные для хранения настроек яркости и палитры дисплеев:

byte bright[]={0xff};

byte pal[]={0x0f,0x00}; // text/fon
Arduino

Код функций SPI_send_cmd и UART_send_cmd подачи команд управления дисплеем также хорошо подходит для отрисовки графических примитивов (круги, прямоугольники, треугольники).

Пример задания окружности и круга с центрами по координатам (0;21) и радиусами 2 и 4 пикселя:

byte circl1[]={01, 0,21, 0,15, 2,   00, 0,21, 0,15, 4};
Arduino

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

SPI
// for POLYLINE drawing--------------------------------------

void SPI_send_poly(byte command, unsigned int data_len, unsigned int data[]){

unsigned int dlen = data_len / sizeof(int);

byte len[]={byte(2*dlen>>8), byte(2*dlen & 0xFF)};

byte ack;

for(int i=0;i<sizeof(prefix);i++){

ack=SPI.transfer(oled_cs, prefix[i]); delay(pause);

}

ack=SPI.transfer(oled_cs, command); delay(pause);

for(int i=0;i<sizeof(len);i++){

ack=SPI.transfer(oled_cs, len[i]); delay(pause);

}

for(int i=0;i<dlen;i++){

ack=SPI.transfer(oled_cs, byte(data[i]>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(data[i] & 0xFF)); delay(pause);

}

for(int i=0;i<sizeof(suffix);i++){

ack=SPI.transfer(oled_cs, suffix[i]); delay(pause);

}

}
Arduino
UART
// -------------for POLYLINE drawing-------------------------

void UART_send_poly(byte command, unsigned int data_len, unsigned int data[]){

unsigned int dlen = data_len / sizeof(int);

byte len[]={byte(2*dlen>>8), byte(2*dlen & 0xFF)};

byte ack;

for(int i=0;i<sizeof(prefix);i++){

ack=Serial1.write(prefix[i]); delay(pause);

}

ack=Serial1.write(command); delay(pause);

for(int i=0;i<sizeof(len);i++){

ack=Serial1.write(len[i]); delay(pause);

}

for(int i=0;i<dlen;i++){

ack=Serial1.write(byte(data[i]>>8)); delay(pause);

ack=Serial1.write(byte(data[i] & 0xFF)); delay(pause);

}

for(int i=0;i<sizeof(suffix);i++){

ack=Serial1.write(suffix[i]); delay(pause);

}

}
Arduino

Пример задания и вывода полилинии (последовательность координат x и y – знакомый многим «ежик» из учебников математики средней школы):

byte poly1[]={

15, 42, 3, 42, 3, 39, 0, 36, 3, 33, 0, 30, 3, 27, 0, 24,

3, 21, 0, 18, 3, 15, 0, 12, 3, 9, 0, 6, 3, 3, 6, 6,

12,0, 15,6, 21,3, 21,6, 27,6, 15,12, 15,42, 21,42, 21,45,

27,45, 27,42, 24,42, 21,39, 21,21, 27,18, 24,15, 24,12,

21,9

};

SPI_send_poly(polyline, sizeof(poly1), poly1);

SPI_send_cmd(circle, sizeof(circl1), circl1);

UART_send_cmd(circle, sizeof(circl1), circl1);

UART_send_poly(polyline, sizeof(poly1), poly1);
Arduino

Результирующий вывод представлен на рисунке 13.

Рис. 13. Пример вывода элементов векторной графики

Рис. 13. Пример вывода элементов векторной графики

Пиксельная графика

Группа команд пиксельной графики представлена в таблице 8.

Таблица 8. Команды пиксельной графики

Команда Код инструкции Данные команды Описание
Отображение монохромного изображения 0х41 Address_X+ Address_Y + Pic_W+ Pic_H

 

Address_X (адрес, кратный 4) и Address_Y используются для указания начального адреса, отображаемого в верхнем левом углу изображения;
Pic_W: Ширина изображения в пикселях (два байта) (ширина, кратная 4)
Pic_H: Высота изображения в пикселях (два байта).
Пример:
Отобразить изображение размером 128х64 в позиции (0,0) (данные изображения могут быть получены с помощью программного обеспечения modulus)
Отправить: fe fd 41 00 08 (00 00 00 00 00 80 00 40) dd cc bb aa
Терминал возвращает fc, указывая, что он готов к приему данных изображения (1024 байта – один бит на пиксель), и возвращает fe после получения данных изображения. (Поскольку имеется буфер, данные могут быть отправлены напрямую, не дожидаясь возврата fc) (Также существует ограничение по времени ожидания для приема данных изображения (таймаут). Если в течение указанного времени данные не будут получены, прием будет остановлен. Время по умолчанию – 50 мс.)
Отображение «серого» изображения 0х42

Address_X+ Address_Y + Pic_W+ Pic_H

 

Address_X (адрес, кратный 4) и Address_Y используются для указания начального адреса, отображаемого в верхнем левом углу изображения;
Pic_W: Ширина изображения в пикселях (два байта) (ширина, кратная 4)
Pic_H: Высота изображения в пикселях (два байта).
Пример:
Отобразите изображение размером 128х32 в позиции (0,0)
Отправить:
fe fd 42 00 08 (00 00 00 00 00 80 00 20) dd cc bb aa
Терминал возвращает fc, указывая, что он готов к приему данных изображения (4096 байт), и возвращает fe после получения данных изображения.
(Поскольку имеется буфер, данные могут быть отправлены напрямую, не дожидаясь возврата fc) (Также существует ограничение по времени ожидания для приема данных изображения (таймаут). Если в течение указанного времени данные не будут получены, прием будет остановлен. Время по умолчанию – 50 мс.)
byte mono_picture = 0x41;

byte gray_picture = 0x42;
Arduino

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

SPI
// ===========for image============================

void SPI_send_image(byte command, unsigned int x, unsigned int y, unsigned int pic_x,
unsigned int pic_y, const uint8_t data[]){

unsigned int data_len = 8;

unsigned int image_size = pic_x * pic_y;

if(command==mono_picture){image_size = image_size>>3;};

byte len[]={byte(data_len>>8), byte(data_len & 0xFF)};

byte ack;

//--------send prefix-------------------------------

for(int i=0;i<sizeof(prefix);i++){

ack=SPI.transfer(oled_cs, prefix[i]); delay(pause);

}

//--------send cmd-------------------------------

ack=SPI.transfer(oled_cs, command); delay(pause);

//--------send lenght-------------------------------

for(int i=0;i<sizeof(len);i++){

ack=SPI.transfer(oled_cs, len[i]); delay(pause);

}

//-------send coordinates-------------------------

ack=SPI.transfer(oled_cs, byte(x>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(x & 0xff)); delay(pause);

ack=SPI.transfer(oled_cs, byte(y>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(y & 0xff)); delay(pause);

//-------send picture sizes-------------------------

ack=SPI.transfer(oled_cs, byte(pic_x>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(pic_x & 0xff)); delay(pause);

ack=SPI.transfer(oled_cs, byte(pic_y>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(pic_y & 0xff)); delay(pause);

//--------send suffix-------------------------------

for(int i=0;i<sizeof(suffix);i++){

ack=SPI.transfer(oled_cs, suffix[i]); delay(pause);

}

//---------------------------------------------------

delay(pause);

//-------send image----------------------------------------

for(int i=0; i<image_size; i++){

ack=SPI.transfer(oled_cs, data[i]); delay(pause);

}

}
Arduino
UART
// ===========for image=========================

void UART_send_image(byte command, unsigned int x, unsigned int y, unsigned int pic_x,
unsigned int pic_y, const uint8_t data[]){

unsigned int data_len = 8;

unsigned int image_size = pic_x * pic_y;

if(command==mono_picture){image_size = image_size>>3;};

//if(command==gray_picture){image_size = image_size<<2;};

byte len[]={byte(data_len>>8), byte(data_len & 0xFF)};

byte ack;

//--------send prefix-------------------------------

for(int i=0;i<sizeof(prefix);i++){

ack=Serial1.write(prefix[i]); delay(pause);

}

//--------send cmd-------------------------------

ack=Serial1.write(command); delay(pause);

//--------send lenght-------------------------------

for(int i=0;i<sizeof(len);i++){

ack=Serial1.write(len[i]); delay(pause);

}

//-------send coordinates-------------------------

ack=Serial1.write(byte(x>>8)); delay(pause);

ack=Serial1.write(byte(x & 0xff)); delay(pause);

ack=Serial1.write(byte(y>>8)); delay(pause);

ack=Serial1.write(byte(y & 0xff)); delay(pause);

//-------send picture sizes-------------------------

ack=Serial1.write(byte(pic_x>>8)); delay(pause);

ack=Serial1.write(byte(pic_x & 0xff)); delay(pause);

ack=Serial1.write(byte(pic_y>>8)); delay(pause);

ack=Serial1.write(byte(pic_y & 0xff)); delay(pause);

//--------send suffix-------------------------------

for(int i=0;i<sizeof(suffix);i++){

ack=Serial1.write(suffix[i]); delay(pause);

}

//---------------------------------------------------

delay(pause);

//-------send image----------------------------------------

for(int i=0; i<image_size; i++){

ack=Serial1.write(data[i]); //delay(pause);

}

}
Arduino

Прописываем картинку в постоянную память:

const uint8_t bat[] PROGMEM = {

#include "bat.h"

};
Arduino

В файле “bat.h” – последовательность байт картинки (для данного примера – в двоичном формате для монохромной картинки).

0b00000000,0b00000000,0b00000000,

0b00000000,0b00000000,0b00000000,

0b00000000,0b00000000,0b00000000,

0b00000000,0b11111111,0b00000000,

0b00000011,0b11111111,0b11000000,

0b00011100,0b00000000,0b01110000,

0b00011000,0b00000000,0b00110000,

0b00011000,0b00000000,0b00110000,

0b00011000,0b00000000,0b00110000, и тому подобное.
Arduino

Сам вызов функции отрисовки картинки (выведет картинку размерами 24*28 точки, начиная с координаты (40;1) для SPI и (40;19) для UART):

SPI_send_image(mono_picture, 40, 1, 24, 28, bat);

UART_send_image(mono_picture, 40, 19, 24, 28, bat);
Arduino

Вывод «серого» изображения (картинки в градациях серого) аналогичен:

UART_send_image(gray_picture, 40, 3, 16, 15, pic1);
Arduino

Глубина цвета – 4 бита на пиксель (16 градаций):

const uint8_t pic1[] PROGMEM = {

#include "pic1.h"

};
Arduino

Сам pic.h (почти квадрат с градиентной заливкой):

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,

0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
Arduino

Малоформатные дисплеи (128*32) не работают с полутоновыми рисунками – модель JR12832-1A_SPI_Blue_3.3V не поддерживает команду вывода серого изображения.

Результат представлен на рисунке 14 – к ежику добавлены батарейка и градиентный квадрат.

Стоит отметить, что выходы выводимых примитивов (векторных) и текста за физические пределы дисплеев не приводят к фатальным ошибкам, а всего лишь обрезают фактический вывод.

Рис. 14. Комбинирование вывода векторной и пиксельной графики

Рис. 14. Комбинирование вывода векторной и пиксельной графики

Конечно же, вывод графики и текста можно комбинировать произвольным образом – рисунок 15.

Рис. 15. Комбинированный вывод графики и текста

Рис. 15. Комбинированный вывод графики и текста

Яркость дисплея можно программно менять в ходе работы практически в любое время, также можно выключать и включать отображение на дисплее.

При высоких уровнях яркости может наблюдаться слабая фоновая засветка темных пикселей (заметно на синем дисплее на рисунке 15а).

Например – циклическое изменение яркости дисплеев с отключением OLED на 5 секунд:

void loop() {

delay(2000);

SPI_send_cmd(cmd_dspl_bright, sizeof(bright), bright);

UART_send_cmd(cmd_dspl_bright, sizeof(bright), bright);

bright[0]+=16;

delay(2000);

SPI_send_cmd(cmd_dspl_off, sizeof(empty), empty);

UART_send_cmd(cmd_dspl_off, sizeof(empty), empty);

delay(5000);

SPI_send_cmd(cmd_dspl_on, sizeof(empty), empty);

UART_send_cmd(cmd_dspl_on, sizeof(empty), empty);

}
Arduino

Токи потребления дисплеев при работе представлены в таблице 9.

Таблица 9. Токи потребления дисплеев JR12832/JR25664

Режим JR12832-1A_SPI_Blue
(напряжение питания 3,3 В)
JR25664-2A_White
(напряжение питания 5 В)
Состояние – вкл, пустой экран ~26 мА ~28 мА
Состояние – вкл, среднее заполнение (текст+немного векторной графики), максимальная яркость ~82 мА ~100 мА
Состояние – вкл, среднее заполнение (текст+немного векторной графики), минимальная яркость ~40 мА ~51 мА
Состояние – выкл. ~22 мА ~25 мА

Программное выключение дисплеев отключает только саму OLED-панель, а не весь дисплей с контроллером целиком, так что по команде программного включения дисплея на нем отображается ранее выведенное изображение.

Заключение

В целом работа с дисплеями Jirun с последовательными интерфейсами (SPI/UART) достаточно проста. Особой инициализации при включении они не требуют – после подачи питания изделия по умолчанию готовы к работе и находятся в активном режиме.

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

Ссылки

  1. Сайт компании Jirun
  2. Интеллектуальные OLED-дисплеи JIRUN с поддержкой кириллицы и широким выбором интерфейсов

Приложение 1

Таблицы кодировок символов, поддерживаемых дисплеями

Рис. 16. ASCII

Рис. 16. ASCII

Рис. 17. Расширенный набор символов GB2312, кодовая страница A1

Рис. 17. Расширенный набор символов GB2312, кодовая страница A1

Рис. 18. Расширенный набор символов GB2312, кодовая страница A2

Рис. 18. Расширенный набор символов GB2312, кодовая страница A2

Рис. 19. Расширенный набор символов GB2312, кодовая страница A3

Рис. 19. Расширенный набор символов GB2312, кодовая страница A3

Рис. 20. Расширенный набор символов GB2312, кодовая страница A6

Рис. 20. Расширенный набор символов GB2312, кодовая страница A6

Рис. 21. Расширенный набор символов GB2312, кодовая страница A7

Рис. 21. Расширенный набор символов GB2312, кодовая страница A7

Рис. 22. Расширенный набор символов GB2312, кодовая страница A8

Рис. 22. Расширенный набор символов GB2312, кодовая страница A8

Рис. 23. Расширенный набор символов GB2312, кодовая страница A9

Рис. 23. Расширенный набор символов GB2312, кодовая страница A9

Приложение 2

Исходный код примера (для рисунка 14)

#include <SPI.h>

int uart_speed=115200;

byte cmd_link_test = 0x11;

byte cmd_speed = 0x12;

byte cmd_timeout = 0x13;

byte cmd_dspl_on = 0x14;

byte cmd_dspl_off = 0x15;

byte cmd_dspl_bright = 0x16;

byte palette = 0x21;

byte clear_screen = 0x22;

byte points = 0x23;

byte polyline = 0x24;

byte triangle = 0x25;

byte rectangle = 0x26;

byte circle = 0x27;

byte ellips = 0x28;

byte mono_picture = 0x41;

byte gray_picture = 0x42;

byte text_6_12 = 0x31;

byte text_8_16 = 0x32;

byte text_12_24 = 0x33;

byte text_32_32 = 0x34;

byte inv_text_6_12 = 0x35;

byte inv_text_8_16 = 0x36;

byte inv_text_12_24 = 0x37;

byte inv_text_32_32 = 0x38;

byte ext_symb = 0xA1;

byte roman_nbr = 0xA2;

byte point_ascii = 0xA3;

byte greek = 0xA6;

byte russian = 0xA7;

byte ext_national = 0xA8;

byte table = 0xA9;

byte ext_ascii = 0xAA;

byte ext_nat_symb = 0xAB;

byte spec_symb = 0xAC;

//===============================================

byte prefix[] = {0xFE, 0xFD};

byte suffix[] = {0xDD, 0xCC, 0xBB, 0xAA};

byte bright[]={0xff};

byte pal[]={0x0f,0x00}; // text/fon

byte empty[]={};

//===============================================

//=======text/obj samples===================================================

unsigned int poly_int1[]={100,0, 250,13, 253,63, 3,61 };

unsigned int poly_int2[]={50,0, 125,13, 127,31, 3,9 };

//============pins & ect===================================================

int oled_cs = 10;

int oled_busy = 9;

int oled_reset = 8;

int oled_uart_busy = 7;

int pause = 1;

void wait_busy(int pin){

while (digitalRead(pin)) {};

}

//=================SPI_functions =====================================

// for commands and vector drawing

void SPI_send_cmd(byte command, unsigned int data_len, byte data[]){

byte len[]={byte(data_len>>8), byte(data_len & 0xFF)};

byte ack;

for(int i=0;i<sizeof(prefix);i++){

ack=SPI.transfer(oled_cs, prefix[i]); delay(pause);

}

ack=SPI.transfer(oled_cs, command); delay(pause);

for(int i=0;i<sizeof(len);i++){

ack=SPI.transfer(oled_cs, len[i]); delay(pause);

}

for(int i=0;i<data_len;i++){

ack=SPI.transfer(oled_cs, data[i]); delay(pause);

}

for(int i=0;i<sizeof(suffix);i++){

ack=SPI.transfer(oled_cs, suffix[i]); delay(pause);

}

}

// for POLYLINE drawing---------------------------------------

void SPI_send_poly(byte command, unsigned int data_len, unsigned int data[]){

unsigned int dlen = data_len / sizeof(int);

byte len[]={byte(2*dlen>>8), byte(2*dlen & 0xFF)};

byte ack;

for(int i=0;i<sizeof(prefix);i++){

ack=SPI.transfer(oled_cs, prefix[i]); delay(pause);

}

ack=SPI.transfer(oled_cs, command); delay(pause);

for(int i=0;i<sizeof(len);i++){

ack=SPI.transfer(oled_cs, len[i]); delay(pause);

}

for(int i=0;i<dlen;i++){

ack=SPI.transfer(oled_cs, byte(data[i]>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(data[i] & 0xFF)); delay(pause);

}

for(int i=0;i<sizeof(suffix);i++){

ack=SPI.transfer(oled_cs, suffix[i]); delay(pause);

}

}

// ===========for text========================================

void SPI_send_text(byte command, unsigned int x, unsigned int y, unsigned int data_len,
byte data[]){

//unsigned int data_len = sizeof(data);

data_len += 4;

byte len[]={byte(data_len>>8), byte(data_len & 0xFF)};

byte ack;

//--------send prefix-------------------------------

for(int i=0;i<sizeof(prefix);i++){

ack=SPI.transfer(oled_cs, prefix[i]); delay(pause);

}

//--------send cmd-------------------------------

ack=SPI.transfer(oled_cs, command); delay(pause);

//--------send lenght-------------------------------

for(int i=0;i<sizeof(len);i++){

ack=SPI.transfer(oled_cs, len[i]); delay(pause);

}

//-------send coordinates-------------------------

ack=SPI.transfer(oled_cs, byte(x>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(x & 0xff)); delay(pause);

ack=SPI.transfer(oled_cs, byte(y>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(y & 0xff)); delay(pause);

//-------send text----------------------------------------

for(int i=0;i<data_len;i++){

ack=SPI.transfer(oled_cs, data[i]); delay(pause);

}

//--------send suffix-------------------------------

for(int i=0;i<sizeof(suffix);i++){

ack=SPI.transfer(oled_cs, suffix[i]); delay(pause);

}

}

void SPI_send_ASCII_text(byte command, unsigned int x, unsigned int y,
unsigned int data_len, String data){

//unsigned int data_len = sizeof(data);

data_len += 4;

byte len[]={byte(data_len>>8), byte(data_len & 0xFF)};

byte ack;

//--------send prefix-------------------------------

for(int i=0;i<sizeof(prefix);i++){

ack=SPI.transfer(oled_cs, prefix[i]); delay(pause);

}

//--------send cmd-------------------------------

ack=SPI.transfer(oled_cs, command); delay(pause);

//--------send lenght-------------------------------

for(int i=0;i<sizeof(len);i++){

ack=SPI.transfer(oled_cs, len[i]); delay(pause);

}

//-------send coordinates-------------------------

ack=SPI.transfer(oled_cs, byte(x>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(x & 0xff)); delay(pause);

ack=SPI.transfer(oled_cs, byte(y>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(y & 0xff)); delay(pause);

//-------send text----------------------------------------

for(int i=0;i<data_len;i++){

ack=SPI.transfer(oled_cs, data[i]); delay(pause);

}

//--------send suffix-------------------------------

for(int i=0;i<sizeof(suffix);i++){

ack=SPI.transfer(oled_cs, suffix[i]); delay(pause);

}

}

// ===========for image========================================

void SPI_send_image(byte command, unsigned int x, unsigned int y, unsigned int pic_x,
unsigned int pic_y, const uint8_t data[]){

unsigned int data_len = 8;

unsigned int image_size = pic_x * pic_y;

if(command==mono_picture){image_size = image_size>>3;};

byte len[]={byte(data_len>>8), byte(data_len & 0xFF)};

byte ack;

//--------send prefix-------------------------------

for(int i=0;i<sizeof(prefix);i++){

ack=SPI.transfer(oled_cs, prefix[i]); delay(pause);

}

//--------send cmd-------------------------------

ack=SPI.transfer(oled_cs, command); delay(pause);

//--------send lenght-------------------------------

for(int i=0;i<sizeof(len);i++){

ack=SPI.transfer(oled_cs, len[i]); delay(pause);

}

//-------send coordinates-------------------------

ack=SPI.transfer(oled_cs, byte(x>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(x & 0xff)); delay(pause);

ack=SPI.transfer(oled_cs, byte(y>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(y & 0xff)); delay(pause);

//-------send picture sizes-------------------------

ack=SPI.transfer(oled_cs, byte(pic_x>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(pic_x & 0xff)); delay(pause);

ack=SPI.transfer(oled_cs, byte(pic_y>>8)); delay(pause);

ack=SPI.transfer(oled_cs, byte(pic_y & 0xff)); delay(pause);

//--------send suffix-------------------------------

for(int i=0;i<sizeof(suffix);i++){

ack=SPI.transfer(oled_cs, suffix[i]); delay(pause);

}

//---------------------------------------------------

delay(pause);

//-------send image----------------------------------------

for(int i=0; i<image_size; i++){

ack=SPI.transfer(oled_cs, data[i]); delay(pause);

}

}

//=====================================================================

//=====================================================================

//=================UART_functions =====================================

// for commands and vector drawing

void UART_send_cmd(byte command, unsigned int data_len, byte data[]){

byte len[]={byte(data_len>>8), byte(data_len & 0xFF)};

byte ack;

for(int i=0;i<sizeof(prefix);i++){

ack=Serial1.write(prefix[i]); delay(pause);

}

ack=Serial1.write(command); delay(pause);

for(int i=0;i<sizeof(len);i++){

ack=Serial1.write(len[i]); delay(pause);

}

for(int i=0;i<data_len;i++){

ack=Serial1.write(data[i]); delay(pause);

}

for(int i=0;i<sizeof(suffix);i++){

ack=Serial1.write(suffix[i]); delay(pause);

}

}

// ----------------for POLYLINE drawing---------------------------------------

void UART_send_poly(byte command, unsigned int data_len, unsigned int data[]){

unsigned int dlen = data_len / sizeof(int);

byte len[]={byte(2*dlen>>8), byte(2*dlen & 0xFF)};

byte ack;

for(int i=0;i<sizeof(prefix);i++){

ack=Serial1.write(prefix[i]); delay(pause);

}

ack=Serial1.write(command); delay(pause);

for(int i=0;i<sizeof(len);i++){

ack=Serial1.write(len[i]); delay(pause);

}

for(int i=0;i<dlen;i++){

ack=Serial1.write(byte(data[i]>>8)); delay(pause);

ack=Serial1.write(byte(data[i] & 0xFF)); delay(pause);

}

for(int i=0;i<sizeof(suffix);i++){

ack=Serial1.write(suffix[i]); delay(pause);

}

}

// ===========for text========================================

void UART_send_text(byte command, unsigned int x, unsigned int y, unsigned int data_len,
byte data[]){

//unsigned int data_len = sizeof(data);

data_len += 4;

byte len[]={byte(data_len>>8), byte(data_len & 0xFF)};

byte ack;

//--------send prefix-------------------------------

for(int i=0;i<sizeof(prefix);i++){

ack=Serial1.write(prefix[i]); delay(pause);

}

//--------send cmd-------------------------------

ack=Serial1.write(command); delay(pause);

//--------send lenght-------------------------------

for(int i=0;i<sizeof(len);i++){

ack=Serial1.write(len[i]); delay(pause);

}

//-------send coordinates-------------------------

ack=Serial1.write(byte(x>>8)); delay(pause);

ack=Serial1.write(byte(x & 0xff)); delay(pause);

ack=Serial1.write(byte(y>>8)); delay(pause);

ack=Serial1.write(byte(y & 0xff)); delay(pause);

//-------send text----------------------------------------

for(int i=0;i<data_len;i++){

ack=Serial1.write(data[i]); delay(pause);

}

//--------send suffix-------------------------------

for(int i=0;i<sizeof(suffix);i++){

ack=Serial1.write(suffix[i]); delay(pause);

}

}

void UART_send_ASCII_text(byte command, unsigned int x, unsigned int y,
unsigned int data_len, String data){

//unsigned int data_len = sizeof(data);

data_len += 4;

byte len[]={byte(data_len>>8), byte(data_len & 0xFF)};

byte ack;

//--------send prefix-------------------------------

for(int i=0;i<sizeof(prefix);i++){

ack=Serial1.write(prefix[i]); delay(pause);

}

//--------send cmd-------------------------------

ack=Serial1.write(command); delay(pause);

//--------send lenght-------------------------------

for(int i=0;i<sizeof(len);i++){

ack=Serial1.write(len[i]); delay(pause);

}

//-------send coordinates-------------------------

ack=Serial1.write(byte(x>>8)); delay(pause);

ack=Serial1.write(byte(x & 0xff)); delay(pause);

ack=Serial1.write(byte(y>>8)); delay(pause);

ack=Serial1.write(byte(y & 0xff)); delay(pause);

//-------send text----------------------------------------

for(int i=0;i<data_len;i++){

ack=Serial1.write(data[i]); delay(pause);

}

//--------send suffix-------------------------------

for(int i=0;i<sizeof(suffix);i++){

ack=Serial1.write(suffix[i]); delay(pause);

}

}

// ===========for image========================================

void UART_send_image(byte command, unsigned int x, unsigned int y, unsigned int pic_x,
unsigned int pic_y, const uint8_t data[]){

unsigned int data_len = 8;

unsigned int image_size = pic_x * pic_y;

if(command==mono_picture){image_size = image_size>>3;};

//if(command==gray_picture){image_size = image_size<<2;};

byte len[]={byte(data_len>>8), byte(data_len & 0xFF)};

byte ack;

//--------send prefix-------------------------------

for(int i=0;i<sizeof(prefix);i++){

ack=Serial1.write(prefix[i]); delay(pause);

}

//--------send cmd-------------------------------

ack=Serial1.write(command); delay(pause);

//--------send lenght-------------------------------

for(int i=0;i<sizeof(len);i++){

ack=Serial1.write(len[i]); delay(pause);

}

//-------send coordinates-------------------------

ack=Serial1.write(byte(x>>8)); delay(pause);

ack=Serial1.write(byte(x & 0xff)); delay(pause);

ack=Serial1.write(byte(y>>8)); delay(pause);

ack=Serial1.write(byte(y & 0xff)); delay(pause);

//-------send picture sizes-------------------------

ack=Serial1.write(byte(pic_x>>8)); delay(pause);

ack=Serial1.write(byte(pic_x & 0xff)); delay(pause);

ack=Serial1.write(byte(pic_y>>8)); delay(pause);

ack=Serial1.write(byte(pic_y & 0xff)); delay(pause);

//--------send suffix-------------------------------

for(int i=0;i<sizeof(suffix);i++){

ack=Serial1.write(suffix[i]); delay(pause);

}

//---------------------------------------------------

delay(pause);

//-------send image----------------------------------------

for(int i=0; i<image_size; i++){

ack=Serial1.write(data[i]); //delay(pause);

}

}

//######################################################################################

byte circl1[]={01, 0,21, 0,15, 2,   00, 0,21, 0,15, 4};

unsigned int poly1[]={

15, 42, 3, 42, 3, 39, 0, 36, 3, 33, 0, 30, 3, 27, 0, 24,

3, 21, 0, 18, 3, 15, 0, 12, 3, 9, 0, 6, 3, 3, 6, 6,

12,0, 15,6, 21,3, 21,6, 27,6, 15,12, 15,42, 21,42, 21,45,

27,45, 27,42, 24,42, 21,39, 21,21, 27,18, 24,15, 24,12,

21,9

};

String str_text1="This is just ASCII";//18

String str_text2="string for test :)";//18

String str_text3="This's ASCII string for test :)";//18

byte text1[]={0xa7,0xb4, 0xa7,0xd6, 0xa7,0xdc, 0xa7,0xe3, 0xa7,0xe4, '+','5',
0xa6,0xc2, 0xa1,0xe6};

byte text2[]={0xa7, 0xe4, 0xa7, 0xd6, 0xa7, 0xe7, 0xa7, 0xdf, 0xa7, 0xe0, 0xa7, 0xdd,
0xa7, 0xe0,0xa7, 0xd4, 0xa7, 0xda, 0xa7, 0xda};

byte text4[]={0xa1, 0xe6, 0xa2, 0xd5, 0xa3, 0xa4, 0xa3, 0xc0, 0xa6, 0xb2, 0xa6, 0xc5,
0x20, 0xa7, 0xa7, 0xa7, 0xd8, 0xaa, 0xa3};

const uint8_t bat[] PROGMEM = {

#include "bat.h"

};

const uint8_t pic1[] PROGMEM = {

#include "pic1.h"

};

void setup() {

// put your setup code here, to run once:

Serial.begin(115200);

Serial1.begin(9600);

//========SPI_OLED_INIT=============

pinMode(oled_cs, OUTPUT);

pinMode(oled_reset, OUTPUT);

pinMode(oled_busy, INPUT);

digitalWrite(oled_reset, HIGH);

//delay(2000);

digitalWrite(oled_reset, LOW);

//digitalWrite(oled_cs, HIGH);

delay(10);

digitalWrite(oled_reset, HIGH);
//SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3));

SPI.setBitOrder(MSBFIRST);

SPI.begin(oled_cs);

SPI.setClockDivider(oled_cs, 10);

delay(1000);

SPI_send_cmd(cmd_dspl_bright, sizeof(bright), bright);

SPI_send_cmd(clear_screen, sizeof(empty), empty);

UART_send_cmd(cmd_dspl_bright, sizeof(bright), bright);

UART_send_cmd(clear_screen, sizeof(empty), empty);

// circles

SPI_send_cmd(circle, sizeof(circl1), circl1);

UART_send_cmd(circle, sizeof(circl1), circl1);

//polyline

SPI_send_poly(polyline, sizeof(poly1), poly1);

UART_send_poly(polyline, sizeof(poly1), poly1);

// ASCII text

SPI_send_ASCII_text(text_6_12, 30, 0, str_text3.length(), str_text3);

//  SPI_send_ASCII_text(inv_text_6_12, 33, 14, str_text2.length(), str_text2);

UART_send_ASCII_text(text_6_12, 30, 0, str_text1.length(), str_text1);

UART_send_ASCII_text(inv_text_12_24, 170, 13, str_text2.length(), str_text2);

// common text

SPI_send_text(inv_text_6_12, 30, 23, sizeof(text1), text1);

UART_send_text(text_6_12, 5, 51, sizeof(text1), text1);

//SPI_send_image(byte command, unsigned int x, unsigned int y, unsigned int pic_x,
// unsigned int pic_y, byte data[])

// SPI_send_image(mono_picture, 40, 19, 24, 28, bat);

// SPI_send_image(gray_picture, 80, 19, 16, 15, pic1);

UART_send_image(mono_picture, 40, 19, 24, 28, bat);

UART_send_image(gray_picture, 80, 19, 16, 15, pic1);

bright[0]=0;

}

//int br=0;

void loop() {

delay(2000);

SPI_send_cmd(cmd_dspl_bright, sizeof(bright), bright);

UART_send_cmd(cmd_dspl_bright, sizeof(bright), bright);

bright[0]+=16;

delay(2000);

SPI_send_cmd(cmd_dspl_off, sizeof(empty), empty);

UART_send_cmd(cmd_dspl_off, sizeof(empty), empty);

delay(5000);

SPI_send_cmd(cmd_dspl_on, sizeof(empty), empty);

UART_send_cmd(cmd_dspl_on, sizeof(empty), empty);

///*

}
Arduino
•••

Наши информационные каналы

О компании Jirun

Shenzhen Jirun Industrial Co., Ltd. (Jirun) – китайская fabless-компания, специализирующаяся на разработке и поставке OLED-дисплеев. Основана и располагается в городе Шеньчжень. Компания поставляет OLED-дисплеи и OLED-модули семи базовых моделей с диагоналями от 1,54 до 5,5 дюймов (от 128х32 до 256х64 пикселя) с рабочей температурой -40…85°С в двух модификациях – стандартные для промышленного использования и интеллектуальные с микроконтроллерным управлением. Головной офис: г. Шеньчжень, п ...читать далее

Товары
Наименование
JR25664-1A_SPI_Green_3.3V (JIRUN)
 
JR25664-1A_UART_Green_5V (JIRUN)
 
JR12832-1A_SPI_Blue_3.3V (JIRUN)
 
JR12864-2A_UART_White_5V (JIRUN)
 
JR12864-2A_SPI_Yellow_3.3V (JIRUN)
 
JR25664-2A_White (JIRUN)
 
JR25664-2A_Green (JIRUN)
 
JR12864-3 (JIRUN)