Работа с ЖК индикатором на отладочной плате STM32L-Discovery. Работа с символьными жк дисплеями Библиотека для работы с lcd дисплеями
Читатель нашего блога Михаил (mishadesh ) создал отличную библиотеку для работы с LCD и предложил написать статью для демонстрации ее возможностей. Собственно, сегодня именно об этом и пойдет речь 😉 Разберем, какие реализованы функции, а также в конце статьи будет выложен пример для работы с дисплеем.
Как обычно начнем с обсуждения железа… А тут на самом деле и не о чем говорить. Как и в первой статье, посвященной работе с дисплеями (), мы будем использовать отладочную плату Mini STM32 . Собственно, подключение дисплея, основные команды для записи данных, последовательность инструкций для инициализации – все это там есть =) Поэтому сейчас переходим сразу к обсуждению библиотеки для работы с графическими дисплеями.
Вот полный список функций с пояснениями:
Следующая функция, как видно из ее названия, меняет ориентацию экрана. Возможно два положения экрана, соответственно два возможных значения параметра orientation :
- Orientation_Portrait
- Orientation_Album
Функция отрисовывает на графическом дисплее символ, располагая его по переданным в функцию координатам, а также задавая его цвет. Начертание символа соответствует шрифту, определенному в файле font.c (файл идет в составе библиотеки).
Из функции LCD_DrawChar() плавно вытекает следующая функция:
void LCD_DrawString(char * s, uint16_t x, uint16_t y, uint16_t color, uint16_t backColor, uint8_t isTransparent) ; |
Тут понятно и без лишних слов 😉 Функция печатает на LCD строку текста. Базой для этой функции является предыдущая – LCD_DrawChar() .
Помимо символов и текста, конечно же, необходимо иметь возможность нарисовать основные графические примитивы, например линию или круг. Для этого реализовано следующее:
void LCD_drawLine ( int x1, int y1, int x2, int y2, uint16_t color) ; void LCD_DrawRect ( int x1, int y1, int x2, int y2, uint16_t color, uint8_t filled ) ; void LCD_DrawEllipse(uint16_t X1, uint16_t Y1, uint16_t R, uint16_t color) ; |
Для рисования линии нужно передать в функцию координаты начальной точки, координаты конечной точки, а также нужный цвет. Для прямоугольника – координаты верхнего левого угла и координаты правого нижнего угла (!). Последний параметр filled – определяет, необходимо ли выполнять заливку фигуры. Единица – значит да, фигура будет закрашена выбранным цветом, ноль – будет нарисован только контур фигуры. С этим понятно) Осталась только окружность – функция DrawEllipse() . Здесь вместо координат начала и конца (верхнего/нижнего углов) передаем в качестве аргументов центр окружности и радиус.
Ну и напоследок еще одна функция:
void LCD_FillScr(uint16_t color) ; |
Функция позволяет залить экран сплошным цветом.
Все перечисленные функции реализованы в файле GUI_DRV.c .
Помимо них библиотека включает в себя функции для записи данных в дисплей (LCD_DRIVER.c ) а также уже упомянутые шрифты (font.c ). Как видите, все четко отсортировано по разным файлам, так что в принципе все очень понятно, поэтому давайте перейдем к практическому примеру!
Давайте разбираться! Идем в файл main.c … Не буду приводить полный код функций инициализации периферии и дисплея, все это можно посмотреть непосредственно в файле, либо в предыдущей статье, ссылка на которую была в начале этой статьи 😉 Функция main() :
int main(void ) { initPeriph() ; initFSMC() ; initLCD() ; delay(10000 ) ; LCD_FillScr(0xFFFF ) ; delay(100 ) ; LCD_SetOrient(Orientation_Album) ; delay(100 ) ; LCD_DrawString("Библиотека для LGDP4532" , 30 , 30 , 0x888F , 0x0000 , 0 ) ; LCD_DrawRect(100 , 100 , 200 , 200 , 0x0000 , 0 ) ; LCD_DrawRect(120 , 120 , 180 , 180 , 0xFF00 , 1 ) ; LCD_DrawEllipse(150 , 150 , 50 , 0xF000 ) ; while (1 ) { } } |
Начинаем с инициализации, закрашиваем экран белым цветом и устанавливаем альбомную ориентацию экрана. И теперь переходим к отрисовке графики)
Выводим на экран строку, а также два прямоугольника и круг. Результат налицо:
Очевидно, что все работает отлично 😉
Итак, на этом на сегодня заканчиваем, огромное спасибо Михаилу за проделанную работу и приведенные материалы. Вот контакты автора библиотеки:
Skype – mishadesh
Mail – [email protected]
На этом все, спасибо за внимание, до скорых встреч!
Рассмотрим взаимодействие пользователя и устройства на базе микроконтроллера. Очень часто пользователю нужно чем-то вводить информацию, и с чего-то ее считывать. Для этих целей очень хорошо подходит клавиатура и дисплей ().Рассмотрим взаимодействие пользователя и устройства на базе микроконтроллера. Очень часто пользователю нужно чем-то вводить информацию, и с чего-то ее считывать. Для этих целей очень хорошо подходит клавиатура и дисплей (). В этой заметке рассмотрим поподробнее отображение информации на символьном ЖКИ со знакосинтезирующим .
Такие индикаторы часто используются при проектировании цифровых устройств, поэтому с ним необходимо уметь работать.
Рассмотрим типовое внутреннее строение знакосинтезирующего ЖКИ
:
Внутренняя структура 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) – для начальной инициализации индикатора:
#define RS 2 //RS=PD2 - сигнал управления ЖКИ
#define E 3 //E=PD3 - сигнал управления ЖКИ
#define TIME 10 //Константа временной задержки для ЖКИ
//Частота тактирование МК - 4Мгц
//Программа формирвоания задержки
void pause (unsigned int a)
{ unsigned int i;
for (i= a; i> 0 ; i-- ) ;
//Программа передачи команд в ЖКИ
void lcd_com (unsigned char lcd)
{ unsigned char temp;
temp= (lcd& ~(1 << RS) ) | (1 << E) ; //RS=0 – это команда
PORTD= temp; //Выводим на portD старшую тетраду команды, сигналы RS, E
asm("nop" ) ;
PORTD= temp& ~(1 << E) ; //Сигнал записи команды
temp= ((lcd* 16 ) & ~(1 << RS) ) | (1 << E) ; //RS=0 – это команда
PORTD= temp; //Выводим на portD младшую тетраду команды, сигналы RS, E
asm("nop" ) ; //Небольшая задержка в 1 такт МК, для стабилизации
PORTD= temp& ~(1 << E) ; //Сигнал записи команды
pause (10 * TIME) ; //Пауза для выполнения команды
//Программа записи данных в ЖКИ
void lcd_dat (unsigned char lcd)
{ unsigned char temp;
temp= (lcd| (1 << RS) ) | (1 << E) ; //RS=1 – это данные
PORTD= temp; //Выводим на portD старшую тетраду данных, сигналы RS, E
asm("nop" ) ; //Небольшая задержка в 1 такт МК, для стабилизации
PORTD= temp& ~(1 << E) ; //Сигнал записи данных
temp= ((lcd* 16 ) | (1 << RS) ) | (1 << E) ; //RS=1 – это данные
PORTD= temp; //Выводим на portD младшую тетраду данных, сигналы RS, E
asm("nop" ) ; //Небольшая задержка в 1 такт МК, для стабилизации
PORTD= temp& ~(1 << E) ; //Сигнал записи данных
pause(TIME) ; //Пауза для вывода данных
//Программа иниализации ЖКИ
void lcd_init (void )
lcd_com(0x2c ) ; //4-проводный интерфейс, 5x8 размер символа
pause(100 * TIME) ;
pause(100 * TIME) ;
pause (100 * TIME) ;
//Основная программа
int main(void )
DDRD= 0xfc ; //Инициализация portD
PORTD= 0x00 ;
pause(1000 ) ;
lcd_init() ; //Инициализация ЖКИ
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" ) ;
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" ) ;
while (1 ) //бесконечный цикл
return 1 ;
#include
Программа очень проста, разобраться в ней не составит труда любому, кто хоть немного владеет C для AVR . Для латиницы и цифр ASCII коды совпадают с зашитыми в знакогенератор ЖКИ , поэтому позволительно использовать lcd_dat(‘A’) . Можно создать свою библиотеку для работы с ЖКИ, выделив функции lcd_dat(unsigned char x), lcd_com(unsigned char x), lcd_init(void) в отдельный модуль LCD.h и подключать его за надобностью.
Эта затея очень экономит время, стоит только один раз написать нужные функции, а потом все время их только использовать. Также можно подметить, что неудобно выводить длинную фразу по одной букве, для этого можно нашу выводимую строку запихнуть в массив из unsigned char и выводить с помощью цикла:
pause(1000 ) ; //Задержка, чтобы ЖКИ успел включиться
lcd_init() ; //Инициализация ЖКИ
for (i= 0 ; i< 14 ; i++ ) //Вывод записи побуквенно
lcd_dat(data[ i] ) ;
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 ;
Только не стоит забывать, что нумерация массивов в С начинается с нуля. Существующую программу можно без существенных изменений использовать совместно с контроллером 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, чем МЭЛТ"овские
ЖКИ плохи
По просьбе трудящихся, да и моим обещаниям решил я описать работу с знаковым
ЖК 16х2 в среде CodeVisionAVR. Начнем с описания самого ЖК. Алфовитно-цифровой ЖК
дисплей со встроенным чипом HD44780 фирмы Hitachi может выводить символы в одну,
две или четыре сроки по 8, 16, 20 или 40 символов в каждой. В данной статье я буду
рассматривать ЖК 16х2 (16 символов, 2 строки)
. Данный дисплей для физического
подключения к МК имеет 16 выводов (расположение выводов зависит от фирмы
изготовителя)
. Давайте посмотрим на эти выводы. Не мудрствуя лукаво я спер табличку
в МЭЛТе. В принципе она подходит для любого ЖК.
Ну я думаю что объяснять не нужно для чего нужен тот или иной пин. Там все написано
по русски. Но есть несколько небольших но.
1) ЖК дисплеи могут быть выпущены в двух вариантах на 5 вольт, либо на 3,3.
2) В цепи питания не всегда установлен токоограничивающий резистор. Смотрите
внимательно, может стоять просто перемычка. (Я так спалил подсветку на двух
дисплеях.)
3) Схема включения резистора для регулировки контрастности.
Так, ну теперь как сие чудо подключить к МК. Работать будем с ATmega8 и кварцем
на 4 МГц. Вот собственно и схема.
Как видите ничего сложного нет. Первые три разряда порта D
служат для управления,
а последние четыре для данных. Также можно работать с этими дисплеями по 8-и битной
шине, но я думаю отдавать лишние 4 ноги это расточительство. Поэтому будем работать
по 4-х битной шине. Со схемой разобрались, теперь давайте с программной частью.
Для инициализации дисплея и перевод его в 4-х битный режим нужно выполнить
несколько команд. Но перед этим я хочу разъяснить как работают управляющие биты.
Бит RS отвечает за то что будет принимать ЖК. Если RS = 0
, то мы передаем
команду, а если 1
то данные. Если бит RW = 0
, то мы записываем в ЖК, а если 1
,
то читаем. Бит Е
просто строб. То есть как только мы захотим ввести команду или
данные, то после того как выставили все биты на ножках просто выставляем в 1
бит
Е
, а потом опять роняем в 0
.
1 - Включить питание
2 - Выдержать паузу не менее 20 мс
3 - Команда для 4-х бит. шины
4 - Выдержать паузу не менее 40 мкс
5 - Команда для 4-х бит. шины (RS=0), (RW=0), (D7=0), (D6=0), (D5=1),(D4=1)
6 - Выдержать паузу не менее 40 мкс
7 - Команда для 4-х бит. шины (RS=0), (RW=0), (D7=0), (D6=0), (D5=1),(D4=1)
8 - Выдержать паузу не менее 40 мкс
9 - Команда для 4-х бит. шины (RS=0), (RW=0), (D7=0), (D6=0), (D5=1),(D4=0)
10 - Выдержать паузу не менее 40 мкс
11 - Выставить параметры (RS=0), (RW=0), (D7=0), (D6=0), (D5=1),(D4=0)
(RS=0), (RW=0), (D7=1), (D6=0), (D5=0),(D4=0)
12 - Выключаем дисплей (RS=0), (RW=0), (D7=0), (D6=0), (D5=0),(D4=0)
(RS=0), (RW=0), (D7=0), (D6=0), (D5=1),(D4=0)
13 - Очищаем экран (RS=0), (RW=0), (D7=0), (D6=0), (D5=0),(D4=0)
(RS=0), (RW=0), (D7=0), (D6=0), (D5=0),(D4=1)
14 - Режим ввода данных (RS=0), (RW=0), (D7=0), (D6=0), (D5=0),(D4=0)
(RS=0), (RW=0), (D7=0), (D6=1), (D5=1),(D4=0)
О как. Теперь после этой абракадабры наш дисплей готов принимать данные. Что
дальше. А дальше давайте ка рассмотрим команды ЖК. Для передачи команд/данных в
ЖК по 4-х битной шине требуется два захода. Первым передаем старшие 4 байта, а
вторым передаем младшие 4 байта. Дальше все команды я буду писать парами.
Команда очистки индикатора и постановка курсора в левый верхний угол.
RS=0, RW=0, D4=0, D5=0, D6=0, D7=0 (E=1 потом 0)
RS=0, RW=0, D4=0, D5=0, D6=0, D7=1 (E=1 потом 0)
Команда перемещения курсора в левую позицию. (Х-значит пофик какое значение)
RS=0, RW=0, D4=0, D5=0, D6=0, D7=0 (E=1 потом 0)
RS=0, RW=0, D4=0, D5=0, D6=1, D7=Х (E=1 потом 0)
Команда устанавливает направление сдвига курсора(ID=0/1 влево/вправо).
Так же разрешение сдвига дисплея (SH=1) при записи в DDRAM.
RS=0, RW=0, D4=0, D5=0, D6=0, D7=0 (E=1 потом 0)
RS=0, RW=0, D4=0, D5=1, D6=ID, D7=SH (E=1 потом 0)
Команда включения дисплея (D=1) и выбора курсора (A, B).
A=0, B=0
Курсора нет, ничего не мигает
A=0, B=1
Курсора нет, мигает весь символ
A=1, B=0
Курсор в виде подчеркивания, не мигает
A=1, B=1
Курсор в виде подчеркивания и мигает
RS=0, RW=0, D4=0, D5=0, D6=0, D7=0 (E=1 потом 0)
RS=0, RW=0, D4=1, D5=D, D6=A, D7=B (E=1 потом 0)
Команда сдвига дисплея/курсора(SC=0/1 курсор/дисплей RL=0/1 влево/вправо).
RS=0, RW=0, D4=0, D5=0, D6=0, D7=1 (E=1 потом 0)
RS=0, RW=0, D4=SC, D5=RL, D6=X, D7=X (E=1 потом 0)
Команда установки разрядности шины(DL=0/1 4/8 бит) А так же страници
знакогенератора Р.
RS=0, RW=0, D4=0, D5=0, D6=1, D7=DL (E=1 потом 0)
RS=0, RW=0, D4=1, D5=0, D6=Р, D7=0 (E=1 потом 0)
Команда установки адреса следующей операции с установкой туда курсора и
выбора области CGRAM(Свои придуманные символы).
RS=0, RW=0, D4=0, D5=1, D6=ACG, D7=ACG (E=1 потом 0)
RS=0, RW=0, D4=ACG, D5=ACG, D6=ACG, D7=ACG (E=1 потом 0)
Команда установки адреса последующей операции и выбор области памяти
DDRAM (Знакогенератор).
RS=0, RW=0, D4=0, D5=1, D6=ADD, D7=ADD (E=1 потом 0)
RS=0, RW=0, D4=ADD, D5=ADD, D6=ADD, D7=ADD (E=1 потом 0)
Команда Записи данных в текущую область.
RS=1, RW=0, D4=DATA, D5=DATA, D6=DATA, D7=DATA (E=1 потом 0)
RS=1, RW=0, D4=DATA, D5=DATA, D6=DATA, D7=DATA (E=1 потом 0)
Команда Чтения данных в текущую область.
RS=1, RW=1, D4=DATA, D5=DATA, D6=DATA, D7=DATA (E=1 потом 0)
RS=1, RW=1, D4=DATA, D5=DATA, D6=DATA, D7=DATA (E=1 потом 0)
Вот собственно и все команды. Есть еще команда чтения флага занятости, но я ей
не пользуюсь, а просто выдерживаю между каждой командой не менее 40 мкс. Вот и все.
А теперь после прочтения этого трактата, выпейте чашку чая или кофе и забудьте
про все это. Так как всю эту муру на себя берут функции из библиотеки CodeVisionAVR.
Создаем новый проект как это было уже рассказано. Для тех кто не в курсе идем
сюда , остальные заходят в код-генераторе на вкладку LCD
и выбирают PORTD
.
Что мы этим сделали. Первое мы сказали программе что хотим работать с ЖК дисплеем
(выбрав вкладку LCD
). Потом мы сказали что подключим его к порту D
. Ниже выпадающий
список дает возможность выбрать количество символов в строке. Так как по
умолчанию стоит 16
, а мы хотим работать с ЖК 16х2, то ничего менять не надо.
Ниже для подсказки расписаны ножки порта для правильного подключения ЖК к МК.
Все, сохраняем проект и смотрим на свеже-сгенерированный код.
Первое на что надо обратить внимание - это на кусок кода после директивы
препроцессора #include
Следующая функция.
void lcd_puts(char *str)
Эта функция выводит строку расположенную в SRAM начиная с текущей позиции.
Пример:
lcd_gotoxy(0,0);
lcd_puts("СТРОКА");
Видим:
Следующая функция.
void lcd_putsf(char *str)
Эта функция выводит строку расположенную во FLASH начиная с текущей позиции.
Пример:
lcd_gotoxy(0,0);
lcd_putsf("СТРОКА");
Видим:
Ну и замыкает все это безобразие функция "Ластик"
void lcd_clesr(void)
Вызвав данную функцию вы сотрете все что есть на дисплее, а курсор встанет в
крайнее левое положение верхней строки. Вот так для начала можно выводить слова
и цифры на ЖК дисплей при помощи готовых функций.
Теперь давайте поговорим о том как выводить значение переменных. Для этих целей
нам понадобится еще одна библиотека. Ну те кто программировал на С под ПК про нее
должны знать. Называется она stdio.h
Поднимаемся на самый верх программы и после директивы препроцессора
#include
Вот мы и научились выводить форматированный текст на ЖК. Далее кратко пробегусь
по типам преобразования.
i
d
- Для вывода десятичной целой со знаком
u
- Для вывода десятичной целой без знака
e
-d.d e-d
E
- Для вывода вещественного с плавающей точкой вида -d.d E-d
f
- Для вывода вещественного с плавающей точкой вида -d.d
x
- Для вывода в шеснадцатеричном виде маленькими буквами
X
- Для вывода в шеснадцатеричном виде большими буквами
c
- Для вывода в символа
Если написать %-05d
то знак "-"
заставит выравнивать по левому краю, а пустышки
нулями забиваться не будут.
Если вы попытаетесь напечатать число с плавающей точкой, то сильно удивитесь. Число
не напечатается. Во засада)) Проблема кроется в настройках компилятора. Для того
чтобы компилятор начал понимать формат float
нужно его немного настроить. Для этого
заходим Project->Configure
и заходим во вкладку C Compiler
. В своистве
(s)printf Features:
выбираем float, width, precision
. Вот и все.
Пробуйте, экспериментируйте. Возникнут вопросы, пишите на форуме.
Удачи!
И его аналогах, например, таких как 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:
Фьюз биты для прошивки:
Скачать файлы для урока (проект в , исходник, прошивка) вы можете ниже
Для работы с символьными графическими дисплеями предлагаем воспользоваться библиотекой LiquidCrystal которая входит в стандартный набор Arduino IDE и предназначена для работы по 8-битному (4-битному) параллельному интерфейсу. Если Ваш дисплей подключается к Arduino по шине I2, то Вам нужно установить библиотеку LiquidCrystal_I2C (большинство функций которой повторяют функции первой библиотеки).
Поддерживаемые дисплеи:
Дисплей | Подключение и инициализация |
---|---|
LCD1602 - символьный дисплей (16x02 символов), |
#include [ , 8 , 9 , 10 , 11 ]); void setup(){ lcd.begin(16 , 2); } // Пояснение:
|
с интерфейсом I2C (синий) |
#include #include LiquidCrystal_I2C lcd(0x27 или 0x3F , 16 , 2); void setup(){ lcd.init(); } // Пояснение: |
LCD1602 I2C - символьный дисплей (16x02 символов), с интерфейсом I2C (зелёный) |
#include #include LiquidCrystal_I2C lcd(0x27 или 0x3F , 16 , 2); void setup(){ lcd.init(); } // Пояснение: |
LCD2004 - символьный дисплей (20x04 символов), с параллельным интерфейсом (синий) |
#include LiquidCrystal lcd(2 , 3 , 4 , 5 , 6 , 7 [ , 8 , 9 , 10 , 11 ]); void setup(){ lcd.begin(20 , 4); } // Пояснение: // Если используется 8 проводов шины данных, то указываем их все |
LCD2004 I2C - символьный дисплей (20x04 символов), с интерфейсом I2C (синий) |
#include #include LiquidCrystal_I2C lcd(0x27 или 0x3F , 20 , 4); void setup(){ lcd.init(); } // Пояснение: |
#1 Пример
Выводим надпись на дисплей LCD1602 подключённый по шине I2C. Для работы с дисплеем LCD2004 нужно изменить 3 строку на LiquidCrystal_I2C lcd(0x27,20,4);
#include
#2 Пример
Выводим надпись на дисплей LCD1602 подключённый по 4-битной параллельной шине. Для работы с дисплеем LCD2004 нужно изменить 5 строку на lcd.begin(20, 4);
#include
#3 Пример
Выводим надпись «Русский язык» на дисплей LCD1602 подключённый по шине I2C:
#include
Функции, общие для библиотек LiquidCrystal и LiquidCrystal_I2C:
- begin(cols,rows,); – Инициализация дисплея с указанием количества столбцов, строк и размера символа.
- clear(); – Очистка дисплея с установкой курсора в положение 0,0 (Занимает много времени!).
- home(); – Установка курсора в положение 0,0 (Занимает много времени!).
- display(); – Быстрое включение дисплея (без изменения данных в ОЗУ).
- noDisplay(); – Быстрое выключение дисплея (без изменения данных в ОЗУ).
- blink(); – Включение мигающего курсора (с частотой около 1 Гц).
- noBlink(); – Выключение мигающего курсора.
- cursor(); – Включение подчеркивания курсора.
- noCursor(); – Выключение подчеркивания курсора.
- scrollDisplayLeft(); – Прокрутка дисплея влево. Сдвиг координат дисплея на один столбец влево (без изменения ОЗУ).
- scrollDisplayRight(); – Прокрутка дисплея вправо. Сдвиг координат дисплея на один столбец вправо (без изменения ОЗУ).
- leftToRight(); – Указывает в дальнейшем сдвигать положение курсора, после вывода очередного символа, на один столбец вправо.
- rightToLeft(); – Указывает в дальнейшем сдвигать положение курсора, после вывода очередного символа, на один столбец влево.
- noAutoscroll(); – Указывает в дальнейшем выравнивать текст по левому краю от позиции курсора (как обычно).
- autoscroll(); – Указывает в дальнейшем выравнивать текст по правому краю от позиции курсора.
- createChar(num,array); – Запись пользовательского символа в CGRAM дисплея под указанным номером.
- setCursor(col,row); – Установка курсора в позицию указанную номером колонки и строки.
- print(text); – Вывод текста, символов или цифр на экран дисплея. Синтаксис схож с одноимённой функцией класса Serial.
Функции, реализованные только в библиотеке LiquidCrystal_I2C:
- init(); – Инициализация дисплея. Должна быть первой командой библиотеки LiquidCrystal_I2C после создания объекта. На самом деле данная функция есть и в библиотеке LiquidCrystal, но в той библиотеке она вызывается автоматически (по умолчанию) при создании объекта.
- backlight(); – Включение подсветки дисплея.
- noBacklight(); – Выключение подсветки дисплея.
- setBacklight(flag); – Управление подсветкой (true - включить / false - выключить), используется вместо функций noBacklight и backlight.
Подключение:
// Для шины I2C:
|
Параметр:
|
// Для параллельной шины из 4 проводов:
#include LiquidCrystal lcd( RS , E , D4 , D5 , D6 , D7 ); void setup(){ lcd.begin( col , row ); } |
Параметр:
|
// Для параллельной шины из 8 проводов:
#include LiquidCrystal lcd( RS , E , D0 , D1 , D2 , D3 , D4 , D5 , D6 , D7 ); void setup(){ lcd.begin( col , row ); } |
|
begin(col ,
row ,
);
Инициализация дисплея с указанием размеров экрана и символов. |
Параметр:
|
Функции управления дисплеем:
display();
Включает дисплей после того как он был выключен функцией noDisplay. |
Примечание: Функция выполняется быстро и без изменений в ОЗУ дисплея. |
noDisplay();
Выключает дисплей. Данные на дисплее не будут отображаться до вызова функции display, но и не сотрутся из памяти ОЗУ, а после вызова функции display, опять будут отображаться. |
Примечание: Функция выполняется быстро и без изменений в ОЗУ дисплея. |
scrollDisplayLeft();
Сдвигает координаты дисплея на один столбец влево. |
|
scrollDisplayRight();
Сдвигает координаты дисплея на один столбец вправо. Постоянный вызов данной функции создаст эффект бегущей строки. Координаты сдвигаются как для имеющейся на дисплее информации, так и для той, которая будет выведена после. |
Примечание: Функция выполняется без изменений ОЗУ дисплея. Если вызвать функцию 40 раз подряд, то координата вернётся в изначальную точку |
clear();
Очистка дисплея с установкой курсора в положение 0,0. Информация имеющаяся на дисплее безвозвратно сотрётся. |
Примечание: Занимает много времени. |
backlight();
Включение подсветки дисплея. |
|
noBacklight();
Выключение подсветки дисплея. |
Примечание: Функция реализована только в библиотеке LiquidCrystal_I2C. |
setBacklight(flag );
Управление подсветкой (вместо функций noBacklight и backlight). |
Параметр:
|
Функции управления курсором:
setCursor(col ,
row );
Установка курсора в указанную позицию. |
Параметр:
|
home();
Установка курсора в позицию 0,0. Работает как функция setCursor(0,0); |
Примечание: Занимает много времени. |
blink();
Включение мигающего курсора. |
Примечание: Курсор занимает всё поле символа и мигает с частотой около 1 Гц, в той позиции где он был установлен ранее. |
noBlink();
Выключение мигающего курсора. |
Примечание: Курсор становится невидим, но его позиция сохраняется. |
cursor();
Включение подчеркивания курсора. |
Примечание: Курсор принимает вид символа подчёркивания и находится в той позиции, где он был установлен ранее. |
noCursor();
Выключение подчеркивания курсора. |
Примечание: Курсор становится невидим, но его позиция сохраняется. |
Функции указывающие направление и выравнивание:
leftToRight();
Указывает, что после каждого нового символа, положение курсора должно сдвигаться на один столбец вправо. |
Примечание: Если вывести текст "abc" на дисплее отобразится "abc" и текст будет находиться правее от изначального положения курсора. (Как обычно) |
rightToLeft();
Указывает, что после каждого нового символа, положение курсора должно сдвигаться на один столбец влево. |
Примечание: Если вывести текст "abc" на дисплее отобразится "cba" и текст будет находиться левее от изначального положения курсора. (Письменность справа налево) |
noAutoscroll();
Указывает, что в дальнейшем, текст нужно выравнивать по левому краю от изначальной позиции курсора. |
Примечание: если установить курсор в позицию 10,0 и вывести текст, то в данной позиции будет находиться первый символ выведенного текста. (Как обычно) |
autoscroll();
Указывает, что в дальнейшем, текст нужно выравнивать по правому краю от изначальной позиции курсора. |
Примечание: если установить курсор в позицию 10,0 и вывести текст, то в данной позиции будет находиться курсор. (Координаты дисплея будут сдвинуты влево, как будто Вы вызвали функцию scrollDisplayLeft столько раз, сколько букв в выведенном тексте) |
Функции ввода текста и символов:
createChar(num,array);
Запись пользовательского символа в CGRAM дисплея под указанным номером. Если Вы хотите вывести текст (функцией print) в котором должен находиться установленный Вами символ, укажите слэш и номер под которым был записан этот символ: print("C\1MBO\2"). |
Параметр:
|
print(text);
Вывод текста, символов или цифр на экран дисплея. |
Параметр:
|