Про LCD-модули на базе HD44780 (здесь и далее под HD44780 понимается как оригинальный чип, так и совместимые с ним аналоги) я писал уже дважды — в заметке Научился выводить текст на ЖК-индикатор из Arduino , а также Об использовании экранчиков 1602 с I2C-адаптером . В обоих статьях использовался принцип «подключаем экранчик так-то, берем готовую библиотеку, и магия , все работает». Магию, как вы можете помнить, я осуждаю. Поэтому сегодня мы наконец-то разберемся, как устроен протокол подобных дисплеев, и напишем нашу собственную, очень простенькую, библиотеку для работы с ними.

Спрашивается, зачем вообще разбираться в каких-то там протоколах, когда есть готовые библиотеки? Как минимум, выводить что-то на экранчик может хотеться не только с Arduino, но и с отличных от AVR микроконтроллеров (PIC, STM32 , …), а также с какого-нибудь FPGA или даже Raspberry Pi через его GPIO . В этом случае готовой библиотеки у вас может и не быть. Кроме того, готовые библиотеки для Arduino, вроде той же LiquidCrystal, зачастую далеко не оптимальны в плане используемого ими объема flash-памяти, а память у микроконтроллеров не резиновая. Наконец, это просто интересно — разобраться, как же там данные передаются по проводам, что в итоге буковки выводятся.

Итак, работающий прототип у меня получился таким:

Модуль подключается к Arduino точно так же, как было описано в уже упомянутой заметке Научился выводить текст на ЖК-индикатор из Arduino .

Рассмотрим код прошивки:

#include <Arduino.h>

const int PIN_RS = 7 ;
const int PIN_E = 8 ;
const int PIN_D4 = 9 ;
const int PIN_D5 = 10 ;
const int PIN_D6 = 11 ;
const int PIN_D7 = 12 ;

const int LCD_DELAY_MS = 5 ;

void lcdSend ( bool isCommand, uint8_t data ) {
digitalWrite ( PIN_RS, isCommand ? LOW : HIGH ) ;
delay ( LCD_DELAY_MS ) ;

digitalWrite ( PIN_D7, ( data >> 7 ) & 1 ) ;
digitalWrite ( PIN_D6, ( data >> 6 ) & 1 ) ;
digitalWrite ( PIN_D5, ( data >> 5 ) & 1 ) ;
digitalWrite ( PIN_D4, ( data >> 4 ) & 1 ) ;

// Wnen writing to the display, data is transfered only
// on the high to low transition of the E signal.
digitalWrite ( PIN_E, HIGH ) ;
delay ( LCD_DELAY_MS ) ;
digitalWrite ( PIN_E, LOW ) ;

digitalWrite ( PIN_D7, ( data >> 3 ) & 1 ) ;
digitalWrite ( PIN_D6, ( data >> 2 ) & 1 ) ;
digitalWrite ( PIN_D5, ( data >> 1 ) & 1 ) ;
digitalWrite ( PIN_D4, ( data >> 0 ) & 1 ) ;

digitalWrite ( PIN_E, HIGH ) ;
delay ( LCD_DELAY_MS ) ;
digitalWrite ( PIN_E, LOW ) ;
}

void lcdCommand ( uint8_t cmd ) {
lcdSend ( true , cmd ) ;
}

void lcdChar ( const char chr ) {
lcdSend ( false , ( uint8_t ) chr ) ;
}

void lcdString ( const char * str ) {
while ( * str ! = ) {
lcdChar ( * str ) ;
str ++ ;
}
}

void setup ( ) {
pinMode ( PIN_RS, OUTPUT ) ;
pinMode ( PIN_E, OUTPUT ) ;
pinMode ( PIN_D4, OUTPUT ) ;
pinMode ( PIN_D5, OUTPUT ) ;
pinMode ( PIN_D6, OUTPUT ) ;
pinMode ( PIN_D7, OUTPUT ) ;

// 4-bit mode, 2 lines, 5×7 format
lcdCommand ( 0b00110000 ) ;
// display & cursor home (keep this!)
lcdCommand ( 0b00000010 ) ;
// display on, right shift, underline off, blink off
lcdCommand ( 0b00001100 ) ;
// clear display (optional here)
lcdCommand ( 0b00000001 ) ;

lcdCommand ( 0b10000000 ) ; // set address to 0x00
lcdString ( «Using HD44780» ) ;
lcdCommand ( 0b11000000 ) ; // set address to 0x40
lcdString ( «LCD directly! :)» ) ;
}

void loop ( ) {
/* do nothing */
delay ( 100 ) ;
}

Как видите, данные передаются в модуль по четырехбитной шине D4-D7. Если на пин RS модуля подано низкое напряжение, данные воспринимаются, как команда. Если же напряжение на пине высокое, данные выводятся в виде символа. Считывание данных с шины происходит по спаду сигнала (заднему фронту) на пине E.

Наглядная табличка с описанием поддерживаемых команд была найдена мной в статье 1997-го года How to Use Intelligent L.C.D.s, part one [PDF] за авторством Julyan Ilett. Вот эта табличка:

В приведенном выше коде первом делом отправляется команда 0b00110000 , выбирающая четырехбитную передачу данных, двухстрочный режим, и формат символов 5 x 7. Заметьте, что размер шины (4 или 8 бит) передается в 4-м бите команды, а значит чип может интерпретировать команду о желаемом размере шины, не зная размера шины. Какое элегантное решение проблемы курицы и яйца, не находите?

Остальная же часть кода достаточно тривиальна, если не считать адресации символов на индикаторе. Как видите, первому символу в первой строке соответствует адрес 0x00 , а первому символу во второй строке — адрес 0x40 . Спрашивается, а что делать, если у экранчика, скажем, четыре строки? Ведь никакого выбора режима с четырьмя строками в командах не предусмотрено! Оказывается, такие индикаторы обычно имеют ширину 16 символов и адреса в третьей строке начинаются с 0x10 , а в четвертой — 0x50 . То есть, в каком-то смысле такие экранчики даже совместимы с двухстрочными. Вообще, возможных адресов всего лишь 128. То есть, определить, какой адрес какому положению на экране соответствует для данного конкретного экрана, можно обыкновенным перебором.

Размер прошивки получился равным 1438 байтам. Для сравнения, аналогичная прошивка, использующая LiquidCrystal, занимает 2164 байт. Получается, что отказавшись от LiquidCrystal, программу можно сжать на 33.5%, что очень даже неплохой результат! Думаю, что переписав программу на чистый C (см заметку Как я спаял электронные игральные кости на базе ATtiny85 ) результат можно еще улучшить. Если хотите, то можете проверить это утверждение в качестве домашнего задания.

Надеюсь, сей материал был для вас интересен. Полную версию кода к этой заметке вы найдете на GitHub . Как обычно, если после прочтения у вас остались вопросы или появились дополнения, не стесняйтесь воспользоваться комментариями!

Дополнение: Протокол, используемый в I2C-адаптерах к таким экранчикам, рассматривается в посте Микроконтроллеры STM32: работа с экранчиком 1602 по I2C . См также заметку Отображение произвольных символов на ЖКИ 1602 .

admin

Share
Published by
admin

Recent Posts

Лучшие дистрибутивы Linux

Если говорить о том, какие лучшие дистрибутивы Linux мы знаем, то этот список может быть…

6 дней ago

Лучшие браузеры для Ubuntu

Хотя Ubuntu и поставляется со встроенным обозревателем Firefox многие пользователи считают что это не самая…

6 дней ago

Установка Remmina Ubuntu 16.04 или 16.10

Что такое Remmina? Remmina — это совершенно бесплатный и свободный клиент так называемого удаленного рабочего…

6 дней ago

Плюсы Ubuntu

Как мы знаем, Ubuntu это самая популярная сборка из систем на базе ядра Linux. У…

6 дней ago

Выбираем ноутбук для Linux

Выбор ноутбука для каждого пользователя это довольно кропотливый процесс. Люди стараются подобрать ноутбук который будет…

6 дней ago

Установка Linux рядом с Windows 10

Если вы решили ознакомиться с операционной системой Linux более детально и задались вопросом как установить…

6 дней ago