Графический монохромный дисплей LCD12864B

У данного товара нет оценки
Графический монохромный дисплей LCD12864B

$10.50



Доброе время суток! Наконец-то я получил долгожданный графический монохромный дисплей синего цвета разрешением 128x64. Подробности – далее…


Порадовало то что дисплей пришел в точности, такой как на картинке при заказе.
Обратил внимание на этот факт только потому, что недавно был заказан у другого продавца подобный дисплей синего цвета, а прислали дисплей зелёного цвета.
Упаковка также порадовала: дисплей был аккуратно завёрнут в пупырчатый пакетик красного цвета и заклеен кусочком скотча, также имеется и наклейка со штрихкодом и артикулом продавца.

TinyDeal: Графический монохромный дисплей LCD12864B

Внутри пакета обнаружился сам дисплей, опять же порадовало то, что дисплей доехал без каких либо видимых повреждений и царапин.
На лицевой стороне имеется защитная плёнка.
TinyDeal: Графический монохромный дисплей LCD12864B

На обратной стороне имеется маркировка самого дисплея, выводов интерфейса управления, каждый вывод подписан, также есть построечный резистор VR1, судя по всему это встроенный регулятор контрастности который позволяет не подключать вывод 3 (V0).

TinyDeal: Графический монохромный дисплей LCD12864B

Ну что же, приступим к освоению данного дисплея.
Очень быстро был найден соответствующий datasheet. В запросе в google 12864B PDF быстро находим родной datasheet.
К примеру здесь
Из него выяснилось, что дисплей управляется контроллером ST7920 и заточен под интерфейс SPI, так как контакт 15 (PSB) звонится прямо на землю.
Думаю это легко можно изменить, перекинув резистор R10 на позицию R9. Это конечно догадка, но нам и так сойдет. Разберёмся позже. А ещё был удивлён широким температурным диапазоном работы дисплея, по датащиту он варьируется в диапазоне от -20 и до 70 градусов цельсия!
Ну с распиновкой всё понятно, а как быть с контроллером? Как оказалось в сети полно информации и по контроллеру, например здесь
Поискав побольше информации нашлось и множество примеров подключения, различные примеры работы с данным дисплеем.
Например:
пример 1
пример 2
пример 3
пример 4

Я же буду подключать свой дисплей к микроконтроллеру ATMEGA32 (просто потому что есть и памяти программ хватает для экспериментов)
Писать код буду в Atmel studio 6 которую можно взять на официальном сайте www.atmel.com совершенно бесплатно.
И так, подключаем дисплей по простенькой схемке:
TinyDeal: Графический монохромный дисплей LCD12864B
По началу я решил сэкономить время и воспользоваться примерами и описанием вот отсюда, скачав библиотеки и примеры вот отсюда

Немного поправив код у меня кое что получилось.
Пример кода с использованием библиотеки
#include <avr/io.h>
#include <avr/interrupt.h>
#include «u8g.h»
u8g_t u8g;
void draw(void)
{
u8g_SetFont(&u8g, u8g_font_6x10);
u8g_DrawStr(&u8g, 0, 15, «Hello World!»);
}
int main(void)
{
u8g_InitSPI(&u8g, &u8g_dev_st7920_128x64_sw_spi, PN(2, 2), PN(2, 1), PN(3, 0), U8G_PIN_NONE, PN(3,4) );

for(;;)
{
u8g_FirstPage(&u8g);
do
{
draw();
} while ( u8g_NextPage(&u8g) );
u8g_Delay(100);
}
}

Хотя я прописал частоту тактового генератора в компиляторе, связь с дисплеем была неустойчивой и сильно сыпались пиксели из за помех на шине SPI дисплея. Тем не менее удалось получить вот такую картинку.
TinyDeal: Графический монохромный дисплей LCD12864B
Разбираться и копаться в чужых библиотеках я не стал и потому решил написать свой код с нуля, а заодно и разобраться что к чему.
В итоге был написан вот такой демо-код
#include <avr/io.h>
#include <avr/iom32.h>
#include <avr/delay.h>
// тут указываем на каких выводах сидить наш дисплей
#define CS PC0
#define SID PC1
#define SCLK PC2
#define RES PC4

const unsigned char * pic;
extern const unsigned char qweqwe[];

const unsigned char qweqwe[1024] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xFF,0xE0,0x00,0x7F,0xE0,0x00,0x00,0x00,0x03,0xE0,0x00,
0x00,0x00,0x00,0x00,0x03,0xFF,0xF8,0x00,0xFF,0xF8,0x00,0x00,0x00,0x1F,0xE0,0x00,
0x00,0x00,0x00,0x00,0x0F,0xFF,0xFE,0x03,0xFF,0xFC,0x00,0x00,0x00,0xFF,0xC0,0x00,
0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0x07,0xFF,0xFE,0x00,0x00,0x03,0xFF,0xF8,0x00,
0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0x8F,0xFF,0xFF,0x00,0x00,0x1F,0xFE,0x04,0x00,
0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0xEF,0xFF,0xFF,0x80,0x00,0x7F,0xF0,0x0C,0x00,
0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x01,0xFF,0x80,0x30,0x00,
0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x0F,0xFC,0x01,0xC0,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x1F,0xE0,0x0E,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x7F,0x00,0x70,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0xF8,0x07,0x80,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE1,0xC1,0xF8,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x90,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,0x60,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF8,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xE7,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x79,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0xC1,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x0E,0x00,0xFF,0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x70,0x00,0x7F,0xFF,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x03,0xC0,0x00,0x3F,0xFF,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x9E,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x07,0xF0,0x00,0x00,0x07,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x0F,0xC0,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x3F,0xE0,0x00,0x00,0x01,0xFF,0xFF,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
// Функция инициализации портов
void init_io(void)
{
//Порт A на выход
DDRA=0xFF;
PORTA=0x00;
//Порт B на выход
DDRB=0xFF;
PORTB=0x00;
//Порт С на выход
DDRC=0XFF;
PORTC=0x00;
//Порт В на выход
DDRD=0xFF;
PORTD=0x00;
}
// Функция отправки 1 на дисплей
void SendSPI_1 (void)
{
PORTC|=(1<<SID);
_delay_us(250);
PORTC|=(1<<SCLK);
_delay_us(250);
PORTC&=~(1<<SID);
_delay_us(250);
PORTC&=~(1<<SCLK);
_delay_us(250);
}
// Функция отправки 0 на дисплей
void SendSPI_0 (void)
{
_delay_us(250);
PORTC|=(1<<SCLK);
_delay_us(500);
PORTC&=~(1<<SCLK);
_delay_us(250);
}
// Функция отправки на дисплей бита RS и байта на дсплей
void SendSPI (uint8_t sell, uint8_t Data)
{
unsigned char i;
_delay_us(100);
PORTC&=~(1<<SID)|(1<<SCLK);
_delay_us(100);
// Отправляем на дисплей 5 единиц
for (i=0; i<5; i++) { SendSPI_1(); }
// Отправляем 0
SendSPI_0();
// Отправляем бит RS
if (sell==0) { SendSPI_0(); } else { SendSPI_1(); }
// Отправляем 0
SendSPI_0();
// Отправляем старшие 4 бита
for (i=0; i<4; i++)
{
if (((Data>>(7-i))&0x01)==1) SendSPI_1(); else SendSPI_0();
}
// Отправляем 4 бита равные 0
for (i=0; i<4; i++)
{
SendSPI_0();
}
// Отправляем 4 младших бита
for (i=0; i<4; i++)
{
if (((Data>>(3-i))&0x01)==1) SendSPI_1(); else SendSPI_0();
}
// Отправляем 4 бита равные 0
for (i=0; i<4; i++)
{
SendSPI_0();
}
_delay_us(100);
}
// Функция инициализации дисплея
void QC12864_init (void)
{
_delay_ms(40);
PORTC|=(1<<RES);
_delay_ms(50);
PORTC|=(1<<CS);
SendSPI(0,0x30);
SendSPI(0,0x30);
SendSPI(0,0x0C);
SendSPI(0,0x01);
SendSPI(0,0x06);
}
// Фенкция очистки дисплея в режиме базовых инструкций
void QC12864_clear(void)
{
SendSPI(0,0x01);
_delay_ms(2);
}
// Функция очистки дисплея в режиме графики
void QC12864_clear_graph(void)
{
unsigned int i,tm;
uint8_t ox,oy;
tm=8;
ox=0b10000000;
oy=0b10000000;
SendSPI(0,oy);
SendSPI(0,ox);
for (i=0; i<512; i++)
{
if (i==tm)
{
tm=tm+8;
if (i<256)
{
ox=0b10000000;
} else
{
ox=0b10000000+8;
}
oy++;
if (i==256)
{
oy=0b10000000;
}
SendSPI(0,oy);
SendSPI(0,ox);
}
SendSPI(1,0x00);
SendSPI(1,0x00);
}
}

int main(void)
{
init_io();
QC12864_init();
QC12864_clear();
unsigned int i,tm; // Объявили переменные
uint8_t ox,oy; // Объявили переменные в 8bit
SendSPI(1,0xA9);
SendSPI(1,0xB3);
for (i=0; i<6; i++)
{
SendSPI(1,0xA9);
SendSPI(1,0xA5);
}
SendSPI(1,0xA9);
SendSPI(1,0xB7);
SendSPI(0,0b10000000+16);
SendSPI(1,0xA9);
SendSPI(1,0xA7);
SendSPI(0,0b10000000+23);
SendSPI(1,0xA9);
SendSPI(1,0xA7);
SendSPI(0,0b10000000+8);
SendSPI(1,0xA9);
SendSPI(1,0xA7);
SendSPI(0,0b10000000+15);
SendSPI(1,0xA9);
SendSPI(1,0xA7);
SendSPI(0,0b10000000+24);
SendSPI(1,0xA9);
SendSPI(1,0xBB);
for (i=0; i<6; i++)
{
SendSPI(1,0xA9);
SendSPI(1,0xA5);
}
SendSPI(1,0xA9);
SendSPI(1,0xBF);
_delay_ms(2000);
SendSPI(0,0b00110110); // Перевели дисплей в режим графики
QC12864_clear_graph(); //Функция очистки дисплея
//Передаём на дисплей масив картинки qweqwe
pic = qweqwe; //
ox=0b10000000;
oy=0b10000000;
SendSPI(0,oy);
SendSPI(0,ox);
tm=16;
for (i=0; i<1024; i++)
{
if (i==tm)
{
tm=tm+16;
if (i<512)
{
ox=0b10000000;
} else
{
ox=0b10000000+8;
}
oy++;
if (i==512)
{
oy=0b10000000;
}
SendSPI(0,oy);
SendSPI(0,ox);
}
SendSPI(1,*(pic + i));
}
SendSPI(0,0b00110000); // Перевели дисплей в обычный режим
QC12864_clear(); //очистели
SendSPI(0,0b00110110); // Вернули графику
while(1)
{
//TODO:: Please write your application code
}
}


И так дисплей имеет два набора инструкций для работы. Это basic instruction и extended instruction. Режимы работы можно задать как при инициализации так и в любое время когда потребуется. В конце кода это демонстрируется. Также в данном дисплее имеется знакогенератор и всевозможных символов на разных языках. В основном это китайские символа но есть также английские символа и к великой радости русские.

Для примера выведу на дисплей рамку в режиме basic instruction.
Вот как это выглядит:
TinyDeal: Графический монохромный дисплей LCD12864B
Потом переключаю дисплей в режим графики extended instruction и сразу же вижу много мусора в памяти дисплея которую надо очистить или можно сразу вывести графическое изображение. Я решил очистить дисплей при помощи функции QC12864_clear_graph.

При написании этой функции удалось выяснить интересные моменты о которых я ничего не нашел в datasheet. Первое это интересную адресацию координат в режиме графики при передаче данных через SPI. В дисплей нужно передавать по 2 байта как указано в datasheet. Координаты расположены следующим образом: Сначала загружаются первые 16 байт которые оказываются в первой строке. Это ровно 128 bit (16*8=128). Но вот вторая строка из 128 bit оказывается во второй части дисплея. Причём если адресация по горизонтали (в программе это ox) инкриминируется автоматически, то по вертикали инкремент не происходит и данные пишутся с начала координат, т.е. после 256 bit данные начинают загружаться с начала координат. И так попеременно данные будут загружаться то в первую часть дисплея то во второй. Это на мой взгляд весьма неудобно. Потому пришлось применить хитрость с адресацией чтоб вывести изображение последовательно.

По завершению очистки дисплея увидим рамку которая создавалась в начале. Как видите графика не затрагивает данные которые мы вводили ранее.
Теперь выведем массив из 1024 байт, это простенькая картинка которая находится в массиве qweqwe. Как и с очисткой дисплея пришлось применить хитрый алгоритм.

В итоге подучим вот такую вот картинку:
TinyDeal: Графический монохромный дисплей LCD12864B
Ну и в заключении переключимся в режим basic instruction и очистим дисплей командой QC12864_clear(); и вернём режим графики т.е. extended instruction послав на дисплей команду SendSPI(0,0b00110110);
TinyDeal: Графический монохромный дисплей LCD12864B
К сожалению последовательный интерфейс оказался очень медленным способом вывода графических изображений а потому думаю врятли в дальнейшем буду его использовать с данным дисплеем. А вот по паралельному интерфейсу вполне можно добиться приемлемой скорости даже для простенькой анимации.
Итог:
В общем, я остался доволен, дисплей вполне подходит для многих задач, к примеру реализации часов, метеостанции, гаджетов для авто и многих других приборов где требуется вывод разнообразной информации. Но для новичков мало разбирающихся в программировании дисплей немного сложен в освоении.

9 комментариев

Valendar
Спасибо за интересный и качественный обзор!!! С почином.
Было интересно почитать, я немного далек от этого и всегда было загадкой как выводится то информация на этот дисплей то…
Zloi
  • Zloi
  • +1
Интересный обзор. А для каких целей его покупали вы?
AlexP
Спасибо за интересный обзор. Присоединюсь к вопросу — какая конечная цель использования дисплея? Или просто в качестве экспериментов с Ардуино?
SmirnOFF
А можно подробнее об ардино как то в обзорах — я планирую купить, но еще не знаю, что с ней делать ))
Saiberex
Я планирую на нём сделать типа часиков на тумбочку с датчиками давления (будет составляться график через определённые интервалы), датчиком температуры и влажности. Всё тоже с графиками. Ну и вторая задумка это контроллер водяного охлаждения для компа, хотя на этот счёт возможно использую цветной дисплей и контроллер STM32 купленный в том же магазине обзор о ка тором будет позже.
SmirnOFF
Уххх ты. А потом отчет о реализации будет??! Очень прикольная задумка…
Valendar
А скажите, если купить такой дисплей и не иметь навыков в программировании можно ли что то сделать с ним или даже не стоит побывать?!
Saiberex
К сожалению не имея навыков в программировании и в электроники вряди что сможете сделать.
Valendar
Жаль. Ну желаю Вам удачи, и если потом не сложно покажите конечный результат! Очень интересно!

Оставить комментарий