Для того, чтобы обеспечить хорошую коммуникацию между миром машин и миром людей, необходим жидкокристаллический дисплей. Как правило, он является важным компонентом различных встраиваемых систем. Все дисплеи, большие они или маленькие, функционируют согласно следующим основным принципам. Рассмотрим дисплеи 16x1 и 16x2. Дисплей 16x1 позволяет отобразить 16 символов в одной строке. Дисплей 16x2 позволяет отображать 32 символа – 16 символов на первой строке и 16 символов на второй. Для того чтобы научиться работать с дисплеем необходимо понять, что каждый символ занимает на дисплее 5x10=50 пикселов. То есть чтобы отобразить один символ на экране дисплея, все эти пикселы должны работать одновременно. Но эти проблемы нас не будут волновать поскольку в составе дисплея, который мы будем использовать, присутствует контроллер HD44780, который берет всю работу по контролю этих пикселов на себя.
Необходимые компоненты
Аппаратное обеспечение
- Микроконтроллер ATmega32 (семейство AVR).
- Программатор AVR-ISP (купить на AliExpress), USBASP (купить на AliExpress) или другой подобный.
- JHD_162ALCD (жидкокристаллический дисплей 16x2) (купить на AliExpress).
- Конденсатор 10 мкФ.
- Источник питания с напряжением 5 Вольт.
Программное обеспечение
- Atmel Studio версии 6.1 (или выше).
- Progisp или flash magic (необязательно).
Работа схемы
Схема устройства приведена на следующем рисунке.
На схеме показано, что порты микроконтроллера AVR ATmega32 подсоединены к портам данных жидкокристаллического дисплея (ЖК). При этом необходимо помнить о том, что необходимо деактивировать интерфейс JTAG в PORTC ATmega32 при помощи изменения фьюзов (fuse bytes) чтобы иметь возможность использовать порты PORTC в качестве обычных портов ввода/вывода. У ЖК дисплея 16x2 всего 16 контактов если в нем присутствует черный цвет. Если же черного цвета нет, то у ЖК дисплея будет 14 контактов. 2 контакта, отвечающих за черный цвет, можно проигнорировать. Таким образом, среди оставшихся 14 контактов имеем 8 контактов данных (7-14 или D0-D7), 2 контакта для подачи питающего напряжения (1&2 или VSS&VDD или gnd&+5v), 3-й контакт для контроля контраста (насколько "жирно" будут выглядеть символы на экране), 3 контакта контроля (RS&RW&E).
На представленной схеме использовано только 2 контакта контроля, что обеспечивает дополнительную гибкость схеме. Контакт контраста и контакт READ/WRITE используются редко, поэтому в нашем случае они могут быть просто замкнуты на землю, что гарантирует ЖК дисплею максимальный контраст и переключает его в режим чтения (READ). Нам необходимо всего лишь управлять контактами ENABLE и RS чтобы передавать на дисплей символы и данные.
Необходимые соединения между микроконтроллером ATmega32 и 16x2 ЖК дисплеем следующие:
PIN1 или VSS – земля (ground)
PIN2 или VDD или VCC – питание +5 В
PIN3 или VEE - земля (обеспечивает максимальный контраст символов)
PIN4 или RS (Register Selection) - PD6 микроконтроллера
PIN5 или RW (Read/Write) - земля (переводит ЖК дисплей в режим чтения)
PIN6 или E (Enable) - PD5 микроконтроллера
PIN7 или D0 - PA0 микроконтроллера
PIN8 или D1 - PA1
PIN9 или D2 - PA2
PIN10 или D3 - PA3
PIN11 или D4 - PA4
PIN12 или D5 - PA5
PIN13 или D6 - PA6
PIN14 или D7 - PA7
В представленной схеме мы использовали 8-битную связь с ЖК (D0-D7), хотя это не обязательно и мы могли ограничиться 4-битной связью (D4-D7) – но в этом случае программа была бы немного сложнее, что было бы не очень хорошо для начинающих.
Таким образом, мы соединили 10 контактов ЖК дисплея с микроконтроллером, из которых 8 контактов используются для передачи данных, а 2 контакта – для управления.
Принципы управления жидкокристаллическим дисплеем
Итак, мы определились с тем, что будем использовать 10 контактов ЖК дисплея: 8 контактов для передачи данных и 2 контакта для управления.
2 контакта управления будут использоваться следующим образом:
1. Контакт RS (Register selection – выбор регистра) будет использоваться для того, чтобы сообщить ЖК дисплею о том будем ли мы пересылать ему данные или команду.
К примеру:
В представленной таблице (верхней) значение порта данных ЖК дисплея (D7-D0), равное "0b0010 1000" (двоичный код) или "0x28" (шестнадцатеричный код) указывает на то, что ЖК дисплей должен отобразить на своем экране символ "(". В таблице 2 (нижней) то же самое значение "0x28" указывает ЖК дисплею что он должен переключиться в режим: 4 бита, 2 строки, 5х7 точек. Таким образом, одно и то же значение порта данных (D7-D0) может использоваться для двух целей – и выбор одной из этих целей осуществляется с помощью регистра выбора RS. Если на контакте RS низкое напряжение – это свидетельствует ЖК дисплею о том, что мы будем передавать команду. Если на контакте RS высокое напряжение, то ЖК дисплей понимает что мы будем передавать данные. Соответственно, ЖК дисплей конфигурирует свой порт данных в зависимости от состояния регистра (контакта) RS.
2. Контакт E (Enable - доступен) устанавливает готовность порта данных к приему информации. Если напряжение на этом контакте изменяется с высокого на низкое – это свидетельствует о том, что ЖК дисплей принял данные и отображает на экране соответствующий результат. Таким образом, на этот контакт подается высокое напряжение перед началом передачи данных и низкое напряжение когда процесс передачи данных завершен.
Объяснение работы программы
После того как вы соединили аппаратные компоненты схемы между собой, запустили программу Atmel studio и начали в ней новый проект для написания программы, сейчас самое время открыть окно программирования и начать написание программы. Программа должны делать следующие вещи.
Сначала мы сообщаем микроконтроллеру ATmega32 какие порты ЖК дисплея мы собираемся использовать для передачи данных и команд управления. Затем мы сообщаем микроконтроллеру когда мы будем посылать данные ЖК дисплею устанавливая соответствующие значения контактов RS и E дисплея.
Короткое объяснение принципов работы программы:
- На контакт E подается высокое напряжение (сообщаем ЖК дисплею что он будет принимать данные), а на контакт RS подается низкое напряжение (сообщаем ЖК дисплею о том, что будет передаваться команда).
- Передаем значение 0x01 на порт данных – команда очистки экрана.
- На контакт E подается высокое напряжение (сообщаем ЖК дисплею что он будет принимать данные), на контакт RS также подается высокое напряжение (сообщаем ЖК дисплею о том, что будут передаваться данные).
- Передаем строку символов – по одному символу, один за другим.
- На контакт E подается низкое напряжение – сообщаем ЖК дисплею о том, что мы закончили передачу данных.
- После этой последней команды ЖК дисплей заканчивает процессы связи (передачи/приема данных), обрабатывает полученные данные и высвечивает полученную строку символов на экране.
В представленном сценарии работы программы мы передаем поочередно символы на ЖК дисплей – один за другим. Символы передаются на ЖК дсиплей в ASCII коде (American standard Code for Information Interchange - Американский стандартный код обмена информацией).
На следующем рисунке представлена таблица ASCII кодов. К примеру, чтобы ЖК дисплей отобразил символ “@” мы должны передать ему в шестнадцатеричном коде код “64”. Если мы передадим на ЖК дисплей значение ‘0x62’, то он отобразит на экране символ ‘>’. Таким образом, передавая необходимые ASCII коды на ЖК дисплей, мы заставим отображать его те символы, которые нам нужны.
Ниже представлен код программы на языке С с необходимыми пояснениями.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
// код программы для взаимодействия жидкокристаллического дисплея с микроконтроллером ATmega32 #include <avr/io.h> #define F_CPU 1000000UL #include <util/delay.h> #define RS 6 #define E 5 void send_a_command (unsigned char command); void send_a_character(unsigned char character); int main(void) { DDRA = 0xFF; DDRD = 0xFF; _delay_ms(50); send_a_command(0x01);// команда очистить экран send_a_command(0x38);// устанавливаем режим 16*2 в ЖК дисплее send_a_command(0x0E);// включить экран и курсор send_a_character (0x44); // ASCII код для символа 'D' send_a_character (0x49); // ASCII код для символа 'I' send_a_character (0x4C); // ASCII код для символа 'L' send_a_character (0x49); // ASCII код для символа 'I' send_a_character (0x50); // ASCII код для символа 'P' } void send_a_command (unsigned char command) { PORTA=command; PORTD&= ~(1<<RS); PORTD|= (1<<E); _delay_ms(50); PORTD&= ~(1<<E); PORTA =0; } void send_a_character (unsigned char character) { PORTA=character; PORTD|= (1<<RS); PORTD|= (1<<E); _delay_ms(50); PORTD&= ~(1<<E); PORTA =0; } |
Здравствуйте, есть вопрос. В принципе все понятно, верхнюю строчку LCD (1 Line)освоил, а как теперь спуститься вниз, на (2 Line)? Надеюсь понятно написал:)
Что надо изменить в коде под 4 бит?
Дмитрий, для 4 битного режима уже не помню что нужно изменить. Возможно,когда вернусь из отпуска,смогу помочь в этом вопросе если для вас это будет ещё актуально
Да, актуально как никогда)
Дмитрий,посмотрите здесь ниже мой комментарий от 14.03.2020, там есть ссылка на статью про амперметр на авр, в ней приведена команда на перевод строки для ЖК дисплея
Спасибо, нашел в статье как переключиться на 2 (Line). А вот 4 битный режим для меня сейчас как никогда актуален.
К сожалению, с 4 битным режимом не могу пока помочь. Если подождете до 7 октября, когда я из отпуска приеду, то тогда могу попробовать помочь
Замечательная статья! Немного практики. Хотелось бы сделать вывод определенных словосочетаний при срабатывании датчика, концевика и т.п. Набор из 10-20 разных сообщений.
С Уважением Владимир
Был в отпуске, поэтому не заметил ваш комментарий. Срабатывание датчика легко проверить с помощью проверки состояния контакта, примеры проверки состояния контактов по нажатию кнопок рассмотрены в этой статье, а вывод целой строки символов на экран ЖК дисплея - в данной статье, функция void send_a_string(char *string_of_characters), в самом конце исходного кода программы