Цветной OLED дисплей 96х64 пикселя

Эта статья является логическим продолжением вот этой статьи про монохромный OLED дисплей. На этот раз мне в руки достался цветной OLED дисплей, разрешением 96*64 пикселя с магазина Banggood. Пока не забыл, на странице товара есть ссылка на архив с документацией на дисплей: http://files.banggood.com/2016/08/SKU407528.zip

Кроме того достаточно информации по дисплею встречается в сети, так же есть готовые библиотеки для нетерпеливых (от Adafruit, Seeed-Studio и конечно же монстр среди библиотек для дисплеев U8Glib). Я же покажу работу с дисплеем безо всяких библиотек, покажу в среде программирования ArduinoIDE, что бы было понятно новичкам (матерые программисты наверняка разберутся).

Итак, дисплей может подключаться при помощи параллельных интерфейсов (6800, 8080) и последовательного интерфейса SPI. В модуле, который попал мне в руки, реализован SPI протокол.

Распиновка слева-направо: 2 вывода для питания, SCL — предназначен для тактового сигнала, SDA — по этому входу в контроллер дисплея поступают данные, RES — предназначен для сброса дисплея, DC (data/command) — логический сигнал на этом входе сообщает дисплею что в данный момент передается, данные или команда (об этом чуть позже подробнее), CS — обычный chip select протокола SPI, низкий уровень на этом входе сообщает дисплею, что данные, поступающие по нему, предназначены именно для дисплея. Подробно вдаваться в суть протока SPI я не буду, стоит лишь уточнить, что дисплей работает в режиме SPI_MODE3 (CPOL=1, CPHA=1).

Вас могут смутить обозначения SDA и SCL, ведь они применяются для обозначения выводов устройств, работающих по протоколу I2C, но всё на самом деле не так плохо. Поскольку по линии SDA идут данные от микроконтроллера к дисплею — он подключается к выводу MOSI микроконтроллера (D11 на ардуино). По SCL идут тактовые сигналы, а значит он подключается к выводу SCK микроконтроллера (D13 на ардуино).

Для выводов RES, DC и CS можно выбрать любые выводы (у меня D10 для CS, D8 для DC и  D9 для RES). Библиотека SPI не будет управлять этими выводами, это придется делать вручную. Разберемся для чего нужен каждый из этих выводов.

CS — самое простое, логический 0 говорит дисплею о том, что данные предназначены для него, логическая 1 — о том что передача данных завершена.

RES — служит для сброса дисплея, для этого надо на некоторое время подать на этот вывод логический 0. Это необходимо сделать один раз в начале программы перед инициализацией дисплея.

DC — логический 0, подаваемый на этот вывод, сообщает дисплею о том, что передаются команды, логическая 1 — передаются данные.

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

#include <SPI.h>

const int ss = 10; //slave select
const int dc = 8; // data/command data=1 command=0
const int reset = 9; //oled reset=0

void oledCommand(uint8_t val) //общая функция отправки команды дисплею
{
digitalWrite(ss, LOW); //slave select устанавливаем в 0, это активирует SPI
digitalWrite(dc, LOW); //DC равен 0, это значит что отправляется команда
SPI.transfer(val); //отправляем команду стандартной функцией библиотеки SPI
digitalWrite(ss, HIGH); //slave select устанавливаем в 1, это означает что работа с SPI завершена
}

void oledData(uint8_t val) //общая функция отправки данных дисплею
{
digitalWrite(ss, LOW); //slave select устанавливаем в 0, это активирует SPI
digitalWrite(dc, HIGH); //DC равен 1, это значит что отправляются данные
SPI.transfer(val); //отправляем данные стандартной функцией библиотеки SPI
digitalWrite(ss, HIGH); //slave select устанавливаем в 1, это означает что работа с SPI завершена
}
void setup() {

 pinMode(ss, OUTPUT);
 pinMode(dc, OUTPUT);
 pinMode(reset, OUTPUT);

 SPI.begin();
 SPI.setDataMode(SPI_MODE3);
 oledInit();
}
void setup() {

pinMode(ss, OUTPUT);
pinMode(dc, OUTPUT);
pinMode(reset, OUTPUT);

SPI.begin();
SPI.setDataMode(SPI_MODE3);
oledInit();
}

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

В программе это будет выглядеть так:

void oledInit() //функция инициализации дисплея
{
digitalWrite(reset, HIGH); //процедура сброса дисплея
delay(100);
digitalWrite(reset, LOW);
delay(100);
digitalWrite(reset, HIGH);
delay(100);
//процедура инициализации дисплея
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0xAE); //display OFF
SPI.transfer(0xA0); //remap & color depth setting
SPI.transfer(0x72); //b01110010 расшифровка ниже
/*
b01 — 65k format, (00 -256 color, 10 — 65k color format 2)
1 — enable COM split odd even (0 — disable)
1 — scan COM95 to COM0 (0 — COM0 to COM95) отражение по короткой стороне
0 — disable left-right swaping (1 — enable swaping)
0 — RGB color (1 — BGR color)
1 — RAM column 0 to 95 (0 — 95 to 0)
0 — horizontal address increment (1 — vertical)
*/
SPI.transfer(0xA1); //set display start line (0-63)
SPI.transfer(0x0);
SPI.transfer(0xA2); //set vertical offset (0-63)
SPI.transfer(0x0);
SPI.transfer(0xA4); //normal display (A5 — all pixel ON, A6 — all pixel OFF, A7 — inverse display)
SPI.transfer(0xA8); //set MUX ratio N+1 mux
SPI.transfer(0x3F); //default 0x3F
SPI.transfer(0xAD); //select internal Vcc supply
SPI.transfer(0x8E); //default 0x8E
SPI.transfer(0xB0); //set power saving mode
SPI.transfer(0x0B); //default 0x0B (disable power saving mode) 0X1A — enable
SPI.transfer(0xB1); //set reset, pre-charge period
SPI.transfer(0x31); //default 0x31
SPI.transfer(0xB3); //oscillator frequency
SPI.transfer(0xF0); //default 0xF0
SPI.transfer(0x8A); //set second pre-charge color A
SPI.transfer(0x64); //default 0x64
SPI.transfer(0x8B); //set second pre-charge color B
SPI.transfer(0x78); //default 0x78
SPI.transfer(0x8C); //set second pre-charge color C
SPI.transfer(0x64); //default 0x64
SPI.transfer(0xBB); //set pre-charge voltage level
SPI.transfer(0x3A); //default 0x3A
SPI.transfer(0xBE); //set COM deselect voltage level
SPI.transfer(0x3E); //default 0x3E
SPI.transfer(0x87); //set master current
SPI.transfer(0x06); //default 0x06
SPI.transfer(0x81); //set contrast for color A
SPI.transfer(0x91); //default 0x91
SPI.transfer(0x82); //set contrast for color B
SPI.transfer(0x50); //default 0x50
SPI.transfer(0x83); //set contrast for color C
SPI.transfer(0x7D); //default 0x7D
SPI.transfer(0xAF); //display ON, normal mode
digitalWrite(ss, HIGH);
}

Теперь дисплей готов к выводу изображения. Но стоит рассмотреть некоторые команды. В частности очень важны следующие строки:

SPI.transfer(0xA0); //remap & color depth setting

SPI.transfer(0x72); //b01110010 расшифровка ниже

/* b01 — 65k format, (00 -256 color, 10 — 65k color format 2) — здесь мы выбираем в каком формате будут задаваться цвета и сколько цветов будет возможно использовать

Поскольку выбираем 65 тысяч цветов, то значение цвета в один байт не поместится, лишь в два байта.

1 — enable COM split odd even (0 — disable)

1 — scan COM95 to COM0 (0 — COM0 to COM95) отражение по короткой стороне

0 — disable left-right swaping (1 — enable swaping) 0 — RGB color (1 — BGR color) задаем привычный нам формат RGB

1 — RAM column 0 to 95 (0 — 95 to 0)

0 — horizontal address increment (1 — vertical) */ Выбираем как будут выводиться данные на дисплей, слева-направо сверху-вниз (привычный нам способ, потому что и пишем так и массивы задаем) или сверху-вниз слева-направо. Эти методы адресации рассмотрены в предыдущей статье, лишь отмечу что мы будем использовать горизонтальную адресацию.

Поскольку для задания цвета у нас есть всего 2 байта, а формат RGB предполагает 3, то необходимо произвести преобразование. Для красного цвета отводятся первые 5 бит, далее 6 бит зеленого цвета, замыкают 5 бит синего, поэтому функцию преобразования цвета я назвал color565

uint16_t color565(uint8_t r, uint8_t g, uint8_t b) //функция преобразования цвета R8G8B8bit в формат R5G6B5bit
{
uint16_t c;
c = r >> 3;
c <<= 6;
c |= g >> 2;
c <<= 5;
c |= b >> 3;

return c;// получаем 16-битное значение цвета и возвращаем его
}

Поскольку данными необходимо передавать лишь цвет, то функцию передачи данных можно переделать в функцию передачи цвета, но 16-битное значение цвета необходимо будет разбить на два 8-битных и послать их одно за другим.

void oledDataColor(uint16_t color) //измененная функция для отправки 16-битного значения цвета
{
digitalWrite(ss, LOW);
digitalWrite(dc, HIGH);
SPI.transfer(color >> 8); //разбиваем 16-битное значение на 2 8-битных
SPI.transfer(color);
digitalWrite(ss, HIGH);
}

Теперь можно рисовать, и начну я с базового элемента любого растрового изображения — пикселя. Для отображения графических примитивов предусмотрены готовые функции, но не для пикселя и окружности, поэтому будем изобретать велосипед.

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

Представим, что необходимо вывести изображение размером N на N пикселей, левый верхний угол изображения должен находиться в координатах х=X, у=Y. Для этого необходимо выбрать прямоугольную область на дисплее, а далее передать значения цвета пикселей по очереди обходя каждый пиксель изображения слева-направо сверху-вниз. Полученные дисплеем значения цвета так же будут выводиться слева-направо сверху-вниз в районе выбранной области, и обход пикселей будет таким, как представлен на изображении ниже.

Для выбора области на дисплее необходимо передать команду 0x15,значения Х и У левого верхнего угла области, далее команду 0x75 и значения Х и У правого нижнего угла области. Все эти значения передаются командами, то есть вывод DC подтянут к нулю. Затем подаем на DC логическую единицу и посылаем значения цвета каждого пикселя. Функции отправки команд, данных и цвета я уже привел. Далее необходимо включить фантазию и принять факт что один пиксель — это изображение состоящее из одного пикселя, и процедуру вывода изображения применить к одному единственному пикселю. В итоге получается вот такая функция:

//функция задает цвет выбранной точке
void oledPixel(uint8_t x, uint8_t y, uint16_t color) {
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x15);
SPI.transfer(x);
SPI.transfer(95);
SPI.transfer(0x75);
SPI.transfer(y);
SPI.transfer(63);
delay(1);
digitalWrite(dc, HIGH);
SPI.transfer(color >> 8);
SPI.transfer(color);
delay(1);
digitalWrite(ss, HIGH);
}

Далее пойдут уже готовые функции для вывода линии, прямоугольника и залитого прямоугольника. 

//функция отрисовывает линию определенного цвета между двумя указанными координатами
void oledLine (uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t color)
{
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x21);
SPI.transfer(x1); //x start
SPI.transfer(y1); //Y start
SPI.transfer(x2); //X end
SPI.transfer(y2); //Y end
delay(1);
//здесь синтезированный в формат 565 цвет разбирается отбратно
//я понимаю что это костыль, но во первых для задания цвета необходимо использовать один аргумент вместо 3-х
//а во вторых, я использовал именно такой способ для общего понимания работы с цветом при работе с данным дисплеем
SPI.transfer((color >> 11) & 0x1F); //R color
SPI.transfer((color >> 5) & 0x3F); //G color
SPI.transfer(color & 0x1F); //B color
delay(1);
digitalWrite(ss, HIGH);
}

//функция рисует прямоугольник заданной высоты ширины и цвета, левый верхний угол прямоугольника задается первыми двумя аргументами
void oledRect (uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t colorFrame)
{
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x26); //настройка заливки прямоугольника
SPI.transfer(0x0); //отключаем заливку прямоугольника
SPI.transfer(0x22);
SPI.transfer(x); //x start
SPI.transfer(y); //Y start
SPI.transfer(x + w); //X end
SPI.transfer(y + h); //Y end
delay(1);
SPI.transfer((colorFrame >> 11) & 0x1F); //R color frame
SPI.transfer((colorFrame >> 5) & 0x3F); //G color
SPI.transfer(colorFrame & 0x1F); //B color
delay(10);
digitalWrite(ss, HIGH);
}

//то же самое, но прямоугольникк залит определенным цветом (6 аргумент задает цвет заливки)
void oledRectFill (uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t colorFrame, uint16_t colorFill)
{
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x26); //настройка заливки прямоугольника
SPI.transfer(0x1); //включаем заливку прямоугольника
SPI.transfer(0x22);
SPI.transfer(x); //x start
SPI.transfer(y); //Y start
SPI.transfer(x + w); //X end
SPI.transfer(y + h); //Y end
delay(1);
SPI.transfer((colorFrame >> 11) & 0x1F); //R color frame
SPI.transfer((colorFrame >> 5) & 0x3F); //G color
SPI.transfer(colorFrame & 0x1F); //B color
SPI.transfer((colorFill >> 11) & 0x1F); //R color fill
SPI.transfer((colorFill >> 5) & 0x3F); //G color
SPI.transfer(colorFill & 0x1F); //B color
delay(10);
digitalWrite(ss, HIGH);
}

Так же предусмотрена функция очистки прямоугольной области дисплея и она же используется для очистки всего дисплея.

void oledClear(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x25);
SPI.transfer(x1);
SPI.transfer(y1);
SPI.transfer(x2);
SPI.transfer(y2);
delay(1);
digitalWrite(ss, HIGH);
}

void oledClearAll()
{
oledClear(0, 0, 95, 63);
}

И ещё команды скролинга дисплея. В них я глубоко не вникал, заставил картинку двигаться вертикально, но не смог заставить двигаться горизонтально. На том и хватит, я вряд ли буду использовать эти команды.

//настройка скролинга дисплея
void oledScrollSetup (uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e)
{
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x27);
SPI.transfer(a);
SPI.transfer(b);
SPI.transfer(c);
SPI.transfer(d);
SPI.transfer(e);
delay(1);
digitalWrite(ss, HIGH);
}

void oledScrollOn()
{
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x2F);
digitalWrite(ss, HIGH);
}

void oledScrollOff()
{
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x2E);
digitalWrite(ss, HIGH);
}

 

Приведу весь код «скетча».

#include <SPI.h>

const int ss = 10; //slave select
const int dc = 8; // data/command data=1 command=0
const int reset = 9; //oled reset=0

void oledCommand(uint8_t val) //общая функция отправки команды дисплею
{
digitalWrite(ss, LOW); //slave select устанавливаем в 0, это активирует SPI
digitalWrite(dc, LOW); //DC равен 0, это значит что отправляется команда
SPI.transfer(val); //отправляем команду стандартной функцией библиотеки SPI
digitalWrite(ss, HIGH); //slave select устанавливаем в 1, это означает что работа с SPI завершена
}

void oledData(uint8_t val) //общая функция отправки данных дисплею
{
digitalWrite(ss, LOW); //slave select устанавливаем в 0, это активирует SPI
digitalWrite(dc, HIGH); //DC равен 1, это значит что отправляются данные
SPI.transfer(val); //отправляем данные стандартной функцией библиотеки SPI
digitalWrite(ss, HIGH); //slave select устанавливаем в 1, это означает что работа с SPI завершена
}

void oledDataColor(uint16_t color) //измененная функция для отправки 16-битного значения цвета
{
digitalWrite(ss, LOW);
digitalWrite(dc, HIGH);
SPI.transfer(color >> 8); //разбиваем 16-битное значение на 2 8-битных
SPI.transfer(color);
digitalWrite(ss, HIGH);
}

void oledInit() //функция инициализации дисплея
{
digitalWrite(reset, HIGH); //процедура сброса дисплея
delay(100);
digitalWrite(reset, LOW);
delay(100);
digitalWrite(reset, HIGH);
delay(100);
//процедура инициализации дисплея
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0xAE); //display OFF
SPI.transfer(0xA0); //remap & color depth setting
SPI.transfer(0x72); //b01110010 расшифровка ниже
/*
b01 — 65k format, (00 -256 color, 10 — 65k color format 2)
1 — enable COM split odd even (0 — disable)
1 — scan COM95 to COM0 (0 — COM0 to COM95) отражение по короткой стороне
0 — disable left-right swaping (1 — enable swaping)
0 — RGB color (1 — BGR color)
1 — RAM column 0 to 95 (0 — 95 to 0)
0 — horizontal address increment (1 — vertical)
*/
SPI.transfer(0xA1); //set display start line (0-63)
SPI.transfer(0x0);
SPI.transfer(0xA2); //set vertical offset (0-63)
SPI.transfer(0x0);
SPI.transfer(0xA4); //normal display (A5 — all pixel ON, A6 — all pixel OFF, A7 — inverse display)
SPI.transfer(0xA8); //set MUX ratio N+1 mux
SPI.transfer(0x3F); //default 0x3F
SPI.transfer(0xAD); //select internal Vcc supply
SPI.transfer(0x8E); //default 0x8E
SPI.transfer(0xB0); //set power saving mode
SPI.transfer(0x0B); //default 0x0B (disable power saving mode) 0X1A — enable
SPI.transfer(0xB1); //set reset, pre-charge period
SPI.transfer(0x31); //default 0x31
SPI.transfer(0xB3); //oscillator frequency
SPI.transfer(0xF0); //default 0xF0
SPI.transfer(0x8A); //set second pre-charge color A
SPI.transfer(0x64); //default 0x64
SPI.transfer(0x8B); //set second pre-charge color B
SPI.transfer(0x78); //default 0x78
SPI.transfer(0x8C); //set second pre-charge color C
SPI.transfer(0x64); //default 0x64
SPI.transfer(0xBB); //set pre-charge voltage level
SPI.transfer(0x3A); //default 0x3A
SPI.transfer(0xBE); //set COM deselect voltage level
SPI.transfer(0x3E); //default 0x3E
SPI.transfer(0x87); //set master current
SPI.transfer(0x06); //default 0x06
SPI.transfer(0x81); //set contrast for color A
SPI.transfer(0x91); //default 0x91
SPI.transfer(0x82); //set contrast for color B
SPI.transfer(0x50); //default 0x50
SPI.transfer(0x83); //set contrast for color C
SPI.transfer(0x7D); //default 0x7D
SPI.transfer(0xAF); //display ON, normal mode
digitalWrite(ss, HIGH);
}

uint16_t color565(uint8_t r, uint8_t g, uint8_t b) //функция преобразования цвета R8G8B8bit в формат R5G6B5bit
{
uint16_t c;
c = r >> 3;
c <<= 6;
c |= g >> 2;
c <<= 5;
c |= b >> 3;

return c;// получаем 16-битное значение цвета и возвращаем его
}

//функция задает цвет выбранной точке
void oledPixel(uint8_t x, uint8_t y, uint16_t color) {
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x15);
SPI.transfer(x);
SPI.transfer(95);
SPI.transfer(0x75);
SPI.transfer(y);
SPI.transfer(63);
delay(1);
digitalWrite(dc, HIGH);
SPI.transfer(color >> 8);
SPI.transfer(color);
delay(1);
digitalWrite(ss, HIGH);
}

void oledSetArea(uint8_t x, uint8_t y, uint8_t w, uint8_t h) {
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x15);
SPI.transfer(x);
SPI.transfer(y);
SPI.transfer(0x75);
SPI.transfer(x + w);
SPI.transfer(y + h);
delay(1);
digitalWrite(ss, HIGH);
}

//функция отрисовывает линию определенного цвета между двумя указанными координатами
void oledLine (uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t color)
{
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x21);
SPI.transfer(x1); //x start
SPI.transfer(y1); //Y start
SPI.transfer(x2); //X end
SPI.transfer(y2); //Y end
delay(1);
//здесь синтезированный в формат 565 цвет разбирается отбратно
//я понимаю что это костыль, но во первых для задания цвета необходимо использовать один аргумент вместо 3-х
//а во вторых, я использовал именно такой способ для общего понимания работы с цветом при работе с данным дисплеем
SPI.transfer((color >> 11) & 0x1F); //R color
SPI.transfer((color >> 5) & 0x3F); //G color
SPI.transfer(color & 0x1F); //B color
delay(1);
digitalWrite(ss, HIGH);
}

//функция рисует прямоугольник заданной высоты ширины и цвета, левый верхний угол прямоугольника задается первыми двумя аргументами
void oledRect (uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t colorFrame)
{
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x26); //настройка заливки прямоугольника
SPI.transfer(0x0); //отключаем заливку прямоугольника
SPI.transfer(0x22);
SPI.transfer(x); //x start
SPI.transfer(y); //Y start
SPI.transfer(x + w); //X end
SPI.transfer(y + h); //Y end
delay(1);
SPI.transfer((colorFrame >> 11) & 0x1F); //R color frame
SPI.transfer((colorFrame >> 5) & 0x3F); //G color
SPI.transfer(colorFrame & 0x1F); //B color
delay(10);
digitalWrite(ss, HIGH);
}

//то же самое, но прямоугольникк залит определенным цветом (6 аргумент задает цвет заливки)
void oledRectFill (uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t colorFrame, uint16_t colorFill)
{
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x26); //настройка заливки прямоугольника
SPI.transfer(0x1); //включаем заливку прямоугольника
SPI.transfer(0x22);
SPI.transfer(x); //x start
SPI.transfer(y); //Y start
SPI.transfer(x + w); //X end
SPI.transfer(y + h); //Y end
delay(1);
SPI.transfer((colorFrame >> 11) & 0x1F); //R color frame
SPI.transfer((colorFrame >> 5) & 0x3F); //G color
SPI.transfer(colorFrame & 0x1F); //B color
SPI.transfer((colorFill >> 11) & 0x1F); //R color fill
SPI.transfer((colorFill >> 5) & 0x3F); //G color
SPI.transfer(colorFill & 0x1F); //B color
delay(10);
digitalWrite(ss, HIGH);
}

void oledClear(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x25);
SPI.transfer(x1);
SPI.transfer(y1);
SPI.transfer(x2);
SPI.transfer(y2);
delay(1);
digitalWrite(ss, HIGH);
}

void oledClearAll()
{
oledClear(0, 0, 95, 63);
}

//настройка скролинга дисплея
void oledScrollSetup (uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e)
{
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x27);
SPI.transfer(a);
SPI.transfer(b);
SPI.transfer(c);
SPI.transfer(d);
SPI.transfer(e);
delay(1);
digitalWrite(ss, HIGH);
}

void oledScrollOn()
{
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x2F);
digitalWrite(ss, HIGH);
}

void oledScrollOff()
{
digitalWrite(ss, LOW);
digitalWrite(dc, LOW);
SPI.transfer(0x2E);
digitalWrite(ss, HIGH);
}

void setup() {

pinMode(ss, OUTPUT);
pinMode(dc, OUTPUT);
pinMode(reset, OUTPUT);

SPI.begin();
SPI.setDataMode(SPI_MODE3);
oledInit();
oledClearAll();
randomSeed(millis);
}

void loop() {
oledClearAll();
oledPixel(10, 10, color565(255, 0, 0));
oledLine(45, 32, 40, 63, color565(0, 255, 0));
oledRectFill(60, 0, 10, 20, color565(0, 0, 255), color565(255, 255, 0));
oledRect(40, 0, 10, 20, color565(255, 255, 0));

int x = 20, y = 31, w = 10, h = 10;
oledSetArea(x, y, w, h);
for (int i = 0; i < (w*h); i++) {
oledDataColor(color565(random(0, 255), random(0, 255), random(0, 255)));
}

delay(5000);

}

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

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

P.S. В архиве скетч, библиотеки для ArduinoIDE и даташиты.

Прикрепленные файлы:

Добавить комментарий

Ваш адрес email не будет опубликован.