В предыдущей статье, Управление HD44780 дисплеем, была описана работа (подключение, система команд и т.д.) символьного дисплея, на базе HD44780 – совместимого контроллера.
Данная статья представляет собой небольшое руководство по использованию библиотеки управления дисплеем на базе hd44780-совместимого контроллера.
Итак, не буду долго "тянуть кота за хвост”. Библиотека состоит из трех файлов : hd44780.c, hd44780.h и mac.h. Первые два файла как раз и представляют собой библиотеку, а вот в третьем (mac.h), располагаются различные (полезные) макроопределения.
Подключение микроконтроллера к дисплею Первым делом вам следует выбрать (в файле hd44780.h) используемый порт ввода/вывода (PORTA, PORTB, …) и указать какой вывод данного порта (0, 1, 2, 3, …) какому выводу дисплея соответствует (E, RS, D7, D6, …).
К примеру, как показано на предыдущем рисунке, для управления дисплеем используются выводы порта С (макрос LCD_WIRE). Далее, четвертый вывод порта С подключен к выводу Е дисплея (Enable или стробирующий вывод), пятый вывод порта С подключен к выводу RS дисплея (Register Select или Commands/Data Select) и т.д.
Рабочая частота управляющего микроконтроллера Для расчета правильных временных задержек, следует указать (в файле hd44780.h) рабочую частоту управляющего микроконтроллера, для этого, присваиваем макросу MCU_CLK_VALUE любое целое число (значение частоты в МГц) не меньше единицы!
Макрос MCU_WAIT_CYCLES представляет собой число циклов ожидания. У большинства производителей символьных дисплеев, среднее время выполнения одной команды занимает от 2.0μs до 100.0μs. Значение 200 подобрано специально для используемого мной дисплея, что превышает максимальное время ожидания выполнения одной команды (~500μs), для большей надежности. Свою лепту в точность расчета времени ожидания вносит и Си компилятор, так что учитывайте и этот фактор при установке времени ожидания.
Макросы конфигурации дисплея Под конфигурацией подразумевается выбор разрядности интерфейса общения между дисплеем и управляющим микроконтроллером (4-bit или 8-bit), число рабочих строк, а также размер шрифта дисплея.
По умолчанию (DEFAULT_DISPLAY_CONFIG) используется конфигурация DISPLAY_CONFIG_4bit_2L_5x8 : 4-разрядный интерфейс, 2 строчки со шрифтом 5х8 пикселей.
Второй макрос DISPLAY_CONFIG_4bit_1L_5x10 предназначен для работы только с первой строкой дисплея, при этом в качестве шрифта используется 5х10 пикселей.
Поскольку данная библиотека работает с 4-разрядным интерфесов, то выбор 8-разрядного интерфейса напрочь отсутствует. Также, при использовании всех строк, шрифт автоматически устанавливается на 5х8 пикселей, а при использовании одной строки – автоматически устанавливается в 5×10, поэтому выбор других шрифтов отсутствует.
Изменять конфигурацию дисплея во время работы ЗАПРЕЩЕНО, так что все изменения должны касаться только макроса DEFAULT_DISPLAY_CONFIG (присвоение одного из двух макросов).
Макросы режима ввода При помощи этих макросов выбираем, каким образом будут отображаться на дисплее, введеные нами символы : слева на право или справа на лево (как у арабов), плюс активировать сдвиг экрана после заполнения видимой части строки.
По умолчанию, используется ввод символов слева на право без сдвига видимой части дисплея (ENTRY_MODE_INC_NO_SHIFT), т.е. если вы введете, скажем для 16-ти символьного дисплея, строчку из 17 символов, то последний символ не будет виден, так как он на данный момент находится в неотображаемой области дисплея (DDRAM памяти). Если в качестве режима ввода, вы выберете режим ENTRY_MODE_INC_WITH_SHIFT (слева на право, со сдвигом), то тогда, при вводе 17-ти символьной строчки, отображаться будет только последний символ, так как предыдущая видимая область (16 символов подряд) дисплея была заполнена и дисплей перешел на следующую область видимости (следующие 16 ячеек DDRAM памяти).
При желании, режим ввода можно менять во время работы дисплея, при помощи команды :
lcd_cmd(ENTRY_MODE,0); // где вместо ENTRY_MODE используйте один из четырех макросов
Макросы управления отображением дисплея Эти макросы (режимы отображения дисплея) можно использовать для включения/выключения дисплея, курсора и мигающего квадрата (Blink).
По умолчанию дисплей включен (.. что естественно :) ), а вот курсор и мигающий квадрат отключены.
При желании, можно менять во время работы дисплея режимы отображения (к примеру отключать дисплей на некоторое время, включить курсор, и т.д.), при помощи команды :
lcd_cmd(VIEW_MODE,0); // где вместо VIEW_MODE используйте один из пяти макросов
Описание функций void lcd_cmd(int8u_t data, int16u_t loop); Функция "lcd_cmd(data, loop)", является низкоуровневой функцией, которая используется для передачи как команд, так и данных (перед отправкой данных следует установить высокий уровень на выводе RS, а после отправки сбросить уровинь вывода RS). Поскольку для передачи данных используется функции lcd_putc(data) / lcd_prints("string”) / lcd_itostr(number) / lcd_numTOstr(number, nDigit), то функцию "lcd_cmd(data, loop)” рекомендуется использовать только для передачи команд дисплею.
Параметр "loop” предназначен для указания дополнительной временной задержки после выполнения функции "lcd_cmd”. В большинстве случаев дополнительная задержка не используется ("loop =0″).
void lcd_clrscr(void); Очищает всю DDRAM память, т.е. всю видимую и скрытую области дисплея.
void lcd_return(void); Возвращает курсор в первую ячейку первой строки дисплея (DDRAM памяти), т.е. в верхний левый угол дисплея.
void lcd_goto(int8u_t line, int8u_t address); При помощи функции lcd_goto(line, address) можно перемещать курсор между ячейками одной строки, между ячейками разных строк, а также между ячейками разных областей памяти (DDRAM или CGRAM памяти).
В качестве параметра "line” следует указать номер строки (1, 2, .. ) на которую собираетесь переместить курсор (аналогично оси ординат Y), а в качестве параметра "address” следует указать номер ячейки (0, 1, 2, .., 15, ..) на этой строке (аналогично оси абсцисс X).
К примеру:
lcd_goto(1, 10); lcd_putc('A'); lcd_goto(2,3); lcd_putc('B'); lcd_goto(2,12); lcd_putc('C');
Рис. 2x16 дисплей Также, при помощи функции lcd_goto(CGRAM, address) (где "address” это номер регистра CGRAM памяти), можно переместить курсор в CGRAM память (для записи пользовательского символа).
Внимание Для записи пользовательского символа в CGRAM память, рекомендую пользоваться предназначенные для этого функциями : lcd_load / lcd_drawchar.
void lcd_prints(const int8u_t *p); Функция "lcd_prints” предназначена для вывода символьной строки (массив типа char, заканчивающийся нулем) на дисплей (DDRAM память). Также, для большего удобства работы с дисплеем, можно активировать форматированный вывод символов (cистемные символы : ‘\n‘, ‘\t‘, ‘\r‘). Для этого следует присвоить макросу USE_FORMATTED_OUTPUT значение "1″. Чтобы отключить использование форматированного вывода, следует присвоить этому макросу значение "0″.
- Символ перехода на новую строку (‘\n‘) используется только для перехода со строки #1 на строку #2!
- Символ возврат каретки (‘\r‘) аналогичен функции "lcd_return()” и возвращает курсор в первую ячейку первой строки дисплея (DDRAM памяти), т.е. в верхний левый угол дисплея! Символ ‘\r‘ можно использовать для перемещения курсора в начало первой строки, а символ ‘\n‘ использовать для перемещения курсора в начало второй строки.
- Символ табуляции (‘\t‘) имеет то же предназначение что и системный символ ‘\t’. Для управления шагом табуляции используется макрос TAB_SPACE, значения которого могут быть : 1, 2, 4 или 8.
Пример использования :
lcd_prints("\tHello World\nfrom\t\tGrAnd\r");
Рис. 2x16 дисплей void lcd_putc(int8u_t data); Функция "lcd_putc” используется для вывода символов на дисплей (запись DDRAM памяти).
void lcd_load(int8u_t *vector, int8u_t position); Функция "lcd_load” используется для загрузки пользовательского символа в CGRAM память. Размер символа зависит от конфигурации дисплея (макрос DEFAULT_DISPLAY_CONFIG), а также от значения макроса DRAW_CHAR_SIZE (8 или 11), которые по умолчанию соответствуют символам 5х8 пикселей.
Параметр "vector” является массивом (типа unsigned char) шириной DRAW_CHAR_SIZE, где каждый элемент массива представляет собой один ряд пикселей пользовательского символа. Параметр "position” выполняет два предназначения : во первых указывает области CGRAM памяти (DRAW_CHAR_SIZE байт подряд) для загрузки пользовательского символа (0, 1, 2, .. 7, ..), а во вторых представляет собой кодировку нового пользовательского символа.
Рис. 5х8 шрифт Пример использования :
unsigned char CHESS[DRAW_CHAR_SIZE] = {0x19,0x19,0x06,0x06,0x19,0x19,0x06,0x06}; lcd_load(CHESS,0); В этом примере мы загрузили пользовательский символ CHESS (массив типа unsigned char, шириной DRAW_CHAR_SIZE байт) с 5х8 шрифтом в первую восьмерку (отсчет начинается с нуля) байт CGRAM памяти (на это указывает значение параметра "position = 0″) и с этого момента кодировкой символа CHESS является 0 (ноль), т.е. область памяти куда мы записали пользовательский символ.
unsigned char MOTO[DRAW_CHAR_SIZE] = {0x04,0x04,0x1f,0x1f,0x04,0x04,0x1f,0x1f}; lcd_load(MOTO,2); Здесь мы загрузили символ МОТО в третью восьмерку байт CGRAM памяти (на это указывает значение параметра "position = 2″) и с этого момента кодировкой символа МОТО является 2 (два).
При использовании функции lcd_load следует быть осторожными, так как после первого вызова функции, курсор перемещается в адресное пространство CGRAM памяти и любая попытка вывести на дисплей (DDRAM адресное пространство) ASCII/пользовательские символы провалится. Осторожность заключается в том, что перед тем как выводить ASCII/пользовательские символы на дисплей, следует вернуться в адресное пространство DDRAM памяти, при помощи функции "lcd_goto(line, address)”, где в качестве значения line должен быть указан номер строки дисплея, а в качестве address номер ячейки.
При помощи функции "lcd_load” можно записать несколько символов подряд в CGRAM память, без вывода их на дисплей (DDRAM память).
lcd_goto(1,0); // возврощаемся в адресное пространство DDRAM памяти // выводим символ CHESS lcd_putc(0); // выводим символ с кодировкой "0" lcd_putc('F'); lcd_putc('1'); lcd_putc(0); // выводим символ MOTO lcd_goto(2,0); lcd_putc(2); // выводим символ с кодировкой "2" lcd_prints("MOTO"); lcd_putc(2);
Рис. вывод пользовательского символа void lcd_drawchar(int8u_t *vector, int8u_t position, int8u_t line, int8u_t address); Функция "lcd_drawchar” как и функция "lcd_load” записывает пользовательский символ (параметр vector) в некоторую область CGRAM память (параметр position), но в отличии от "lcd_load” сразу выводит этот символ на дисплей в указанную строку и ячейку (параметры "line” и "address”).
// пользовательский символ 5х8 unsigned char CHESS[DRAW_CHAR_SIZE] = {0x19,0x19,0x06,0x06,0x19,0x19,0x06,0x06}; lcd_drawchar(CHESS,4,2,7); // загружаем символ CHESS в пятую восьмерку байт CGRAM памяти // выводим пользовательский символ // на вторую строку дисплея в ячейку номер семь lcd_putc('F'); lcd_putc(0x31); // выводим символ с кодировкой 0x31 lcd_putc(4); // вывод символа с кодировкой 4 (четыре)
void lcd_backspace(void); Функция "lcd_backspace()” используется для очистки ячейки DDRAM памяти слева от курсора.
void lcd_scroll(int8u_t direction); Каждый вызов функции "lcd_scroll” смещает видимую часть дисплея (DDRAM памяти) влево/вправо (при помощи макросов LEFT и RIGHT) на одну позицию. При помощи данной функции можно получить эффект "бегущей строки”.
lcd_scroll(RIGHT); // смещение вправо видимой части дисплея for(i=0;i<N;i++){ lcd_scroll(LEFT); // смещение N-раз влево видимой части дисплея _delay_ms(500); } void cursor_shift(int8u_t direction); Каждый вызов функции "cursor_shift” смещает курсор влево/вправо (при помощи макросов LEFT и RIGHT) на одну позицию. Эту функцию можно использовать для редактирования в режиме реального времени ошибок при вводе значений с клавиатуры (к примеру кодовый замок).
void lcd_itostr(int32s_t value); Функция "lcd_itostr” выводит целые числа (в диапазоне +/- 2147483647) на дисплей.
unsigned long data = 78336; lcd_itostr(data); lcd_goto(2,0); lcd_itostr(-100006);
void lcd_numTOstr(int16u_t value, int8u_t nDigit); Функция "lcd_numTOstr” используется для вывода нескольких разрадов целого числа (в диапазоне : 0 .. 65535) на дисплей. В случае если у выводимого числа меньше разрядов чем указано в параметре nDigit, то тогда оставшиеся разряды заполняются нулями, т.е. "выводимое число” занимает фиксированное число ячеек дисплея, что в некоторых ситуациях весьма полезное свойство (см. ниже процент заполнения).
unsigned long data = 7833; lcd_numTOstr(data,2);
Progress Bar Для использования свойства Progress Bar (индикатор выполнения), в заголовочном файле hd44780.h следует присвоить единицу макросу USE_PROGRESS_BAR. В противном случае следует присвоить ноль.
Далее, если индикатор выполнения активирован, то тогда в первые шесть областей CGRAM память загружаются шесть символов (NUMBER_OF_CELL_ELEMENTS) используемых индикатором. Соответственно в эти области CGRAM памяти запрещено загружать пользовательские символы, .. только в области начиная с 7-ой (символы с кодировкой 6, 7, ..).
Для выбора строки на которой будет отображаться индикатор, следует присвоить макросу DRAW_PROGRESS_BAR_ON_LINE номер этой строки (1, 2, ..). Также можно указать высоту (в пикселях) и ширину (число ячеек) индикатора (PROGRESS_BAR_HEIGHT и PROGRESS_BAR_WIDTH соответственно). Запрещено выводить символы в ячейки используемые индикатором.
Для управления заполнением индикатора используются две функции :
void lcd_drawbar(int8u_t data); Индикатор выполнения мгновенно заполняется до значения передаваемого через параметр "data”. Индикатору можно присваивать значения между : 0 .. NUMBER_OF_BAR_ELEMENTS. Во время работы, заполнение индикатора может как увеличиваться (передавая значение больше предыдущего) так и уменьшаться (передавая значение меньше предыдущего). Макрос NUMBER_OF_BAR_ELEMENTS представляет собой число шагов нужные индикатору для полного заполнения.
void lcd_clearbar(void); Функция "lcd_clearbar()” очищает ячейки индикатора, т.е. переводит индикатор в начальное положение.
Пример использования :
#define USE_PROGRESS_BAR 1 /* 1 or 0 */ #define DRAW_PROGRESS_BAR_ON_LINE 2 /* Select lcd line: 1, 2, 4, ... */ #define PROGRESS_BAR_HEIGHT 5 /* in pixel: 1(min),2,3,4,5,6,7,8(max) */ #define PROGRESS_BAR_WIDTH 10
lcd_prints("\tLoading...");
lcd_goto(DRAW_PROGRESS_BAR_ON_LINE, PROGRESS_BAR_WIDTH); lcd_prints("[ %]");
for(i=0;i<NUMBER_OF_BAR_ELEMENTS;i++){ lcd_goto(DRAW_PROGRESS_BAR_ON_LINE, PROGRESS_BAR_WIDTH + 1); lcd_numTOstr( (i*100)/NUMBER_OF_BAR_ELEMENTS, 3 ); lcd_drawbar(i); _delay_ms(500); }
Рис. 2х16 дисплей В этом примере, первые десять ячеек (макрос PROGRESS_BAR_WIDTH) второй строки (макрос DRAW_PROGRESS_BAR_ON_LINE) выделены под индикатор заполнения. Оставшиеся шесть ячеек второй строки используются для вывода процента заполнения. На первой строке выводится произвольный текст.
#define USE_PROGRESS_BAR 1 /* 1 or 0 */ #define DRAW_PROGRESS_BAR_ON_LINE 1 /* Select lcd line: 1, 2, 4, ... */ #define PROGRESS_BAR_HEIGHT 8 /* in pixel: 1(min),2,3,4,5,6,7,8(max) */ #define PROGRESS_BAR_WIDTH 16
lcd_goto(2,0); lcd_prints("\tLoading..."); for(i=0;i<NUMBER_OF_BAR_ELEMENTS;i++) { lcd_drawbar(i); _delay_ms(500); }
Рис. 2х16 дисплей В этом примере для вывода индикатора заполнения используется первая строка (DRAW_PROGRESS_BAR_ON_LINE). Высота индикатора составляет 8 пикселей (PROGRESS_BAR_HEIGHT).
void lcd_init(void); Функцмя "lcd_init()” вызывается (до начала использования дисплея) для инициализации дисплея (конфигурация дисплея, выбор режима ввода и т.д.). Поскольку в функцию "lcd_init()” не входит инициализация выводов порта микроконтроллера (E, RS, D7, ..) для работы с дисплеем, то пользователю перед инициализацией дисплея следует самостоятельно выставить выводы порта на выход. Для AVR это выглядит так :
PORTC &=~ (1<<E)|(1<<RS)|(1<<D7)|(1<<D6)|(1<<D5)|(1<<D4); DDRC |= (1<<E)|(1<<RS)|(1<<D7)|(1<<D6)|(1<<D5)|(1<<D4); lcd_init(); Для чего это было задумано см. в разделе "Кроссплатформенность”.
Кроссплатформенность Изначально библиотека была задумана как универсальная библиотека для любого управляющего микроконтроллеров (AVR, PIC, STM32, …), но протестировать ее удалось только на AVR микроконтроллерах.
Есть платка с STM32F103RB, но никак руки не доходят сделать шлейф для дисплея.
Для использования того или иного микроконтроллера, следует в файле mac.h включить заголовочный файл нужного вам микроконтроллера (к примеру avr/io.h или stm32f10x.h и т.д.).
Последнее изменение, на пути использования нужного вам микроконтроллера является изменение значения макроса LCD_WIRE (по умолчанию, как и в случае с заголовочным файлом, используется имя порта AVR микроконтроллера). К примеру, вместо PORTC (для AVR микроконтроллеров) поставить GPIOC->ODR (для STM32F10x микроконтроллеров) и т.д.
По этому же поводу (стремление к кроссплатформенности) в инициализацию дисплея (lcd_init()) не включена инициализация порта ввода/вывода, поскольку в разных микроконтроллерах инициализация производится по разному. Пользователю придется самостоятельно инициализировать (как выходы) используемые выводы порта (E, RS, D7, D6, D5, D4).
По этому же поводу библиотека не читает никаких данных из дисплея (поскольку в разных микроконтроллерах чтение происходит по разному, точнее переключение порта между входом и выходом).
gpio_init(); // инициализация порта ввода/вывода lcd_init(); // инициализация дисплея А в остальном, ногодруг он везде ногодруг.
Спасибо за внимание. Желаю успехов в использовании библиотеки. Если будут вопросы/замечания, милости просим в комментарии.
|