Окт 222012
 

В предыдущей статье, Управление HD44780 дисплеем, была описана работа (подключение, система команд и т.д.) символьного дисплея, на базе HD44780 – совместимого контроллера. Данная статья представляет собой небольшое руководство по использованию драйвера для дисплеев на базе HD44780-совместимого контроллера.

Итак, не буду долго “тянуть кота за хвост”. Драйвер состоит из трех файлов:

  • hd44780.c и hd44780.h - драйвер HD44780-совместимого контроллера.
  • lcd_cfg.h - все настройки HD44780-драйвера осуществляются из этого файла.

Внимание : статья обновлена 24 Сентября 2014.

Подключение микроконтроллера к ЖК дисплею

Для того чтобы подключить управляющий микроконтроллер к ЖК дисплею, вам следует указать (в файле lcd_cfg.h) для каждого ЖК вывода, какой порт и вывод данного порта ему соответствует (к примеру: первый вывод порта “A” подключен к выводу “E” дисплея, третий вывод порта “B” подключен к выводу “RS” дисплея и т.д.). При желании, все выводы дисплея могут быть подключены к одному порту микроконтроллера. Такой подход позволяет “разбросать” выводы дисплея по разным портам управляющего микроконтроллера, что несомненно более удобно при разработке печатной платы/устройства.

Рис. Настройка выводов управления и данных
Рис. 1 Настройка выводов управления и данных
Инициализация ЖК дисплея
default_config
Рис.2 Режимы работы “по умолчанию” (в файле lcd_cfg.h)

DEFAULT_DISPLAY_CONFIG – выбор разрядности шины, число используемых строк и размер шрифта. Поскольку данный драйвер работает с 4-разрядным интерфейсов, то выбор 8-разрядного интерфейса напрочь отсутствует. Также, при использовании всех строк, шрифт автоматически устанавливается на 5×8 пикселей, а при использовании одной строки – автоматически устанавливается в 5×10, поэтому выбор других шрифтов также отсутствует. Для настройки 4-х строчного дисплея используйте тот же макрос что и для 2-х строчного (DISPLAY_CONFIG_4bit_2L_5x8).
После инициализации дисплея невозможно изменить разрядность шины/число строк/размер шрифта! Так что метод инициализации дисплея указывайте при помощи DEFAULT_DISPLAY_CONFIG макроса.

disp_cfg
Рис. 3 Методы инициализации дисплея (в файле hd44780.h)

DEFAULT_ENTRY_MODE – настройка “режима ввода” (выбираем каким образом будут отображаться на дисплее, введенные нами символы : слева направо или справа налево (как у арабов), плюс сдвигать или нет весь экран после заполнения видимой части строки). По умолчанию, используется ввод символов слева направо, без сдвига видимой части строки (ENTRY_MODE_INC_NO_SHIFT), т.е. если вы введете, скажем для 16-ти символьного дисплея, строчку из 17 символов, то последний символ не будет виден, так как он на данный момент находится в не отображаемой области дисплея (DDRAM памяти). Если в качестве режима ввода, вы выберете режим ENTRY_MODE_INC_WITH_SHIFT (слева направо, со сдвигом), то тогда, при вводе 17-ти символьной строчки, отображаться будет только последний символ, так как предыдущая видимая область (16 символов подряд) дисплея была заполнена и дисплей перешел на следующую область видимости (следующие 16 ячеек DDRAM памяти).
После инициализации дисплея, можно изменить “режим ввода” при помощи функции lcd_setmode( ).
К примеру:

lcd_setmode(ENTRY_MODE_DEC_WITH_SHIFT); // Справа налево, со сдвигом при заполнении.
disp_entry
Рис. 4 Режимы ввода (в файле hd44780.h)

DEFAULT_VIEW_MODE – настройка “режима отображения” : включить/выключить дисплей (для энергосбережения),  включить/выключить курсор и/или мигающий квадрат (для создания “терминала ввода” или т.п.). По умолчанию дисплей включен (.. что естественно :) ), а вот курсор и мигающий квадрат отключены.
После инициализации дисплея, можно изменить режим отображения при помощи функции lcd_setmode( ).
К примеру:

lcd_setmode(VIEW_MODE_DispOff_BlkOff_CrsOff); // Выключить дисплей на неопределенное время.
lcd_view
Рис. 5 Режимы отображения (в файле hd44780.h)

USE_BUSY_FLAG – использовать или нет флаг “занятости” дисплея. По сути, при помощи этого макроса, мы выбираем какой тип задержки будем использовать после отправки команды дисплею: аппаратную или программную. В зависимости от значения данного макроса (“1″ или “0″), также потребуется изменить и некоторые другие макросы в файле lcd_cfg.h :

USE_BUSY_FLAG = “0” – для определения правильных временных задержек, драйвер использует программный цикл ожидания (wait loop). В данном режиме вывод “RW” дисплея не используется драйвером, так что его либо следует “посадить” на землю (экономим один вывод управляющего микроконтроллера), либо присвоить выводу LCD_RW значение “0″.

disp_time

Для того чтобы правильно рассчитать временные задержки, первым делом следует указать частоту тактирования управляющего микроконтроллера.

MCU_FREQ_VALUE – частота управляющего микроконтроллера в единицах МГц. Минимальное значение равно 1 (МГц) !

BUSY_CYCLE_TIME – максимальное время выполнения HD44780 команды (кроме “очистки дисплея” и “возврата каретки”). Значения следует присваивать в десятках микросекунд. К примеру значение “5″ равно 50-ти микросекундам.

CLRSCR_CYCLE_TIME – время выполнения команды “очистка дисплея” (clear display). Значения следует присваивать в десятках микросекунд. К примеру значение “200″ равно 2-м миллисекундам (2000 микросекунд).

RETHOME_CYCLE_TIME – время выполнения команды “возврат каретки” (return home). Значения следует присваивать в десятках микросекунд. К примеру значение “200″ равно 2-м миллисекундам (2000 микросекунд).

USE_BUSY_FLAG = “1” – для определения правильных временных задержек, драйвер опрашивает флаг “занятости” дисплея. В данном режиме, драйвер использует выводы “RW” и “D7″ дисплея для чтения состояния флага “занятости”.

disp_d7

Для чтения состояния флага “занятости”, первым делом следует указать входной порт вывода “D7″ дисплея, а также заполнить две функции (callbacks) для переключения вывода “D7″ на вход и выход соответственно.

LCD_D7_IN - входной порт управляющего микроконтроллера к которому подключен вывод “D7″ дисплея.

lcd_D7

Set_D7_as_Input( ) – макрос предназначенный для переключения вывода LCD_D7 на вход (для чтения состояния флага “занятости”). К примеру для AVR микроконтроллеров этот макрос может выглядеть следующим образом :

DDRx &=~ (1 << LCD_D7) // где x - имя порта а LCD_D7 - номер вывода

Set_D7_as_output( ) – макрос предназначенный для переключения вывода LCD_D7 на выход (для возврата в исходное состояние, т.е. для записи данных/команд). К примеру для AVR микроконтроллеров этот макрос может выглядеть следующим образом :

DDRx |= (1 << LCD_D7) // где x - имя порта а LCD_D7 - номер вывода

Замечание: несмотря на то что время выполнения команды определяется при помощи флага “занятости” (USE_BUSY_FLAG = “1″), программная задержка все еще используется для расчета очень малых, но необходимых задержек, поэтому следует указать правильное значение для макроса MCU_FREQ_VALUE и присвоить значение от “0″ до “10″ макросу BUSY_CYCLE_TIME (используется для инициализации дисплея).

Настройка индикатора выполнения

lcd_bar

Для использования индикатора выполнения (Progress Bar), следует присвоить макросу USE_PROGRESS_BAR значение “1″. В этом случае становятся доступными ряд служб для управления индикатором выполнения, а также в первые 6 секторов CGRAM памяти (6×8 байт) загружаются элементы индикатора выполнения.

USE_PROGRESS_BAR – использовать или нет индикатор выполнения. Если USE_PROGRESS_BAR = “1″, то тогда запрещено загружать в первые 6 секторов CGRAM памяти пользовательские символы.

USE_REGRESS_BAR – если этому макросу присвоено значение “1″, то индикатор выполнения может как увеличиваться так и уменьшаться, в зависимости от входного значения. Если присвоено значение “0″, то тогда индикатор может только увеличиваться.

PROGRESS_BAR_LINE – выбор строчки, на которой будет отображаться индикатор выполнения (1, 2, 3 или 4).

PROGRESS_BAR_HEIGHT – указываем высоту (в пикселях) индикатора выполнения (от 1 до 8 пикселей).

PROGRESS_BAR_WIDTH – указываем ширину (число знакомест) индикатора выполнения. Максимальное значение (100% заполнение) индикатора выполнения можно узнать при помощи макроса PROGRESS_BAR_MAX_LOAD. Индикатор выполнения занимает ячейки от “0″ до “PROGRESS_BAR_WIDTH – 1″ строчки PROGRESS_BAR_LINE.

Другие настройки

lcd_other

Для 4-х строчных дисплеев можно указать начальные адреса третьей (START_ADDRESS_3rd_LINE) и четвертой (START_ADDRESS_4th_LINE) строки для перехода на эти адреса при помощи функции lcd_goto.

USE_FORMATTED_OUTPUT – использовать (значение “1″) или нет (значение “0″) форматированный вывод символов на дисплей. Для форматированного вывода используется функция lcd_puts.

TAB_SPACE – если форматированный вывод используется, то тогда можно указать число пробелов для символа табуляции (“\t”). Этому макросу можно присвоить значения от “0″ до “255″.

Описание функций
void lcd_setmode(uint8_t param);

Функцию lcd_setmode(param) следует использовать для установки нового режима ввода (entry mode) или нового режима отображения (display control). Доступны следующие режимы работы дисплея (в файле hd44780.h) :

lcd_entry

Рис. Режимы ввода

lcd_view

Рис. Режимы отображения

void lcd_clrscr(void);

Очищает всю DDRAM память, т.е. всю видимую и скрытую области дисплея.

void lcd_return(void);

Возвращает курсор в первую ячейку первой строки дисплея (DDRAM памяти), т.е. в верхний левый угол дисплея.

void lcd_goto(uint8_t line, uint8_t address);

При помощи функции lcd_goto(line, address) можно перемещать курсор между ячейками одной строки, между ячейками разных строк, а также между ячейками разных областей памяти (DDRAM или CGRAM памяти).

В качестве параметра “line” следует указать номер строки (1, 2, 3 или 4) на которую собираетесь переместить курсор (аналогично оси ординат Y), а в качестве параметра “address” следует указать номер ячейки (0, 1, 2, .., 15, .. 19) на этой строке (аналогично оси абсцисс X). Также можно использовать макросы (из файла hd44780.h) вместо констант (1, 2, 3 или 4), для перехода на другую строчку :

lcd_line

К примеру:

lcd_goto(1, 10);
lcd_putc('A');
lcd_goto(LCD_2nd_LINE, 3);
lcd_putc('B');
lcd_goto(2, 12);
lcd_putc('C');
Рис. 2×16 дисплей

Также, при помощи функции lcd_goto(CGRAM, address) (где “address” это номер регистра CGRAM памяти), можно переместить курсор в CGRAM память (для записи пользовательского символа).

Внимание: для записи пользовательского символа в CGRAM память, рекомендую пользоваться предназначенные для этого функциями : lcd_loadchar и lcd_drawchar.

void lcd_puts(const uint8_t *string);

Функция lcd_puts(“string”) предназначена для вывода символьной строки (массив типа char, заканчивающийся нулем) на дисплей (DDRAM память). Также, для большего удобства работы с дисплеем, можно активировать форматированный вывод символов (системные символы : ‘\n‘, ‘\t‘, ‘\r‘) на дисплей при помощи макроса USE_FORMATTED_OUTPUT.

  • Символ перехода на новую строку (‘\n‘) используется только для перехода на строку #2, если даже вы используете 4-х строчный дисплей.
  • Символ возврат каретки (‘\r‘) аналогичен функции lcd_return( ) и возвращает курсор в первую ячейку первой строки дисплея (DDRAM памяти), т.е. в верхний левый угол дисплея! Символ ‘\r‘ можно использовать для перемещения курсора в начало первой строки, а символ ‘\n‘ использовать для перемещения курсора в начало второй строки.
  • Символ табуляции (‘\t‘) имеет то же предназначение что и системный символ ‘\t’. Для управления шагом табуляции используется макрос TAB_SPACE, значения которого могут быть от “0″ до “255″.

Пример использования :

lcd_puts("\tHello World\nfrom\t\tGrAnd\r");
Рис. 2×16 дисплей
void lcd_putc(uint8_t data);

Функция lcd_putc(data) используется для записи символов в DDRAM (вывода символов на дисплей) или CGRAM память (предварительно следует перейти в адресное пространство CGRAM памяти при помощи функции lcd_goto(CGRAM, address)).

Внимание: для записи пользовательского символа в CGRAM память, рекомендую пользоваться предназначенные для этого функциями : lcd_loadchar и lcd_drawchar.

void lcd_loadchar(uint8_t *vector, uint8_t position);

Функция lcd_loadchar(symbol, position) используется для загрузки пользовательского символа (шрифт 5×8 пикселей) в CGRAM память.

Параметр “vector” является массивом (типа unsigned char) шириной FONT_HEIGHT (8 байт), где каждый элемент массива представляет собой один ряд пикселей (начиная с верхнего) пользовательского символа (старшие 3 пикселя каждой строки игнорируются дисплеем). Параметр “position” выполняет два предназначения : во первых указывает области CGRAM памяти (FONT_HEIGHT байт подряд) для загрузки пользовательского символа (0, 1, 2, .. 7), а во вторых представляет собой кодировку нового пользовательского символа.

Замечание: после вызова функции lcd_loadchar, курсор перемещается в верхний левый угол дисплея (адрес “0″ DDRAM памяти).

Рис. 5х8 шрифт

Пример использования :

unsigned char CHESS[FONT_HEIGHT] = {0x19,0x19,0x06,0x06,0x19,0x19,0x06,0x06};
lcd_loadchar(CHESS, 0);

В этом примере мы загрузили пользовательский символ CHESS (массив типа unsigned char, шириной FONT_HEIGHT байт) с 5×8 шрифтом в первую восьмерку (отсчет начинается с нуля) байт CGRAM памяти (на это указывает значение параметра “position = 0″) и с этого момента кодировкой символа CHESS является “0″ (ноль), т.е. область памяти куда мы записали пользовательский символ.

Пример :

unsigned char MOTO[FONT_HEIGHT] = {0x04,0x04,0x1f,0x1f,0x04,0x04,0x1f,0x1f};
lcd_loadchar(MOTO, 2);

Здесь мы загрузили символ МОТО в третью восьмерку байт CGRAM памяти (на это указывает значение параметра “position = 2″) и с этого момента кодировкой символа МОТО является “2″ (два).

lcd_putc(0); // Выводим символ с кодировкой "0"
lcd_putc('F');
lcd_putc('1');
lcd_putc(0);
// Выводим символ MOTO
lcd_goto(2,0);
lcd_putc(2); // Выводим символ с кодировкой "2"
lcd_puts("MOTO");
lcd_putc(2);
Рис. вывод пользовательского символа
void lcd_drawchar(uint8_t *vector, uint8_t position, uint8_t line, uint8_t address);

Функция lcd_drawchar, как и функция lcd_loadchar, записывает пользовательский символ (параметр vector) в некоторую область CGRAM память (параметр position), но в отличии от lcd_loadchar, сразу выводит этот символ на дисплей в указанную строку и ячейку DDRAM памяти (параметры “line” и “address”).

Пример использования :

// Пользовательский символ 5x8
unsigned char CHESS[FONT_HEIGHT] = {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(uint8_t direction);

Каждый вызов функции lcd_scroll смещает видимую часть дисплея (DDRAM памяти) влево/вправо (при помощи макросов LEFT и RIGHT) на одну позицию. При помощи данной функции можно получить эффект “бегущей строки”.

Пример :

for(i=0; i<N; i++){
lcd_scroll(LEFT); // Смещение N-раз влево видимой части дисплея
_delay_ms(500);
}
void cursor_shift(uint8_t direction);

Каждый вызов функции cursor_shift смещает курсор влево/вправо (при помощи макросов LEFT и RIGHT) на одну позицию. Эту функцию можно использовать для редактирования в режиме реального времени ошибок при вводе значений с клавиатуры (к примеру “кодовый замок”, “терминал ввода” и т.п.).

void lcd_itos(int32_t value);

Функция lcd_itos выводит целые числа (в диапазоне +/- 2147483647) на дисплей.

Пример использования :

unsigned long data = 78336;
lcd_itos(data);
lcd_goto(2, 0);
lcd_itos(-100006);

void lcd_ftos(float value, uint8_t n);

Функция lcd_ftos выводит на дисплей числа с плавающей точкой. Параметр “n” указывает сколько символов после точки отображать.

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

void lcd_ntos(uint32_t value, uint8_t nDigit);

Функция lcd_ntos используется для вывода нескольких разрядов целого числа (в диапазоне : 0 .. 4294967295) на дисплей. В случае если у выводимого числа меньше разрядов чем указано в параметре “nDigit”, то тогда оставшиеся разряды заполняются нулями, т.е. “выводимое число” занимает фиксированное число знакомест дисплея, что в некоторых ситуациях весьма полезное свойство (см. ниже процент заполнения).

Пример использования :

unsigned long data = 7833;
lcd_ntos(data, 2);

void lcd_init(void);

Функция lcd_init( ) вызывается (до начала использования других функций HD44780-драйвера) для инициализации дисплея (конфигурация дисплея, выбор режима ввода и т.д.). Также, до вызова функции lcd_init( ), пользователь должен настроить все выводы управляющего микроконтроллера (LCD_E, LCD_RS, LCD_RW (если используется), LCD_D7, .. LCD_D4) как выходы! Это можно сделать двумя способами (точнее, способ один но выглядит это по разному :) ) :

1. Добавить в макрос “Set_All_pins_as_Outputs( )” (эдакий callback, в файле lcd_cfg.h) функцию/код инициализации всех выводов управляющего микроконтроллера.

disp_gpio

2. Настроить все выводы управляющего микроконтроллера до вызова lcd_init( ), а макрос Set_All_pis_as_Outputs( ) оставить пустым.

gpio_init(); // Инициализация выводов интерфейса (не входит в обязанности HD44780-драйвера).
lcd_init();
Индикатор выполнения (Progress Bar)

Для использования индикатора выполнения, следует присвоить USE_PROGRESS_BAR = “1″ в файле lcd_cfg.h, иначе вызов какой-либо службы индикатора выполнения приведет к ошибке компиляции.

void lcd_drawbar(uint8_t data);

Индикатор выполнения мгновенно заполняется до значения передаваемого через параметр “data”. Индикатору можно присваивать значения от “0″ до “PROGRESS_BAR_MAX_LOAD” (100% заполнение или максимальное число шагов для полного заполнения индикатора). Если присвоить макросу USE_REGRESS_BAR = “1″, то во время работы, заполнение индикатора может как увеличиваться (передавая значение больше предыдущего) так и уменьшаться (передавая значение меньше предыдущего).

Замечание: после вызова lcd_drawbar, устанавливается режим ввода указанный в макросе DEFAULT_ENTRY_MODE и курсор перемещается в левый верхний угол дисплея (на всякий пожарный).

void lcd_clrbar(void);

Функция lcd_clrbar( ) очищает все ячейки индикатора выполнения, т.е. переводит индикатор в начальное состояние (0% заполнение).

Пример использования :

#define USE_PROGRESS_BAR      1  /* 1 or 0 */
#define PROGRESS_BAR_LINE      2  /* Select lcd line: 1, 2, 3 or 4 */
#define PROGRESS_BAR_HEIGHT              5  /* in pixel: 1(min),2,3,4,5,6,7,8(max) */
#define PROGRESS_BAR_WIDTH              10

lcd_puts("\tLoading...");

lcd_goto(PROGRESS_BAR_LINE, PROGRESS_BAR_WIDTH); // Переход на первую ячейку после индикатора выполнения
lcd_puts("[ %]");

for(i=0; i<=PROGRESS_BAR_MAX_LOAD; i++){
lcd_goto(PROGRESS_BAR_LINE, PROGRESS_BAR_WIDTH + 1);
lcd_ntos( (i*100)/PROGRESS_BAR_MAX_LOAD, 3 );
lcd_drawbar(i);
_delay_ms(500);
}
Рис. 2х16 дисплей

В этом примере, первые десять ячеек (макрос PROGRESS_BAR_WIDTH) второй строки (макрос PROGRESS_BAR_LINE) выделены под индикатор выполнения. Оставшиеся шесть ячеек второй строки, используются для вывода процента выполнения. На первой строке выводится произвольный текст.

#define USE_PROGRESS_BAR      1  /* 1 or 0 */
#define PROGRESS_BAR_LINE      1  /* Select lcd line: 1, 2, 3 or 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_puts("\tLoading...");
for(i=0; i<=PROGRESS_BAR_MAX_LOAD; i++)
{
lcd_drawbar(i);
_delay_ms(500);
}
Рис. 2х16 дисплей

В этом примере для вывода индикатора выполнения используется первая строка (PROGRESS_BAR_LINE = “1″). Высота индикатора составляет 8 пикселей (PROGRESS_BAR_HEIGHT).

Переносимость

Для того чтобы портировать HD44780-драйвер на другой управляющий микроконтроллер, вам следует сделать следующее :

1. Добавить заголовочный файл вашего микроконтроллера в lcd_cfg.h.

disp_header

2. Настроить интерфейс между управляющим микроконтроллером и дисплеем, см. раздел “Подключение микроконтроллера к ЖК дисплею”.

3. Инициализировать выводы управляющего микроконтроллера, см. описание функции “lcd_init( )”.

4. В случае, если используется опрос флага “занятости” дисплея, следует указать входной порт вывода “LCD_D7″, а также заполнить две функции/макроса для переключения вывода “D7″ на вход и выход соответственно. Подробнее см. описание макроса USE_BUSY_FLAG.

Замечания

Драйвер протестирован на дисплее RT162-7 и микроконтроллере STM32F103RB. Используемые настройки представлены в качестве примеров.

Спасибо за внимание. Желаю успехов в использовании библиотеки. Если будут вопросы/замечания, милости просим в комментарии.

Скачать HD44780-драйвер

  27 Комментариев к “Управление HD44780 дисплеем. Руководство пользователя”

  1. Если для прогрессбара использовать PROGRESS_BAR_HEIGHT не 8 (т.е. не полностью заполненное знакоместо, ячейку, высота индикатора не 8), то в нижней части ячейки при заполнении появляется “мусор”

     
  2. ))))))) В драйвере за 23 сентября, нет функций lcd_itos и lcd_ntos. По прежнему не могу вывести переменную. Пользуюсь Atmel Studio.

     
    • нет функций lcd_itos и lcd_ntos

      .. попробуйте скачать еще раз :)
      ЗЫ .. есть ошибки при компиляции ?

       
      • Конечно есть :-) У меня же AVR а это драйвер под STM

         
        • .. почему для STM, замените STM’овские регистры на AVR’овские, укажите частоту процессора и подберите BUSY_CYCLE_TIME для вашего дисплея (обычно, значения в пределах от 5 до 10) и все

           
          • Здравствуйте. Вы говорите замени, мол регистры. Да если бы я знал как :-) Вот в версии 1.1, просто надо было в хидере поменять CPIO На нужный порт, тут же не так. Заметьте, чужими библиотеками пользуются чайники… Я, естественно, тоже чайник, и не понимаю что там где менять… Я только начал потихоньку вникать в это. А вы не выложите пример именно для Atmel Studio?

             
            • .. укажите мне следующее :
              - к каким выводам микроконтроллера подключены ЖК выводы
              - частоту процессора
              - как вы предпочитаете выполнять задержку программно (как вы предыдущих версиях) или аппаратно
              (т.е. хотите использовать вывод RW ЖК дисплея или нет)

               
              • RS—- PORTB0
                RW— Нет
                E — PORTB1
                D4 — PORTB2
                D5 — PORTB3
                D6 — PORTB4
                D7 — PORTB5

                 
                • .. вот все что касается переноса на AVR (при USE_BUSY_FLAG = 0u, т.е. не использовании RW вывода). Кстати, на вывод RW следует подать “0″
                  ———————————————————————
                  #include <avr/io.h>

                  #define LCD_E_OUT PORTB
                  #define LCD_E 1u

                  #define LCD_RS_OUT PORTB
                  #define LCD_RS 0u

                  #define LCD_D7_OUT PORTB
                  #define LCD_D7 5u

                  #define LCD_D6_OUT PORTB
                  #define LCD_D6 4u

                  #define LCD_D5_OUT PORTB
                  #define LCD_D5 3u

                  #define LCD_D4_OUT PORTB
                  #define LCD_D4 2u

                  #define USE_BUSY_FLAG 0u

                  #define MCU_FREQ_VALUE 8u /* 8МГц */
                  #define BUSY_CYCLE_TIME 5u /* 50 микросекунд */
                  #define CLRSCR_CYCLE_TIME 200u /* 2 миллисекунды */
                  #define RETHOME_CYCLE_TIME 200u /* 2 миллисекунды */

                  #define Set_All_pins_as_Outputs() \
                  DDRB |= 0x3Fu

                   
  3. А русские символы как вывести??

     
    • .. надо проверить позицию каждого символа в CGROM памяти дисплея. Если все нормально (соответствует таблице ASCII), то прямо пишите на русском. Если некоторые символы не на своих местах (точнее они отсутствуют и вместо них следует использовать похожие латинские), то следует использовать массив символов заканчивающийся ‘\0′:
      uint8_t privet[] = {‘П’, ‘Р’, ‘И’, ‘В’, ‘Е’, ‘Т’, ‘\0′}
      вместо “П” и “И” следует использовать коды указанные в даташите дисплея, а вместо остальных их латинские аналоги (в случае если русские символы отсутствуют).

       
  4. Здравствуйте!
    Использую дисплей 16х2 с STM32VLDISCOVERY, наблюдаю интересный глюк.
    Структура программы такая:
    main {
    небольшая задержка
    lcd_init();
    lcd_clrscr();
    lcd_puts(privet);
    lcd_goto(2,0);
    lcd_puts(privet2);

    действия(); }
    В первую строку выводит привет всегда, чтобы вывело во вторую, нужно кнопку ресет последовательно и быстро нажать два раза. Что это?

    Задержки завысил, подключение супернадёжное.

    Еще, можете объяснить, зачем в функции lcd_goto делается побитовое ИЛИ с 0×80 в lcd_write ?

    case LCD_1st_LINE: lcd_write(0x80u | START_ADDRESS_1st_LINE | address); break;
    case LCD_2nd_LINE: lcd_write(0x80u | START_ADDRESS_2nd_LINE | address); break;
    case LCD_3rd_LINE: lcd_write(0x80u | START_ADDRESS_3rd_LINE | address); break;
    case LCD_4th_LINE: lcd_write(0x80u | START_ADDRESS_4th_LINE | address); break;

     
    • Здравствуйте.

      В первую строку выводит привет всегда, чтобы вывело во вторую, нужно кнопку ресет последовательно и быстро нажать два раза. Что это?

      .. это вуду :) . А вы не пробовали демо проект из архива, по его выполнению могу сказать больше (правда там используется StdPeriph_Lib для инициализации портов – можете заменить ее на вашу инициализацию) ?

      Задержки завысил, подключение супернадёжное.

      .. а вы правильно указали значение частоты микроконтроллера ? Также проверьте USE_BUSY_FLAG и вывод RW (если USE_BUSY_FLAG=0 на RW надо подать 0В).

      Еще, можете объяснить, зачем в функции lcd_goto делается побитовое ИЛИ с 0×80 в lcd_write ?

      .. 0×80 это команда “Set DDRAM address” для HD44780 (точнее при установке DDRAM адреса, последний бит команды должен быть равен “1″)
      ЗЫ .. я иногда, когда делал “эксперименты”, забывал изменить макрос SYSCLK_FREQ_xxMHz в соответствии с MCU_FREQ_VALUE и проект создавался с неправильной частотой.

       
      • Так я и не поборол этот глюк.
        Частота 24МГц, флаг занятости не использую, RW и D0-D3 притянуты к нулю. gpio_init() перепроверил на всякий случай, дело не в нём.
        Выяснил, что LCD плохо воспринимает повторную инициализацию. После подачи питания всё работает как надо, но если нажать ресет мк, выводится только первая строка. Если же перед ресетом на секунду выключить питание LCD, всё снова работает.
        Провёл такой эксперимент:
        main {
        lcd_init();
        lcd_clrscr();
        lcd_puts(privet);
        lcd_goto(2,0);
        lcd_puts(privet2); // выводит, если сбрасывалось питание LCD
        lcd_clrscr();
        lcd_init(); // вызываю повторно инициализацию
        lcd_puts(privet);
        lcd_goto(2,0);
        lcd_puts(privet2); // это уже не выводит
        }

        Есть какие-нибудь мысли в этом направлении?

         
        • Здравствуйте Константин,
          .. попробуйте заменить код в функции lcd_config (которая вызывается в lcd_init) на следующий:

              /* Send commands to LCD. */
              CLR(LCD_RS_OUT, LCD_RS);
          #if (USE_BUSY_FLAG)
              /* Write data/commands to LCD. */
              CLR(LCD_RW_OUT, LCD_RW);
          #endif /* USE_BUSY_FLAG */

              lcd_high(param);
              lcd_strobe();       // Change 8-bit interface to 4-bit interface
              lcd_10us_delay(500);
              lcd_strobe();       /* DB7 to DB4 of the "Function set" instruction is written twice. */
              lcd_10us_delay(10);
                  lcd_strobe();       // Change 8-bit interface to 4-bit interface
              lcd_10us_delay(BUSY_CYCLE_TIME);
                  lcd_strobe(); // Change 8-bit interface to 4-bit interface
              lcd_10us_delay(BUSY_CYCLE_TIME);
              lcd_low(param);
              lcd_strobe();       // 4-bit, two lines, 5x8 pixel
              lcd_10us_delay(BUSY_CYCLE_TIME);
           
          • Никак не повлияло. Буду вникать в протокол и вашу реализацию. Есть еще зацепка, что первую строку дисплей всё-таки при любых условиях выводит, а вторую нет. И в субботу куплю еще дисплей, может в железе дело.

             
            • Есть еще зацепка, что первую строку дисплей всё-таки при любых условиях выводит, а вторую нет

              .. не могу воспроизвести описанное вами поведение, мой дисплей (какой-то RT162-7), подключенный к платке с стм32, после каждого сброса работает нормально.

              может в железе дело

              .. попробуйте также подключить выводы дисплея к другим выводам микроконтроллера, либо к другой платке
              ЗЫ .. а какой марки у вас дисплей ?

               
  5. В какие адреса можно записать пользовательские символы при помощи функции lcd_load. В адреса 0,1,2 пишет, а в адрес 192 не пишет. Я хочу записать с адреса 192 по 255 русский знакогенератор

     
    • .. от 0 до 7 (CGRAM память) – можно записывать пользовательские символы. От 8 до 255 (CGROM память) – зашиты ASCII символы и их изменить нельзя. Ищите дисплей с прошитыми символами, либо создайте таблицу перекодировки

       
  6. У меня похожая проблема (Версия старая). Кварц на 12МГц. После программирования появлялись какие-то крякозяблы. Я в hd44780.h поставил частоту кварца на 8МГц. Прошил и все показываем как надо. Передернул питание и опять крякозяблы. Потом я сделал так(среда Atmel Studio6):
    1. добавил библиотеку в hd44780.с
    2. в файле hd44780.с изменил функцию lcd_config на

    void lcd_config(int8u_t param)
    {/* CONFIGURE THE DISPLAY */
    HIGHBITS(param); // 4-bit, two lines, 5×8 pixel
    _delay_ms(100);
    LCD_STROBE(0); // change 8-bit interface to 4-bit interface
    _delay_ms(100);
    LCD_STROBE(0); // init 4-bit interface
    _delay_ms(100);
    LOWBITS(param);
    _delay_ms(100);
    LCD_STROBE(0);
    _delay_ms(100);
    }

    3. В файле hd44780.h установил частоту кварца 12МГц и изменил
    #define MCU_WAIT_CYCLES 200 на
    #define MCU_WAIT_CYCLES 400

    пока все работает.

     
  7. Великолепно проделанная работа. Драйвер замечательный, (STM32F103) запустился сразу. Практически в коде ничего не менял, скачал пощупать, похоже, что оставлю :) . Похожая проблема как описал Константин с RESET, но такая же и при другом программном обеспечении драйвера LCD. У меня кнопка RST, скорее всего дребезг. Замыкаю pin RST вручную на минус, резет отрабатывает как и положено без глюков. Если через встроенную в плату кнопку, то как и описал Константин, зависает. Еще раз благодарю за прекрасный пример драйвера.

     
  8. Большое спасибо GrAnd за Вашу библиотеку. Подключаю сейчас индикатор к STM32F103VB на 72МГц. Надеюсь, Вас не обидят мои замечания. У меня библиотека сносно заработала после:
    1. замены константы инициализациив файле hd44780.h как требуется в описании контроллера для 4-битного режима
    //#define DISPLAY_CONFIG_4bit_2L_5x8 0x28u /* Use 4-bit interface, 2 or 4 Lines, 5×8 pixel resolution */
    #define DISPLAY_CONFIG_4bit_2L_5x8 0x30u /* Use 4-bit interface, 2 or 4 Lines, 5×8 pixel resolution */
    2. добавления в конце функции lcd_goto() дополнительной задержки
    void lcd_goto(uint8_t line, uint8_t address)
    {
    /* Send a command to LCD. */
    CLR(LCD_RS_OUT, LCD_RS);
    /* Set DDRAM/CGRAM address. */
    switch (line)
    {
    /* Set DDRAM address. */
    case LCD_1st_LINE: lcd_write(0x80u | START_ADDRESS_1st_LINE | address); break;
    case LCD_2nd_LINE: lcd_write(0x80u | START_ADDRESS_2nd_LINE | address); break;
    case LCD_3rd_LINE: lcd_write(0x80u | START_ADDRESS_3rd_LINE | address); break;
    case LCD_4th_LINE: lcd_write(0x80u | START_ADDRESS_4th_LINE | address); break;
    /* Set CGRAM address. */
    case CGRAM : lcd_write(0x40u | address); break;

    default:
    /* Ignore this command */
    break;
    }
    lcd_10us_delay(BUSY_CYCLE_TIME); // <<<< !!!!
    }
    К сожалению, пока не разобрался, почему виснет при включении USE_BUSY_FLAG 1u.

     
    • Здравствуйте.

      замены константы инициализации в файле hd44780.h как требуется в описании контроллера для 4-битного режима

      1. DISPLAY_CONFIG_4bit_2L_5x8 = 0x30u, означает что вы будете использовать 8-разрядную шину, только верхнюю линию и шрифт 5×8. Скорей всего Вы посмотрели пример инициализации дисплея для 8-разрядной шины.

      добавления в конце функции lcd_goto() дополнительной задержки

      2. Вообще то в драйвере уже стоит дополнительная задержка при записи DDRAM памяти. В hd44780.c есть макрос AC_UPDATE_TIME = 1. Все что необходимо то это правильно указать значения :
      MCU_FREQ_VALUE = 72u
      BUSY_CYCLE_TIME = 10u (5 это минимум!)

      К сожалению, пока не разобрался, почему виснет при включении USE_BUSY_FLAG 1u.

      При USE_BUSY_FLAG = 1 используется вывод RW (его следует подключить к микроконтроллеру), а также D7 как вход (следует инициализировать макросы для настройки выводов на вход и выход)

      Надеюсь, Вас не обидят мои замечания.

      Я даже рад. Вы тем самым помогаете отыскивать баги, но думаю не в этот раз ;)

       
  9. Большое спасибо за ответ, уважаемый GrAnd .
    BUSY_CYCLE_TIME = 10u – помогло. По умолчанию было 5. Дополнительную задержку я убрал.
    Однако, Ваш код инициализации в моём случает не работает. Точнее, работает с добавкой:

    оставил как у Вас
    #define DISPLAY_CONFIG_4bit_2L_5x8 0x28u /* Use 4-bit interface, 2 or 4 Lines, 5×8 pixel resolution */

    а 0×30 добавил в инициализацию
    /*! \brief Initializing by instruction. 4-bit interface initialization. */
    static void lcd_config(uint8_t param)
    {/* Low level function. */
    /* Send commands to LCD. */
    CLR(LCD_RS_OUT, LCD_RS);
    #if (USE_BUSY_FLAG)
    /* Write data/commands to LCD. */
    CLR(LCD_RW_OUT, LCD_RW);
    #endif /* USE_BUSY_FLAG */

    // добавка ++++++
    lcd_high(0×30);
    lcd_strobe();
    lcd_10us_delay(500);
    lcd_high(0×30);
    lcd_strobe();
    lcd_10us_delay(20);
    lcd_high(0×30);
    lcd_strobe();
    lcd_10us_delay(20);
    // добавка ——-

    lcd_high(param);
    lcd_strobe(); // Change 8-bit interface to 4-bit interface
    lcd_10us_delay(BUSY_CYCLE_TIME);
    lcd_strobe(); /* DB7 to DB4 of the “Function set” instruction is written twice. */
    lcd_10us_delay(BUSY_CYCLE_TIME);
    lcd_low(param);
    lcd_strobe(); // 4-bit, two lines, 5×8 pixel
    lcd_10us_delay(BUSY_CYCLE_TIME);
    /* Note: The number of display lines and character font cannot be changed after this point. */
    }

     
    • Однако, Ваш код инициализации в моём случает не работает. Точнее, работает с добавкой

      .. должно работать и без добавки. Я гонял дисплей на 72 МГц и при этом менял только MCU_FREQ_VALUE!
      PS .. можно укоротить добавку так :
      // добавка ++++++
      lcd_high(0×30);
      lcd_strobe();
      lcd_10us_delay(500);
      lcd_strobe();
      lcd_10us_delay(20);
      lcd_strobe();
      lcd_10us_delay(20);
      // добавка – - – - – -

       
  10. Огромное спасибо GrAnd! Гоняю Вашу библиотеку и радуюсь:) Желаю Вам дальнейших успехов!

     

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

Current ye@r *