Библиотека для символьного дисплея на базе HD44780

Хотел бы представить Вашему вниманию свою собственную библиотеку для работы с широко распространёнными символьными дисплеями на базе контроллера HD44780.


Рис.1 Внешний вид дисплея на базе контроллера HD44780 ( 2 строки Х 16 символов).

Библиотека написана на С#, в Atmel Studio 6.2. Библиотека состоит из двух файлов: HD44780_Config.h и HD44780.c. Первый файл является заголовочным, он, собственно, и подключается в Ваш разрабатываемый проект директивой #include «HD44780_Config.h». Также, в этом файле мы прописываем все необходимые нам начальные настройки. Вот, собственно, исходный код этого заголовочно — настроечного файла:

 #ifndef HD44780_Config #define HD44780_Config  #define uchar unsigned char #define Sbit(reg,bit) (reg|=(1< #define Cbit(reg,bit) (reg&=~(1< #define CheckBit(reg,bit) (reg&(1< #define FirstStr_StartPosition_DDRAM_Addr 0x80 #define SecondStr_StartPosition_DDRAM_Addr 0xC0  /*  *указываем разрядность шины данных дисплея (1-8 бит, 0-4 бита)  */ #define Data_Length 0  /*  *указываем количество строк дисплея (1-2 строки, 0-1 строка)  */ #define NumberOfLines 1  /*  *указываем размер шрифта дисплея (1–шрифт 5x10 точек, 0–шрифт 5x7 точек)  */ #define Font 1  /*  *указываем порт МК, к которому подключена линия E  *указываем номер бита порта МК, к которому подключена линия E  */ #define PORT_Strob_Signal_E PORTC #define PIN_Strob_Signal_E 1  /*  *указываем порт МК, к которому подключена линия RS  *указываем номер бита порта МК, к которому подключена линия RS  */ #define PORT_Strob_Signal_RS PORTC #define PIN_Strob_Signal_RS 0  /*  *порты ввода-вывода шины данных дисплея D4-D7  *номер бита порта ввода-вывода шины данных дисплея D4-D7  */ #if Data_Length==0   //4-х проводная шина данных   #define PORT_bus_4 PORTD   #define PIN_bus_4 4   #define PORT_bus_5 PORTD   #define PIN_bus_5 5   #define PORT_bus_6 PORTD   #define PIN_bus_6 6   #define PORT_bus_7 PORTD   #define PIN_bus_7 7 /*  *указываем порты ввода-вывода шины данных дисплея D0-D7  *указываем номер бита порта ввода-вывода шины данных дисплея D0-D7  */ #elif Data_Length==1   //8-ми проводная шина данных   #define PORT_bus_0 PORTD   #define PIN_bus_0 0   #define PORT_bus_1 PORTD   #define PIN_bus_1 1   #define PORT_bus_2 PORTD   #define PIN_bus_2 2   #define PORT_bus_3 PORTD   #define PIN_bus_3 3   #define PORT_bus_4 PORTD   #define PIN_bus_4 4   #define PORT_bus_5 PORTD   #define PIN_bus_5 5   #define PORT_bus_6 PORTD   #define PIN_bus_6 6   #define PORT_bus_7 PORTD   #define PIN_bus_7 7 #endif  /*  *функция инициализации дисплея. Должна вызываться первой.  */ void LCD_Init(void);  /*  *функция команды полной очистки DDRAM-памяти дисплея и установка курсора в  *нулевую позицию  */ void LCD_Full_Clean(void);  /*  *функция команды установки курсора и положения дисплея в нулевую позицию  */ void LCD_CursorPosition_ToStart(void);  /*  *функция команды направления сдвига курсора после записи и разрешения сдви-  *га дисплея вместе с курсором:  *I_D(Increment/Decrement)-направление сдвига курсора после записи (I_D=1-сдвиг вправо, I_D=0–сдвиг влево);  *S(Shift)–разрешение сдвига дисплея вместе с курсором (S=1-сдвиг разрешен, S=0-сдвиг запрещен);  */ void LCD_AutoMovCurDispDirect(uchar I_D, uchar S);  /*  *функция команды включения-выключения дисплея, включение-выключение курсора  *и его мигания:  *D(Display)–включение дисплея (D=1-дисплей включен, D=0-дисплей отключен)  *C(Cursor)-видимость курсора (C=1–видимый курсор, C=0–погашенный курсор);  *B(Blink)-мигание курсора (B=1–курсор мигает, B=0–курсор не мигает);  */ void LCD_DisplEnable_CursOnOffBlink(uchar D, uchar C, uchar B);  /*  *функция команды перемешения дисплея/курсора, направления перемешения:  *S_C(Screen/Cursor)–перемещение дисплея/курсора (S_C=1–перемещается дисплей, S_C=0–перемещается курсор)  *R_L(Right/Left)-направление перемещения дисплея/курсора (R_L=1–перемещение вправо, R_L=0–перемещение влево).  */ void LCD_MovingCurDispDirection(uchar S_C, uchar R_L);  /*  *функция вывода символов на дисплей. Параметры:  *Addr-код символа (адрес в памяти знакогенератора)  *Str-номер строки, в которой нужно вывести символ  *Cursor-позиция символа в строке  */ void LCD_Show(uchar Addr, uchar Str, uchar Cursor);  /*  *функция записи пользовательских символов в память знакогенератора CGRAM  *дисплея. Диапазон адресов параметра Addr: 0х00-0x07 (8 пользовательских симво-  *лов). 1 символ занимает 8 байт данных  */ void LCD_UserSymbolsWrite(uchar Addr, uchar *data);  /*  *функция управляющих сигналов RS, E и шины данных. Вызывается для передачи дан-  *ных дисплею. В качестве параметра RS передаётся 0 или 1. Если 0-команда, 1-данные.  */ void BusLinesState(uchar *data, uchar RS);  #endif

Здесь, в общем и целом, каждая функция и каждый заданный макрос описаны между знаками комментария /* */. Большее внимание хотелось бы уделить макросам, определяющим инициализационные настройки:

 #define Data_Length 0

Данный макрос определяет, по какой схеме Вы хотите подключить свой дисплей к микроконтроллеру — 4-х проводная (Data_Length 0) или 8-ми проводная (Data_Length 1).


Рис.2 Схемы подключения дисплея к МК

а) 8-ми проводная б) 4-х проводная

Если вы выбираете 4-х проводную схему, то побитно записываете порты МК, к которым подключены линии дисплея, в этот макрос:

 #if Data_Length==0   //4-х проводная шина данных   #define PORT_bus_4 PORTD   #define PIN_bus_4 4   #define PORT_bus_5 PORTD   #define PIN_bus_5 5   #define PORT_bus_6 PORTD   #define PIN_bus_6 6   #define PORT_bus_7 PORTD   #define PIN_bus_7 7

Например, где PORT_bus_4 — это имя порта МК, к которому подключена линия дисплея DB4. Аналогично и с записью бита порта: PIN_bus — номер бита порта, к которому подключена линия дисплея DB4.

Если вы выбираете 8-ми проводную схему, то побитно записываете порты МК, к которым подключены линии дисплея, в этот макрос:

 #elif Data_Length==1   //8-ми проводная шина данных   #define PORT_bus_0 PORTD   #define PIN_bus_0 0   #define PORT_bus_1 PORTD   #define PIN_bus_1 1   #define PORT_bus_2 PORTD   #define PIN_bus_2 2   #define PORT_bus_3 PORTD   #define PIN_bus_3 3   #define PORT_bus_4 PORTD   #define PIN_bus_4 4   #define PORT_bus_5 PORTD   #define PIN_bus_5 5   #define PORT_bus_6 PORTD   #define PIN_bus_6 6   #define PORT_bus_7 PORTD   #define PIN_bus_7 7 #endif

Здесь все так же, только проводов больше. Зачем же такие сложности, спросите вы? Ответ прост-благодаря этому, Вы можете подключать линии дисплея абсолютно в разброс по всем портам МК, к которым захотите и ножки которых будут свободны. Просто зачастую получается так, что при проектировании какого-либо устройства не удаётся сохранить абсолютно свободным целый порт. Я часто сталкивался с этой проблемой, и решил её таким вот образом. Здесь Вы не привязаны к конкретным ножкам МК, какие цифры напишете и названия портов в вышеприведённых макросах настройки, по таким линиям микроконтроллера и будет работать ваш дисплей.

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

LCD_UserSymbolsWrite(uchar Addr, uchar *data);

Данная функция позволяет нам записать в энергозависимую память знакогенератора 8 собственных символов, которые Вы сами и придумаете. Для большей ясности, дабы мне не повторять автора, можете почитать интересную статью: //cxem.net/mc/book52.php. Там расписана вся работа дисплея на аппаратном уровне. Моя статья и библиотека призваны упростить применение дисплея=)

Так, я немножко отвлёкся от темы….. Запись в дисплей пользовательских символов!!! — Для упрощения этой задачи, в дополнение к библиотеке, я написал простую программу:


Рис.3 Внешний вид программы для рисования пользовательских символов

Синие квадратики соответствуют не активированным пикселям сегмента дисплея. Кликом мыши можно переключать эти пиксели между видимым состоянием и не видимым. Программа рассчитывает значения байтов данных и автоматически создаёт готовый массив одного символа Symbol[8], состоящего из восьми байт. После того, как вы закончили рисование своего символа, копируете весь массив в Ваш проект и запихиваете его в память дисплея функцией LCD_UserSymbolsWrite вот так:

LCD_UserSymbolsWrite(i,&Symbol[0]);

где i — адрес памяти CGRAM, предназначенный для пользовательских символов. Диапазон адресов: 0х00-0х07;

&Symbol[0] — указатель на нулевой (начало) элемент массива с данными для сегмента.

К статье приложен пример использования, там можно будет конкретно посмотреть тело программы + имеется проект в Протеусе.


Рис.4 Внешний вид программы для рисования пользовательских символов с готовым результатом


Рис.5 и 6 Иллюстрация работы

В общем и целом, вроде бы всё. Если что-то будет непонятно, почитать можно тут: //cxem.net/mc/book52.php.

Если даже после этого останутся вопросы — задавайте в комментариях. Спасибо за внимание!