В этой статье я расскажу как с помощью достаточно распространенной библиотеки управлять 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 <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#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; } }


Архив для статьи
Описание: Библиотека для работы с LCD, проект в AVRSTUDIO, Proteus
Размер файла: 2.84 KB Количество загрузок: 7 489 Скачать

Комментарии  

+1 #21 Igor22131 05.08.2014 22:38
Скажите, почему у меня при компиляции приведенного кода в AVR Studio 5 компилятор ругается :
"region 'text' overflowed by 2142 bytes" ?
Сообщить модератору
0 #22 Виктор 25.09.2014 17:26
:cry: Добавьте пожалуйста функцию вывода плавающей запятой. Или подскажите пример для вывода АЦП от ноля до 50 вольт, к примеру. Не могу придумать как делить и раскладывать по разрядам :oops: Спасибо
Сообщить модератору
0 #23 Виктор 25.09.2014 19:40
:sigh: А как сделать чтобы прогресс бар начинался не с ноля и до какого то числа, 0-255, а к примеру 100-230? Что то в этом роде...
Сообщить модератору
0 #24 Виктор 25.09.2014 19:43
:-* То есть, получается, нужен minprogres.
Сообщить модератору
+1 #25 AntonChip 25.09.2014 21:08
Цитирую Виктор:
:sigh: А как сделать чтобы прогресс бар начинался не с ноля и до какого то числа, 0-255, а к примеру 100-230? Что то в этом роде...

Вариант, преобразовывать переменную чтобы минимум шкалы был при 100 а максимум при 230, или менять саму функцию progressbar
Сообщить модератору
0 #26 sascha69 22.12.2014 00:07
Здравствуйте. Пишу в atmel studio 6, выдаёт 18 ошибок типа "Error 6 undefi ned reference to `lcd_clr' подскажите, что не так. И еще почему после добавления библиотеки нужно всегда перезапустить студию, иначе не видит библиотеку.
Спасибо.
Сообщить модератору
0 #27 Артем1 10.05.2015 15:58
если использовать дисплей в две строки на 40 символов.как необходимо будет переделать код?
Сообщить модератору
0 #28 Юра 24.05.2016 07:30
Какие пределы измерений у данного вольтметра? И можно ли им измерять свое питание (Использовать как индикатор заряда у питающей атмегу батареи)?

Спасибо!
Сообщить модератору
+1 #29 AntonChip 24.05.2016 07:56
Цитирую Юра:
Какие пределы измерений у данного вольтметра? И можно ли им измерять свое питание (Использовать как индикатор заряда у питающей атмегу батареи)?

Спасибо!

предел 0-5 Вольт, если напряжение питания 5 Вольт
Измерять свое напряжения питания можно если использовать внутренний ИОН, подробнее тут rlocman.ru/.../...
Сообщить модератору
0 #30 Юра 24.05.2016 22:02
Просто огромнейшее спасибо за ссылку! 8)

А можно ли как нибудь измерить при помощи МК какой ток потребляет вся схема? Хотелось бы обойтись без посторонних микросхем. (Я себе часы наручные делаю, очень поможете)

Заранее спасибо
Сообщить модератору
0 #31 иван русев 07.12.2016 21:09
подскажите а чем отличается библиотека 16x2 на 20х4
Сообщить модератору
0 #32 goodspeedmen 01.11.2017 17:47
Меняю порты в lcd_lib.h и перестаёт работать :o
Сообщить модератору
0 #33 goodspeedmen 01.11.2017 17:49
как отключить LCD_RW удалить весь код? или
Сообщить модератору
0 #34 goodspeedmen 11.11.2017 16:43
Я понимаю что вопрос чайника, но все же. Пытаюсь написать код на СИ для LCD - AVR, вроде казалось вопрос избитый но как оказалось хороший библиотеке рабочей нет, то распиновка не подходит, всякая фигня в виде ошибок или вообще не работает. Читая всякие сайты я не смог понять как происходит передача числа из переменной если значение более 9. В памяти lcd нет числа 124 или 234 значит либо это происходит программно или аппаратно в самом lcd. Но судя из того кода в библиотеках которые я смог найти и понять, идет просто отправка байта, значит это происходит аппаратно в lcd?
Сообщить модератору
0 #35 3dpoint 25.07.2019 18:46
"В функциях lcd_com и lcd_cmd используется прямая запись в порт
LDP=(ch&0b11110 000);
следовательно все определения ножек в .h файле игнорируются и работает это только при строгом подключении шины данных к старшим ногам порта."
Как это поправить? ;-)
Сообщить модератору
0 #36 Юльич 05.04.2020 14:21
Спасибо за доступную для понимания информацию! Парочка вопросов:
Код:void lcd_num_to_str(unsigned int value, unsigned char nDigit)
{
switch(nDigit)
{
case 5: lcd_dat((value/1000)+'0');
case 4: lcd_dat(((value/100)%10)+'0');
case 3: lcd_string(".",1);
case 2: lcd_dat(((value/10)%10)+'0');
case 1: lcd_dat((value%10)+'0');
}

}
lcd_gotoxy(6, 0);
lcd_num_to_str(ADC, 4); // выводит 4-х разрядное значение АЦП в 6 знакоместо 2-й строки

1. Как вывести фактические вольты, да еще с разрешением до сотых?
2. Непонятно, откуда взялась переменная ADC, в коде она не упоминается.
Сообщить модератору
0 #37 AntonChip 06.04.2020 10:38
Здравствуйте.
1. Фактическое напряжение вычисляется по формуле, подробнее здесь radioparty.ru/.../...
2. ADC это не переменная, это регистр контроллера, в нем хранится 10 битный результат преобразования
Сообщить модератору
+1 #38 Вовка 17.10.2020 14:18
код (функция) для вывода с плавающей точкой
//*****************************************************************
void lcdFloat(float float_number, int8_t nrOfDigits){
int16_t integer_part_1 = float_number;
float fractional_part = float_number - integer_part_1;
int16_t integer_part_2 = fractional_part * 10;//100

// Преобразовать дробную часть в положительную
if(integer_part_2 < 0) integer_part_2 = -integer_part_2;
if(float_number < 0 && integer_part_1 == 0) lcd_str_out("-");

lcd_number_to_str(integer_part_1, nrOfDigits);
lcd_str_out(".");
lcd_number_to_str(integer_part_2, 1);
}
Сообщить модератору
0 #39 sergi 12.03.2021 23:05
[quote name="Вовка"]ко д (функция) для вывода с плавающей точкой
//************* *************** *************** *************** *******
код рабочий ?
Сообщить модератору

Последние комментарии

Сейчас на сайте

Сейчас на сайте 79 гостей и нет пользователей