Библиотека для работы с lcd дисплеями. Использование библиотеки для работы с LCD HD44780. Питание, регулировка контрастности и подсветка

Урок 12

Часть 5

LCD индикатор 16×2

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

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

Теперь пришло время написать функцию вывода на экран целой строки, так как выводить посимвольно не совсем удобно, хотелось бы работать со строками. Добавим данную функцию прямо перед функцией main() и передавать мы ей будем массив символов неопределённой размерности

//—————————————-

void str_lcd ( char str1 )

{

}

//—————————————-

Вызовем данную функцию в main(), удалив перед этим весь код посимвольного вывода на дисплей

LCD_ini (); //Инициализируем дисплей

setpos (0,0);

str_lcd ( "Hello World!" );

Дальше начнём писать тело функции вывода строки. Объявим в теле функции переменную для символа. Переменная у нас будет несколько иного типа. Как правило с таким типом лучше распознаются коды символов. Вы можете, конечно, поэксперементировать с другими типами

void str_lcd ( char str1 )

wchar_t n ;

Далее мы, соответственно, организуем цикл и будем попеременно перебирать все переданные символы в массиве и выводить их на дисплей. Применим также мы вариант представления нулевого симвлова "n" и именно до него мы и будем перебирать символы

Wchar_t n ;

for ( n =0; str1 [ n ]!=""; n ++)

sendchar ( str1 [ n ]);

Соберём код и проверим в протеусе работу кода

Теперь можно попробовать вывести строку ещё и в другое место экрана. Напишем код в main()

str_lcd ( "Hello World!" );

setpos (2,1);

str_lcd ( "String 2" );

while (1)

Соберём код и посмотрим результат

Всё работает! Отлично!

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

Оформляем функции в отдельный модуль

Дошли мы с кодом до такого состояния, что наш главный и единственный файл с кодом переполнился до того, что в нём теперь тяжело уже вообще что-то найти. Как же мы с этим можем боротья? Бороться с этим мы будем путём оформления кода функций для отдельно взятого устройства или шины или какой-то технологии в отдельный модуль. Грамотный модуль состоит как правило из заголовочного файла и файла реализации функций. Поэтому давайте для нашего LCD дисплея мы так и поступим. Также это всё дело нужно для того, что если мы будем писать новый проект, то мы данные файлы будем просто к нему подключать, если нам потребуется воспользоваться LCD дисплеем. Это будет нашей так называемой библиотекой для дисплея. Конечно, библиотеки обычно пишутся и компилируются в отдельный файл lib, но в этом случае обычно нет исходного кода и данные библиотеки не могут быть подправлены. А наша библиотека будет вполне исправимой и нам ещё ой как пригодится в будущем.

Но прежде, чем создать данную библиотеку, мы создадим главный заголовочный файл и назовём его main.h, чтобы убрать в данный файл все подключенные библиотеки, различные глобальные переменные и макроподставновки

Для этого мы в дереве проектов щёлкаем правой кнопкой по нашему проекту Test09 и выбираем в контекстном меню субменю Add , а в нём уже выбираем пункт New Item

И в открывшемся диалоге выбираем тип файла, который мы будем создавать, "Include File " И внизу в имени файла меняем IncFile1 на main , затем жмём кнопку Add.

Соответственно, у нас создастся файл main.c вот с таким содержимым

#ifndef MAIN_H_

#define MAIN_H_

#endif /* MAIN_H_ */

Это очень хорошо. Например. в Keil, когда мы занимается программированием контроллеров STM, мы должны это всё писать в ручную. Здесь данная директива говорит о том, что, если файл уже подключался в исполняемый код, чтобы прероцессор его повторно не включал.

В данный файл мы посместим подключения всех заголовочных файлов библиотек и все макроподстановки, а в файле Test09.c всё это, конечно, мы удалим

#ifndef MAIN_H_

#define MAIN_H_

#define F_CPU 8000000UL

#include

#include

#include

#include

#include

//—————————————-

#define e1 PORTD |=0b00001000 // установка линии E в 1

#define e0 PORTD &=0b11110111 // установка линии E в 0

#define rs1 PORTD |=0b00000100 // установка линии RS в 1 (данные)

#define rs0 PORTD &=0b11111011 // установка линии RS в 0 (команда)

//—————————————-

#endif /* MAIN_H_ */

Но недостаточно данный заголовочный файл подключить в Solution Explorer, его также мы должны в файле Test09.c подключить в самом начале в код

#include "main.h"

//—————————————-

Соберём проект, ещё раз проверим его работоспособность.

Теперь начнём создавать нашу библиотеку для дисплея.

Для этого мы таким же образом, как и main.h, создадим заголовочный файл lcd.h

#include

#include "lcd.h"

И наоборот, в файл lcd.h мы подключим файл main.h

#ifndef LCD_H_

#define LCD_H_

#include "main.h"

Насчет того, что получится какое-то перекрёстное зацикливание, можно не беспокоиться — директивы не дадут такому случиться.

Также все макроподстановки из файла main.h мы заберём в файл lcd,h, а в main.h удалим

#include "main.h"

//—————————————-

void LCD_ini ( void );

void setpos ( unsigned char x , unsigned y );

void str_lcd ( char str1 );

void sendchar ( unsigned char c );

//—————————————-

А, чтобы забрать все функции по работе с дисплеем из файла Test09.c, мы создадим теперь уже другой файл — lcd.с . В нём и будет код реализации всех функций

Создаётся файл точно таким же образом, только вместо "Include File" мы выбираем тип файла "C File".

Файл lcd.c создан. В нём уже не будет никаких директив, единственное, будет авторский комментарий, который мы удалим, чтоб не мешался.

В данном файле мы также подключим заголовочный файл lcd.h

#include "lcd.h"

//—————————————-

Теперь мы в данный файл перенесём полностью все функции, предназначенные для работы с дисплеем, из файла Test09.c. В нём останутся только две фунции — port_ini и main() .

Тем самым мы очень серьёзно разгрузим главный файл приложения, сделав его удобочитаемым.

Но этого нам недостаточно. Ни одна функция теперь не будет "видна" в файле Test09.c. Поэтому те функции, которые мы будем использовать в других файлах, мы обязаны объявить, или, как говорят в народе, создать на них прототипы. Делается это обычно в заголовочном файле. Поэтому мы создадим прототипы в заголовочном файле lcd.h. Прототип делается очень легко. Пишется, или обычно копируется заголовок функции со всеми аргументами (всё кроме тела) и в конце ставится точка с запятой. Нам нужны будут функции инициализации дисплея, позиционирования на дисплее и вывода строки на дисплее. Символы мы отдельно пока выводить не будем, поэтому на соответствующую функцию мы прототип не создаём. Вот наши прототипы

#include "main.h"

//—————————————-

void LCD_ini ( void );

void setpos ( unsigned char x , unsigned y );

void str_lcd ( char str1 );

//—————————————-

#define e1 PORTD |=0b00001000 // установка линии E в 1

Теперь соберём файл, запустим его в протеусе, и проверим его работоспособность. Также проверим на практике. Если всё работает, то мы всё сделали правильно. Проект на весь урок приложен внизу и доступен по ссылке "Исходный код".

Таким образом, в сегодняшнем уроке мы много чему научились. Мы научились работать с символьным дисплеем и подключать его к контроллеру AVR. Также мы в рамках данного урока научились грамотному оформлению кода и использованию модульного программирования.

Post Views: 11 438

В этой статье я расскажу как с помощью достаточно распространенной библиотеки управлять LCD дисплеем на базе контроллера HD44780 и выводить на него информацию. Библиотека состоит из двух файлов lcd_lib.h и lcd_lib.c для использования с дисплеем подключенным по четырехбитной шине данных. В заголовочном файле прописываются настройки подключения дисплея к контроллеру, которые можно изменить по своему усмотрению, а также переменные и функции.

Ниже представлены базовые функции управления и вывода информации на LCD.

lcd_com – посылка команды в LCD

Пример:
lcd_com(0x01); // очистка дисплея
lcd_com(0x38); // интерфейс 8 бит 2 строки

lcd_dat – вывод одного символа в текущую позицию

Пример:
lcd_dat("U"); // вывод символа "U"
lcd_dat(0xB0); // вывод символа "Ю"(В соответствие с таблицей символов дисплея)

lcd_init – Инициализация LCD

Вот пример широко распространенной последовательности для инициализации LCD: 0x38, 0xOC, 0x06 .
0x38 устанавливает режим отображения 2-х строк с матрицей 5 х 8 точек и работу с 8-ми разрядной шиной данных;
0xOC включает отображение на экране ЖКИ-можуля, без отображения курсоров;
0x06 устанавливает режим автоматического перемещения курсора слева-направо после вывода каждого символа.

lcd_clr – очистка LCD

lcd_home – переводит курсор в начало

lcd_string – вывод строки указанной длинны в текущую позицию

Пример: lcd_string("TEST",4); // вывод строки TEST длиной 4 символа

lcd_gotoxy – перемещает курсор в указанную позицию

Пример: lcd_gotoxy(12, 1); // курсор в позиции тринадцатый разряд второй строки

copy_string_to_lcd – вывод строки из флеш-памяти в указанную позицию дисплея

Пример: copy_string_to_lcd("TEST",4,0); // вывод строки TEST в позицию пятый разряд первой строки

lcd_definechar – записывает пользовательское изображение символа в память дисплея

Чтобы вывести на экран дисплея собственный символ необходимо знать код символа, прописать этот код в памяти программ микроконтроллера (PROGMEM), затем поместить его в свободную ячейку памяти LCD (CGRAM) и выводить его на экран при помощи функции lcd_dat() .

Для программирования доступны 8 переопределяемых символов в режиме с матрицей 5х7 точек и 4 с матрицей 5х10 (в режиме 5х10 переопределяемые символы адресуются кодами DDRAM через один: 0x00, 0x02, 0x04, 0x06). Для кодирования матрицы используются горизонтально "уложенные" байты, пять младших битов которых несут информацию о рисунке (причем 1(единица) означает, что сегмент будет включен), 4-й разряд каждого из 8-ми (или 11-ти в режиме 5 х 10) байтов матрицы определяет левую колонку символа, а 0-й - правую. Старшие три бита не используются, равно как и старшие пять байтов, составляющих полную область матрицы символа (16 байтов) в режиме 5х10 (обратите внимание, что матрица программируемых символов допускает использование полной высоты строки (8 строчек для режима 5х7 и 11 строчек для режима 5х10), то есть можно размещать точки в области подчеркивающего курсора).

Создавать символ более удобно в двоичном формате, к примеру создадим символ прямоугольника, код будет таким:

Const uint8_t pryamougolnik PROGMEM= { 0b11111, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11111, 0b0 };

lcd_shift_right – перемещает изображение на указанное число символов вправо

lcd_shift_Left – перемещает изображение на указанное число символов влево

lcd_cursor_on – включает курсор подчеркивание

lcd_cursor_blink – включает мигающий курсор

lcd_cursor_off – выключает курсор

lcd_blank – отключает изображение, но не очищает

lcd_visible – включает изображение

lcd_cursor_left – перемещает курсор на указанное число символов влево

lcd_cursor_right – перемещает курсор на указанное число символов вправо

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

lcd_num_to_str - позволяет выводить на дисплей переменную до 4 разрядов

Пример: void lcd_num_to_str(ADC, 4); // Выводим переменную АЦП 4 разряда

Сделаем проект "Аналоговый вольтметр" в котором информация об измеренном напряжении будет выводится на экран в виде горизонтальной динамической шкалы. Измеряемое напряжение подается на вход ADC0, максимум 5В. без использования делителя. Используем для этого проекта микроконтроллер atmega8, который тактируется от внутреннего генератора частотой 8МГц. Дисплей подключаем по четырехбитной шине в соответствие с настройками из файла lcd_lib.h. При создании проекта в AVRSTUDIO копируем 2 файла библиотеки в папку нашего проекта, а в дереве проекта добавляем эти файлы(lcd_lib.c и lcd_lib.h).

За вывод динамической шкалы отвечает функция lcd_progress_bar(uint8_t progress, uint8_t maxprogress, uint8_t length) , в зависимости от состояния переменных этой функции, шкала меняет свой уровень, progress - уровень от 0 до 255, maxprogress - максимальный уровень ограничивается числом от 0 до 255, length - длина шкалы от 0 до 16 ячеек(в зависимости от типа дисплея). Так как при максимальном напряжении на входе значение ADC равно 1024, делим это значение на 4 и присваиваем его переменной "u", а переменную "u" используем в функции вывода динамической шкалы progress() .

Полный текст программы выкладываю ниже:

//******Применение библиотек для работы с LCD HD44780***** #include #include #include #include "lcd_lib.h" const uint8_t simbol_1 PROGMEM= {
0b00000,0b10001,0b01010,0b00100,0b01010,0b10001,0b00000,0b00000
};
const uint8_t simbol_2 PROGMEM= {
0b00100,0b00100,0b00100,0b11111,0b00100,0b00100,0b00100,0b00000
}; unsigned char u; //******************************************************** void progress(void) // функция вывода шкалы { lcd_gotoxy(0, 0); lcd_string("0......05......1",16); lcd_gotoxy(0, 1); lcd_progress_bar(u, 255, 16); } //******************************************************** int main(void) { /***Настройка АЦП***/ ADCSRA |= (1 << ADEN) //Включение АЦП |(1 << ADPS1)|(1 << ADPS0); // предделитель преобразователя на 8 ADMUX |= (0 << REFS1)|(0 << REFS0) // внешний ИОН |(0 << MUX0)|(0 << MUX1)|(0 << MUX2)|(0 << MUX3); // вход PC0 _delay_ms(100); lcd_init();// инициализация LCD lcd_clr();// очистить LCD _delay_ms(10); lcd_definechar(simbol_1, 6); // определяем собств. символ 1 lcd_definechar(simbol_2, 7); // определяем собств. символ 2 for(char a=0; a<10; a++) // цикл приветствия { lcd_gotoxy(0, 0); lcd_dat(6); _delay_ms(100); lcd_gotoxy(0, 0); lcd_dat(7); _delay_ms(100); lcd_gotoxy(3, 0); lcd_string("AЅa»oґoіГ№",10); // Аналоговый lcd_gotoxy(3, 1); lcd_string("іo»Дїјeїp",9); // вольтметр } _delay_ms(1000); lcd_clr();// очистить LCD while(1) { progress(); ADCSRA |= (1 << ADSC); //Начинаем преобразование while ((ADCSRA&(1 << ADIF))== 0); //Ждем флага окончания преобразования u = ADC/4; } }

Рассмотрим взаимодействие пользователя и устройства на базе микроконтроллера. Очень часто пользователю нужно чем-то вводить информацию, и с чего-то ее считывать. Для этих целей очень хорошо подходит клавиатура и дисплей ().Рассмотрим взаимодействие пользователя и устройства на базе микроконтроллера. Очень часто пользователю нужно чем-то вводить информацию, и с чего-то ее считывать. Для этих целей очень хорошо подходит клавиатура и дисплей (). В этой заметке рассмотрим поподробнее отображение информации на символьном ЖКИ со знакосинтезирующим .

Такие индикаторы часто используются при проектировании цифровых устройств, поэтому с ним необходимо уметь работать.
Рассмотрим типовое внутреннее строение знакосинтезирующего ЖКИ :

Внутренняя структура HD44780

В основе ЖКИ лежит матрица из жидких кристаллов, подавая напряжение на элемент которой мы можем «зажечь» точку на экране. В нашем случае матрица состоит из знакомест (чаще всего 8х5 пикселей), сгруппированых в несколько рядков. Этим всем управляет встроенный контроллер HD44780 . У контроллера есть однобайтные ячейки памяти (DDRAM ), содержимое которых собственно отображается на экране согласно таблице записанной в CGRAM . Ячеек памяти обычно больше чем знакомест в ЖКИ , поэтому адресацию знакомест нужно смотреть в даташите. То есть нам необходимо только в нужную позицию записать код нужного знака, а все остальное HD44780 сделает сам.

Для выбора позиции существует виртуальный курсор (номер текущей ячейки памяти, АС), которым можно управлять посредством команд, курсор можно сделать видимым. По умолчанию при записи символа в ячейку, курсор сдвигаеться вперед на одну позицию. Коды символов для ЖКИ поддерживающего кириллицу можно увидеть в таблице:

Старшая тетрада кода будет равна ряду выбранного символа, а младшая – строке. Можно создать свою таблицу символов, записав ее в CGRAM . На каждый символ требуется 5 байт, где единицы отвечают за «зажженные» пиксели. Например, цифра «8» кодируется последовательностью 0x6c,0x92,0x92,0x92,0x6c.
Коды команд приведены в таблице.

Таблица символов HD44780


Значения флагов:


Остается открытым вопрос: «как записать в нужную позицию код требуемого символа»? Для этого рассмотрим за что отвечают выводы ЖКИ . Выводы DB0-DB7 отвечают за входящие/исходящие данные. Высокий уровень на выводе RS дает индикатору понять, что сигнал на выводах DB0-DB7 является данными, а низкий – командой. Вывод W/R отвечает за направление данных, пишутся ли данные в память или читаются из нее (обычно чтение из ЖКИ не используется, можем смело на него подать низкий уровень). Импульс на выводе Е (длительностью не менее 500 нс) используется как сигнал для записи/чтения данных с выводов DB0-DB7 , RS и W/R .

Вывод V0 используется для задания контраста изображения, вывода А,К – для питания подсветки (если она есть в вашей модели ЖКИ ). Оставшиеся 2 вывода – собственно питание ЖКИ . То есть, для управления ЖКИ потребуется 8+1+1=10 выводов. Но можно работать в режиме 4-х битного интерфейса. При этом, сперва будет передавать старшая тетрада команды/данных на выводах DB4-DB7, а после – младшая. Выводы при DB0-DB3 при этом не используются. Итого для управления требуется 6 выводов микроконтроллера.
Теперь рассмотрим живой пример. Напишем программу для вывода текста «сайт» на имеющийся у меня в наличии WH1602А (2 строки по 16 символов).

Для других ЖКИ следует сверить соответствие ячеек DDRAM знакоместам. Схема подключения ЖКИ к контроллеру выглядит так.

Схема подключения к микроконтроллеру AVR


Резистор R3 - 17 Ом ограничивает ток через подсветку, а переменный VR1 задает контраст (если все правильно подключено и запрограммировано, но индикатор молчит, покрутите VR1, чтобы изображения стало видимым). Также не в коем случае не следует путать полярность ЖКИ , питать его выше 5,5В, со своего опыта могу сказать, что горят они моментально. Назначение всех остальных деталей такое же как в
Теперь перейдем к написанию программы. Для контроля индикатора напишем программу с несколькими ключевыми функциями работы с ЖКИ : lcd_dat(unsigned char x) – для записи данных х, lcd_com(unsigned char x) – для записи команды х, lcd_init(void) – для начальной инициализации индикатора:

    #include //библиотека ввода/вывода

  1. #define RS 2 //RS=PD2 - сигнал управления ЖКИ

    #define E 3 //E=PD3 - сигнал управления ЖКИ

  2. #define TIME 10 //Константа временной задержки для ЖКИ

    //Частота тактирование МК - 4Мгц

  3. //Программа формирвоания задержки

    void pause (unsigned int a)

    { unsigned int i;

  4. for (i= a; i> 0 ; i-- ) ;

  5. //Программа передачи команд в ЖКИ

    void lcd_com (unsigned char lcd)

    { unsigned char temp;

  6. temp= (lcd& ~(1 << RS) ) | (1 << E) ; //RS=0 – это команда

    PORTD= temp; //Выводим на portD старшую тетраду команды, сигналы RS, E

    asm("nop" ) ;

    PORTD= temp& ~(1 << E) ; //Сигнал записи команды

  7. temp= ((lcd* 16 ) & ~(1 << RS) ) | (1 << E) ; //RS=0 – это команда

    PORTD= temp; //Выводим на portD младшую тетраду команды, сигналы RS, E

    asm("nop" ) ; //Небольшая задержка в 1 такт МК, для стабилизации

    PORTD= temp& ~(1 << E) ; //Сигнал записи команды

  8. pause (10 * TIME) ; //Пауза для выполнения команды

  9. //Программа записи данных в ЖКИ

    void lcd_dat (unsigned char lcd)

    { unsigned char temp;

  10. temp= (lcd| (1 << RS) ) | (1 << E) ; //RS=1 – это данные

    PORTD= temp; //Выводим на portD старшую тетраду данных, сигналы RS, E

    asm("nop" ) ; //Небольшая задержка в 1 такт МК, для стабилизации

    PORTD= temp& ~(1 << E) ; //Сигнал записи данных

  11. temp= ((lcd* 16 ) | (1 << RS) ) | (1 << E) ; //RS=1 – это данные

    PORTD= temp; //Выводим на portD младшую тетраду данных, сигналы RS, E

    asm("nop" ) ; //Небольшая задержка в 1 такт МК, для стабилизации

    PORTD= temp& ~(1 << E) ; //Сигнал записи данных

  12. pause(TIME) ; //Пауза для вывода данных

  13. //Программа иниализации ЖКИ

    void lcd_init (void )

    lcd_com(0x2c ) ; //4-проводный интерфейс, 5x8 размер символа

    pause(100 * TIME) ;

    pause(100 * TIME) ;

    pause (100 * TIME) ;

  14. //Основная программа

    int main(void )

    DDRD= 0xfc ; //Инициализация portD

    PORTD= 0x00 ;

  15. pause(1000 ) ;

    lcd_init() ; //Инициализация ЖКИ

  16. lcd_dat("w" ) ; //Вывод "www.сайт"

    lcd_dat("w" ) ;

    lcd_dat("w" ) ;

    lcd_dat("." ) ;

    lcd_dat("a" ) ;

    lcd_dat("v" ) ;

    lcd_dat("r" ) ;

    lcd_dat("l" ) ;

    lcd_dat("a" ) ;

    lcd_dat("b" ) ;

    lcd_dat("." ) ;

    lcd_dat("c" ) ;

    lcd_dat("o" ) ;

    lcd_dat("m" ) ;

  17. lcd_dat("I" ) ; //Записываем "It"s so easy"

    lcd_dat("t" ) ;

    lcd_dat(""" ) ;

    lcd_dat("s" ) ;

    lcd_dat(" " ) ;

    lcd_dat("s" ) ;

    lcd_dat("o" ) ;

    lcd_dat(" " ) ;

    lcd_dat("e" ) ;

    lcd_dat("a" ) ;

    lcd_dat("s" ) ;

    lcd_dat("y" ) ;

  18. while (1 ) //бесконечный цикл

  19. return 1 ;

Программа очень проста, разобраться в ней не составит труда любому, кто хоть немного владеет C для AVR . Для латиницы и цифр ASCII коды совпадают с зашитыми в знакогенератор ЖКИ , поэтому позволительно использовать lcd_dat(‘A’) . Можно создать свою библиотеку для работы с ЖКИ, выделив функции lcd_dat(unsigned char x), lcd_com(unsigned char x), lcd_init(void) в отдельный модуль LCD.h и подключать его за надобностью.

Эта затея очень экономит время, стоит только один раз написать нужные функции, а потом все время их только использовать. Также можно подметить, что неудобно выводить длинную фразу по одной букве, для этого можно нашу выводимую строку запихнуть в массив из unsigned char и выводить с помощью цикла:

    int main(void )

    { unsigned char data [ 14 ] = { "w" , "w" , "w" , "." , "a" , "v" , "r" , "l" , "a" , "b" , "." , "c" , "o" , "m" } ;

    unsigned char i;

    DDRD= 0xfc ; //Инициализация portD

    PORTD= 0x00 ;

  1. pause(1000 ) ; //Задержка, чтобы ЖКИ успел включиться

    lcd_init() ; //Инициализация ЖКИ

  2. for (i= 0 ; i< 14 ; i++ ) //Вывод записи побуквенно

    lcd_dat(data[ i] ) ;

Только не стоит забывать, что нумерация массивов в С начинается с нуля. Существующую программу можно без существенных изменений использовать совместно с контроллером ATtiny2313 , подключив ЖКИ к PORTB , та как PORTD у ATtiny2313 имеет всего 7 выводов, а не 8, как у ATmega8 .

Также советую подключать ЖКИ с помощью разъемных соединений. Очень удобно при отладке программы, когда нужно вывести некоторые промежуточные данные. Подсоединил один разъем и всего дела. В продолжение этой заметки в ближайшее время рассмотрю и отображение считанной информации на ЖКИ .
Всем хорошего дня;)

есть маленький недочет в этом примере

есть маленький недочет в этом примере, возможно по этой причине у многих не работает пример!

вобщем пример лаконичен и прост, поэтому в глаза не бросается маленький недочет(тем кто ориентируется в языке "С"), и уж тем более тем кто только только знакомится с AVR и языком "С", возможно они даже недоумевают как так....пишут сделайте так и будет как на картинке....а не тут то было...

вобщем вся проблема с циклами задержки, для того чтоб дисплей поспевал за контроллером, а именно в функции-

//Программа формирвоания задержки

void pause (unsigned int a)

{ unsigned int i;

for (i=a;i>0;i--);

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

по крайней мере это справедливо для atmel studio 6.1, и в этом можно убедится просмотрем папку проэкта, там есть *.lss файл содержащий асемблерный код данной программы, генерируемы при сборке проекта. никакого намека на реализацию функции void pause...

в итоге при прошивке контроллера на дисплее получается случайный мусор или пустота...при нажатии несколько раз на ресет мусор может исчезать и вновь появлятся...явно на лицо расссинхронизация проца и экрана

а вот если сделать маленькую поправку

void pause (unsigned int a)

{ unsigned int i;

for (i=a;i>0;i--)
asm("nop");

То для компилятора это обретает смысл, это так же подтверждается явным появлением реализации функции в асемблерном коде

0000006c
:
6c: 9c 01 movw r18, r24
6e: 03 c0 rjmp .+6 ; 0x76
70: 00 00 nop
72: 21 50 subi r18, 0x01 ; 1
74: 31 09 sbc r19, r1
76: 21 15 cp r18, r1
78: 31 05 cpc r19, r1
7a: d1 f7 brne .-12 ; 0x70

и скорей всего все заработает....покрайней мере у меня на atmega16 (внутренняя RC синхронизация 1Mhz) и использовании atmel studio 6.1 было именно так... возможно на др частотах придется поигратся с константой #define TIME 10 и/или значениями передаваемыми функции void pause

вот здесь-> pause(значение) ...или pause(значение*TIME) ....

удачи в обучении управлению AVR!

Смотри, представь что ЖКИ -

Смотри, представь что ЖКИ - пишущая машинка, бумага в машинке - память ЖКИ, каретка - указатель курсора. Кроме того ЖКИ на экран выводит не все содержимое памяти, а лишь часть. Вроде как некоторое окно, которое мы налаживаем на нашу бумагу с текстом.

Вот I/D задает как мы будем печатать, справа-налево или слева-направо.
S определяет, будем ли мы сдвигать окно экрана вслед за тем, как печатаем или нет.
S/C - просто смещает видимое окно экрана или каретку машинки.
R/L - уточняет куда (влево или вправо) мы будем сдвигать экран или курсов с помощью флага S/C.

чего-то помоему не хватает!

Содрал вашу прогу и протэусе и на меги8 не стартует. Экран молчит, стал копать по даташитам и вот что нарыл:
не хватает в инициализации первых трех!

0011 - ждем 5 мс
0011 - ждем 100 мкс
0011 - ждем 2 мс
0010 - ждем 41 мкс
0000 - -и-
0010 - -и-
1000
0000
1000
0000
0001
0000
0100

если я не прав поправте!

Не работает!

Попробовал поменять частоты тактирования, задержки при инициализации и выводе символов(команд), пока что безуспешно. По поводу фьюзов, если вы имеете ввиду сконфигурировать выводы порта D c помощью регистров DDRB, PORTD как выходы с низким лог. уровнем, то это я сделал.
От делать нечего скомпилировал простую прогу вывода символов с помощью средств CodeVisionAVR, загнал в PROTEUS - работает!...а с реальным LCD отказывается..

Нет я говорю о том, что

Нет я говорю о том, что попробуй на порт D вывести например мигалку, или просто зажечь сразу весь порт. Я когда купил только микроконтроллер у меня этого не получилось сделать. Порыл форумы, оказалось что там как-то фьюзы запрограммированы что порт D и все его 8 бит не включены. Проверь этот момент, а лучше попробуй перевесить ЖКИ на другой порт например на B. То что программа в протеусе работает а с реальным нет - это и есть разница в параметрах ЖКИ забитого в протеусе и реального.

Не работает!

Собрал и подключил всё как по схеме, только МК использовал ATmega16 и LCD WH1602M, соответственно откомпилировал в WinAVR для него прошивку. Однако, выводить что либо LCD отказался, также собирал в протеусе(на ATmega 8 и LM016L), данные с МК выводятся но на LCD ничего не видно. В чем может быть проблема? (Если это важно, использовал внутренний RC генератор для тактирования на 1 мГц)

1. Для Atmega16 необходимо

1. Для Atmega16 необходимо через фьюзы включить сперва что бы порт D работал.
2. Попробуй изменить частоту тактирования на 4МГц и на 8МГц. Вся проблема ЖКИ в том, что не выдержаны все паузы при инициализации или при подаче команды. А контроллер ЖКИ очень чувствительный к этому.

Есть вопрос:
Собрал схемку хронометра на меге 8 с готовым хексом, - показания выводятся на WH0802,
показание- число из трех цифр, которые выводятся на весь экран, одна цифра состоит из 4-х знакомест. Экран типа псевдографический. Каким образом могла писаться прошивка??
Автор категорически отказывается давать исходники и не комментирует работу- наверное из соображения "интеллектуальной собственности".
По-свободе хочу попробовать написать свою прошивку в учебных целях.

Столкнулся с такой

Столкнулся с такой ситуацией.
Есть два LCD 16х2:
1 - MTC-S16204XFGHSAY
2 - WH1602A-YGH-CTK

1-ый использую в проекте с GPS.
2-ой решил использовать в проекте с клавиатурой. Но по каким то причинам lcd не работает.
Контраст регулируется и появляются квадратики. И все.
Возможно там другой порядок инициализации.
Помогите разобраться
Вот даташиты
filebox.od.ua/?file=24a31fc50d62bfcd658bdadac84088ab

Дисплеи ничем не отличаются.

Дисплеи ничем не отличаются. Распиновка одинакова. Тайминги немного разнятся. Попробуй увеличить задержки при отсылке команд на ЖКИ или понизь частоту МК.

Все ЖКИ на HD44780 имеют идентичную систему команд. Ты какой интерфейс юзаеш, 4-х битный, или 8-ми битный? Еще попробуй увеличить задержку между включением ЖКИ и его инициализацией, примерно до 0,1с. Полярность питания для ЖКИ не путалась, чтобы сгореть им немного надо? То я сдуру как-то спалил, а потом пытался подключить. Тоже выводились черные квадратики, через раз выводились данные, т.е. работал крайне нестабильно.

Использую программы из статей

Использую программы из статей о GPS.
интерфейс 4-ех битный

попробовал прогу отсюда
chipenable.ru/index.php/programming-c/75-chasy-na-mikrokontrollere.html

заработало

А что изменить в вашей проге?

Обрати внимание на задержки

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

Аналоги HD44780

Столкнулся с проблемой - не могу найти ЖКИ WH1602A по разумной цене. Например
в чипдипе такие стоят chipdip.ru/product/wh1602a-ygh-ct-k.aspx
700 деревянных. Что такое YGH в названии "WH1602A-YGH-CT(K), ЖКИ 16х2, англо-русский"
Какие есть аналоги ЖКИ на базе HD44780? Вот нашёл страничку micronika.ru/order.phtml?vid=64 - там в названии FDCC1602A-FSBFBW-51SR содержится 1602A,
просто обратил внимание. Может и FDCC1602A-FSBFBW-51S сойдёт без особого изменения кода?
Какие проблемы могут возникнуть при использовани
не собственно HD44780 от Хитачи, а его аналогов?
ЗЫ Не плохо бы почитать про использование различных ЖКИ, аналогов хд44780, чем МЭЛТ"овские
ЖКИ плохи

Работа с дисплеем 16x2 на контроллере HD44780 в Bascom-AVR


Жидкокристаллические дисплеи на контроллере HD44780 (а также совместимом с ним KS0066) очень распространены благодаря простому методу работы с ними, а так же небольшой цене. В зависимости от исполнения дисплея, они позволяют выводить от 8-и до 40-ка символов в каждой строке, строк может быть одна, две или четыре. Чаще всего встречаются 8*2 (восемь символов*две строки), 16*2 и 20*4.

Для примера рассмотрим распиновку индикатора 16*2 (у всех дисплеев на контроллере HD44780 она похожа)

У каждого дисплея на контроллере HD44780 для подключения имеется 14 выводов + 2 вывода для подсветки (если она имеется):

  1. Земля, GND
  2. Напряжение питания, Vcc (+5V)
  3. Настройка контрастности, Vo
  4. Выбор регистра, R/S
  5. Чтение/запись, R/W
  6. Сигнал разрешения чтения/записи, E
  7. Bit 0, D0
  8. Bit 1, D1
  9. Bit 2, D2
  10. Bit 3, D3
  11. Bit 4, D4
  12. Bit 5, D5
  13. Bit 6, D6
  14. Bit 7, D7
  15. Питание подсветки для дисплеев с подсветкой, LED +
  16. Питание подсветки для дисплеев с подсветкой, LED -


Данные в дисплей загружаются по шине данных (D0-D7), при этом контроллер поддерживает как 8-и, так и 4-х битное подключение. 4-х битное подключение экономит ножки микроконтроллера и чаще всего достаточно для многих задач (при 8и битном подключении можно быстрее загружать данные в контроллер дисплея, но нам пока это ни к чему, поэтому не будем его рассматривать). Для 4-х битного подключения используются 4 последних бита шины (D4-D7).

В качестве примера будем использовать дисплей 20х4, подключенный к микроконтроллеру ATmega8 по 4х битному интерфейсу по схеме ниже



Дисплей требует для питания 5 вольт, делителем на резисторе R1 настраивается контрастность отображаемых символов, вывод R/W подключается к земле (т.е. выбрана постоянная запись в дисплей). Подключать оставшиеся выводы можно к любым свободным ножкам микроконтроллера. Конфигурация ножек для подключения дисплея у микроконтроллера ATmega8 будет выглядеть следующим образом:

$regfile = "m8def.dat"
$crystal = 1000000 "частота работы 1 МГц

Config Lcd = 20 * 4


Config Lcdpin = Pin , Db4 = PortB . 3 , Db5 = PortB . 2 , Db6 = PortB . 1 , Db7 = PortB . 0 , E = PortB . 4 , Rs = PortB . 5

CLS - очистка дисплея

LCD - вывести данные на дисплей (пример: Lcd "Hello world" выведет надпись Hello world )

А теперь напишем вот такую небольшую программку, которая выведет надпись на дисплей:

$regfile = "m8def.dat" "выбранный тип микроконтроллера
$crystal = 1000000 "частота работы 1 МГц

Config Lcd = 20 * 4 "указываем какой у нас дисплей
"и конфигурируем ножки для подключения
Config

Cursor Off
Cls "очистим дисплей

Lcd "LCD 20*4 HD44780"
Locate 2 , 8 "переводим курсор на вторую строку, восьмое знакоместо
Lcd "сайт" "выводим текст

End

в результате на дисплее получим следующее:

Также в Bascom-AVR есть еще несколько дополнительных команд для работы с дисплеями:

HOME - также возвращает курсор на верхнюю строчку, но в отличии от команды UPPERLINE эта команда может принимать дополнительные значения: если после нее поставить букву L , T или F то курсор переместится в начало строчки, название которой начинается с соответствующей буквы (пример: для того чтобы переместить курсор в начало третьей строки, нужно написать команду HOME T )

пример кода для вывода информации на дисплей с использованием этих команд:

$regfile = "m8def.dat" "выбранный тип микроконтроллера
$crystal = 1000000 "частота работы 1 МГц

Config Lcd = 20 * 4 "указываем какой у нас дисплей
"и конфигурируем ножки для подключения
Config Lcdpin = Pin , Db4 = Portb . 3 , Db5 = Portb . 2 , Db6 = Portb . 1 , Db7 = Portb . 0 , E = Portb . 4 , Rs = Portb . 5

Cursor Off "выключим отображение курсора
Cls "очистим дисплей

Lcd "*** HD44780 LCD ***" "выводим текст в первой строке
Lowerline "переходим на вторую строку
Lcd "Line number 2" "выводим текст
Thirdline "переходим на третью строку
Lcd "AaBbCcDdEeFfGgHfIiJj" "выводим на третьей строке
Fourthline "переходим на четвертую строку
Lcd "1234567890" "печатаем на четвертой строчке

End "конец программы


и пример того как использовать сдвиг текста:

$regfile = "m8def.dat" "выбранный тип микроконтроллера
$crystal = 1000000 "частота работы 1 МГц

Dim A As Byte "переменная для организации цикла

Config Lcd = 20 * 4 "указываем какой у нас дисплей
"и конфигурируем ножки для подключения
Config Lcdpin = Pin , Db4 = Portb . 3 , Db5 = Portb . 2 , Db6 = Portb . 1 , Db7 = Portb . 0 , E = Portb . 4 , Rs = Portb . 5

Cursor Off "выключим отображение курсора
Cls "очистим дисплей

Locate 1 , 11 "устанавливаем курсор на первой строке, десятом знакоместе
Lcd "Bascom-AVR" "выведем текст

"цикл сдвига влево
For A = 1 To 10 "повторяем этот цикл пока переменная А не достигнет значения 10
Shiftlcd Left "сдвинем текст влево
Waitms 300 "задержка 300 миллисекунд
Next A
"цикл сдвига вправо
For A = 1 To 10 "повторяем цикл пока переменная А не достигнет значения 10
Shiftlcd Right "теперь сдвинем текст вправо
Waitms 300 "задержка 300 миллисекунд
Next A "увеличиваем значение переменной А на 1

"продолжаем выполнение программы
Wait 1 "задержка 1 секунда

Home F "устанавливаем курсор на нижнюю строчку

Lcd "END PROGRAM" "и выводим надпись

End "конец программы

И его аналогах, например, таких как S6A0069, KS0066 и т.д. Данные ЖК индикаторы – текстовые и умеют отображать текст и псевдографические символы. Размер знакоместа у них составляет 5x8 пикселей, ЖК индикаторы бывают разных размеров и с разными разрешениями, например: 8 символов на 2 строки – 8x2, 16x2, 20x2, 40x2, 16x4, 20x4 и т.д.

В данном уроке мы рассмотрим 4 битное подключения ЖК индикатора к микроконтроллеру AVR, и написание программы в среде .

У таких ЖК индикаторов существуют выводы:
VSS – Gnd (Минус питания)
VDD – Vcc (Плюс питания 5v)
VO – Установка контрастности ЖК матрицы
RS – Линия управления RS
RW (Read/Write) – Линия управления RW
E (Enable) – Линия управления E
D0 – Линия данных D0 (Не используется в 4 битном режиме)
D1 – Линия данных D1 (Не используется в 4 битном режиме)
D2 – Линия данных D2 (Не используется в 4 битном режиме)
D3 – Линия данных D3 (Не используется в 4 битном режиме)
D4 – Линия данных D4
D5 – Линия данных D5
D6 – Линия данных D6
D7 – Линия данных D7
A – Анод светодиода подсветки дисплея
K – Катод светодиода подсветки дисплея

Внимание! У разных ЖК индикаторов своё расположение выводов, точное расположение выводов вы можете узнать в технической документации (Даташите) на ваш ЖК индикатор.

Вывод ЖК индикатора VO управляет контрастностью ЖК матрицы в зависимости от подаваемого на этот вывод напряжения питания. Вывод RW если не надо считывать с дисплея информацию подключается к минусу питания.

Пример 4 битного подключения ЖК индикатора к микроконтроллеру Attiny2313:

Подстрочный резистор RV1 регулирует яркость ЖК индикатора.
В BASCOM-AVR перед работой ЖК индикатора необходимо указать, какие выводы дисплея подключены, к каким портам микроконтроллера, для этого есть команда Config Lcdpin, пример применения данной команды: Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7 , E = Portb.3 , Rs = Portb.2 а также указать разрешение ЖК индикатора командой Config Lcd, пример: Config Lcd = 16 * 2 и проинициализировать ЖК индикатор командой Initlcd, после этого ЖК индикатор будет готов к работе.

Вот список команд для работы с ЖК индикатором в BASCOM-AVR:
Config Lcdpin – Установка конфигурации выводов ЖК индикатора и микроконтроллера
Config Lcd – Установка разрешения ЖК индикатора
Initlcd – Инициализация ЖК индикатора
Lcd – Вывод текста на ЖК индикатор, пример: Lcd ”Hello”
Cls – Очистка ЖК индикатора
Locate y, x – Установить курсор в позицию x, y
Lowerline – Переместить курсор на нижнею строку
Upperline – Переместить курсор на верхнею строку
Shiftlcd Right – Сдвинуть изображение ЖК индикатора вправо на одно знакоместо
Shiftlcd Left – Сдвинуть изображение ЖК индикатора влево на одно знакоместо
Cursor Off – Отключить курсор
Cursor On – Включить курсор
Cursor On Blink – Включить мерцающий курсор
Cursor On Noblink – Отключить мерцающий курсор

Внимание! При использовании ЖК индикатора c разрешением 8x2 в BASCOM-AVR конфигурируйте его как 16x2, так как в BASCOM-AVR нет конфигурации на ЖК индикатор с разрешение 8x2.

Пример программы в BASCOM-AVR для вышеизложенной схемы:

$regfile = "attiny2313.dat" $crystal = 8000000 Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7 , E = Portb.3 , Rs = Portb.2 Config Lcd = 16 * 2 Initlcd Cls Locate 1 , 1 Lcd "Hello," Lowerline Lcd "world!" End

Вот как всё это работает с ЖК индикатором 8x2:

Фьюз биты для прошивки:

Скачать файлы для урока (проект в , исходник, прошивка) вы можете ниже