LCD-дисплеи (Liquid Crystal Displays) используют для отображения состояния или параметров в различных приборах.
Жидкокристаллический дисплей LCD1602 представляет собой 16-выводное устройство, имеющее 8 выводов для передачи данных (D0-D7) и 3 вывода управления (RS, RW, EN). Остальные 5 выводов предназначены для питания и подсветки ЖК-дисплея. Цифры «1602» указывают на формат выводимой (отображаемой) информации: 16x02 символов (рисунок 1).
Выводы управления помогают нам настроить LCD-дисплей в командном режиме или режиме передачи данных. Они также помогают настроить режим чтения или записи, а также время чтения или записи.
LCD-дисплей 16x2 можно использовать в 4-битном или 8-битном режиме в зависимости от технических требований. Чтобы использовать его, нам необходимо отправить определенные команды на LCD-дисплей в командном режиме, и как только ЖК-дисплей будет настроен в соответствии с нашими требованиями, мы сможем отправить необходимые данные в режиме передачи данных.
Для получения дополнительной информации о LCD-дисплее 16x02 и о том, как его использовать, необходимо обратиться к datasheet.
Схема подключения жидкокристаллического дисплея LCD1602 (HD44780) к микроконтроллеру ATmega8 в 8-битном режиме показана на рисунке 2.
Подстрочный резистор R1 предназначен для точной подстройки контрастности дисплея. Резистор R2 предназначен для ограничения тока на аноде подсветки дисплея.
Функция инициализации дисплея:
1. Включить питание на LCD-дисплее
2. Необходимо подождать не менее 15 мс, время инициализации включения питания для LCD1602.
3. Отправить команду 0x38 которая переводит LCD-дисплей в 2-строчный, 8-битный режим и 5x8 точек.
4. Отправить одну из команд включения курсора дисплея (0x0E, 0x0C).
5. Отправить команду 0x06 (сдвиг курсора вправо).
Листинг кода:
void LCD_Init (void) /* LCD Initialize function */
{
LCD_Command_Dir = 0xFF; /* Make LCD command port direction as o/p */
LCD_Data_Dir = 0xFF; /* Make LCD data port direction as o/p */
_delay_ms(20); /* LCD Power ON delay always >15ms */
LCD_Command (0x38); /* Initialization of 16X2 LCD in 8bit mode */
LCD_Command (0x0C); /* Display ON Cursor OFF */
LCD_Command (0x06); /* Auto Increment cursor */
LCD_Command (0x01); /* clear display */
LCD_Command (0x80); /* cursor at home position */
}
Теперь, когда LCD–дисплей инициализирован, он готов принимать данные для отображения.
Функция записи команд (инструкций):
1. Отправим значение команды на порт передачи данных LCD1602.
2. Установим вывод RS на «низкий» уровень, RS = 0 (регистр команд).
3. Установим вывод RW на «низкий» уровень, RW = 0 (операция записи)
4. Подадим импульс от «высокого» до «низкого» на выводе Enable (E) с минимальной задержкой 450 нс.
Когда мы подаем разрешающий импульс, LCD-дисплей фиксирует данные, имеющиеся на выводах D0 – D7, и выполняет их как команду, поскольку RS - это регистр команд.
Листинг кода:
void LCD_Command(unsigned char cmnd)
{
LCD_Data_Port= cmnd;
LCD_Command_Port &= ~(1<<RS); /* RS=0 command reg. */
LCD_Command_Port &= ~(1<<RW); /* RW=0 Write operation */
LCD_Command_Port |= (1<<EN); /* Enable pulse */
_delay_us(1);
LCD_Command_Port &= ~(1<<EN);
_delay_ms(3);
}
Функция записи данных:
1. Отправим команду на порт передачи данных.
2. Установим вывод RS на «высокий» уровень, RS = 1 (регистр данных)
3. Установим вывод RW на «низкий» уровень, RW = 0 (операция записи)
4. Подадим импульс от «высокого» до «низкого» на выводе Enable (E).
Когда мы подаем разрешающий импульс, LCD-дисплей фиксирует имеющиеся данные (на выводах D0-D7) и отображает их на матрице 5x8, поскольку RS - это регистр данных.
Листинг кода:
void LCD_Char (unsigned char char_data) /* LCD data write function */
{
LCD_Data_Port = char_data;
LCD_Command_Port |= (1<<RS); /* RS=1 Data reg. */
LCD_Command_Port &= ~(1<<RW); /* RW=0 write operation */
LCD_Command_Port |= (1<<EN); /* Enable Pulse */
_delay_us(1);
LCD_Command_Port &= ~(1<<EN);
_delay_ms(1);
}
Функция отображения строки:
Эта функция принимает строку (массив символов) и отправляет по одному символу в функцию данных LCD-дисплея до конца строки. Цикл for используется для отправки символа на каждой итерации. Символ NULL указывает на конец строки.
Листинг кода:
void LCD_String (char *str)
{
int i;
for(i=0;str[i]!=0;i++) /* send each char of string till the NULL */
{
LCD_Char (str[i]); /* call LCD data write */
}
}
Примечания:
1. Задержка включения LCD-дисплея. После включения LCD1602 мы не можем немедленно отправлять на него команды, поскольку ему требуется время на инициализацию 15 мс. Поэтому при программировании нам нужно позаботиться о том, чтобы обеспечить достаточную задержку включения питания (> 15 мс), а затем отправлять команды на LCD-дисплей.
2. После проверки команд LCD1602 требуется время (в микросекундах) для их выполнения. Но для команды 0x01 (т.е. очистить отображение) выполнение занимает 1,64 мс. Следовательно, после отправки команды 0x01 необходимо обеспечить достаточную задержку (> 1,63 миллисекунды).
Листинг программы:
#define F_CPU 8000000UL /* Define CPU Frequency e.g. here 8MHz */
#include <avr/io.h> /* Include AVR std. library file */
#include <util/delay.h> /* Include inbuilt defined Delay header file */
#define LCD_Data_Dir DDRB /* Define LCD data port direction */
#define LCD_Command_Dir DDRC /* Define LCD command port direction register */
#define LCD_Data_Port PORTB /* Define LCD data port */
#define LCD_Command_Port PORTC /* Define LCD data port */
#define RS PC0 /* Define Register Select (data/command reg.)pin */
#define RW PC1 /* Define Read/Write signal pin */
#define EN PC2 /* Define Enable signal pin */
void LCD_Command(unsigned char cmnd)
{
LCD_Data_Port= cmnd;
LCD_Command_Port &= ~(1<<RS); /* RS=0 command reg. */
LCD_Command_Port &= ~(1<<RW); /* RW=0 Write operation */
LCD_Command_Port |= (1<<EN); /* Enable pulse */
_delay_us(1);
LCD_Command_Port &= ~(1<<EN);
_delay_ms(3);
}
void LCD_Char (unsigned char char_data) /* LCD data write function */
{
LCD_Data_Port= char_data;
LCD_Command_Port |= (1<<RS); /* RS=1 Data reg. */
LCD_Command_Port &= ~(1<<RW); /* RW=0 write operation */
LCD_Command_Port |= (1<<EN); /* Enable Pulse */
_delay_us(1);
LCD_Command_Port &= ~(1<<EN);
_delay_ms(1);
}
void LCD_Init (void) /* LCD Initialize function */
{
LCD_Command_Dir = 0xFF; /* Make LCD command port direction as o/p */
LCD_Data_Dir = 0xFF; /* Make LCD data port direction as o/p */
_delay_ms(20); /* LCD Power ON delay always >15ms */
LCD_Command (0x38); /* Initialization of 16X2 LCD in 8bit mode */
LCD_Command (0x0C); /* Display ON Cursor OFF */
LCD_Command (0x06); /* Auto Increment cursor */
LCD_Command (0x01); /* Clear display */
LCD_Command (0x80); /* Cursor at home position */
}
void LCD_String (char *str) /* Send string to LCD function */
{
int i;
for(i=0;str[i]!=0;i++) /* Send each char of string till the NULL */
{
LCD_Char (str[i]);
}
}
void LCD_String_xy (char row, char pos, char *str)/* Send string to LCD with xy position */
{
if (row == 0 && pos<16)
LCD_Command((pos & 0x0F)|0x80); /* Command of first row and required position<16 */
else if (row == 1 && pos<16)
LCD_Command((pos & 0x0F)|0xC0); /* Command of first row and required position<16 */
LCD_String(str); /* Call LCD string function */
}
void LCD_Clear()
{
LCD_Command (0x01); /* clear display */
LCD_Command (0x80); /* cursor at home position */
}
int main()
{
LCD_Init(); /* Initialize LCD */
LCD_String("Hello World"); /* write string on 1st line of LCD*/
LCD_Command(0xC0); /* Go to 2nd line*/
LCD_String("8 bit"); /* Write string on 2nd line*/
return 0;
После загрузки прошивки на дисплее LCD1602 мы увидим следующий результат, показанный на рисунке 3.
Хорошим тоном программирования является создание отдельной библиотеки для нашего ЖК-дисплея.
Расшифровка наиболее употребляемых команд, посылаемых от микроконтроллера в дисплей LCD1602 (HD44780) приведена в таблицах 2,3.
Время выполнения команд указано приблизительно. Оно определяется частотой внутреннего RC-генератора LCD-дисплея, которая, в свою очередь, зависит от технологического разброса и температуры нагрева корпуса.
Источник информации:
https://www.electronicwings.com/avr-atmega/lcd16x2-interfacing-with-atmega16-32