Вывод символов и строк на LCD дисплей 1602A, с управляющим контроллером KS0066U.

Вывод символов и строк на LCD дисплей 1602A, с управляющим контроллером KS0066U.

В прошлой статье мы рассмотрели как произвести инициализацию LCD дисплея по 4-битной шине, но вместо проверки флага занятости, мы использовали задержку. Давайте с его реализации и начнём.
Вывод символов и строк на LCD дисплей 1602A, с управляющим контроллером KS0066U.


Для проверки флага занятости надо выполнить следующие действия:
  • порт данных на вход с подтяжкой
  • RS = 0
  • R/W = 1
  • поднимаем строб E=1
  • задержка
  • читаем старшую тетраду и фиксируем чему равен 7-й бит
  • опускаем строб E=0
  • задержка
  • поднимаем строб E=1
  • задержка, младшую тетраду читать не будем
  • опускаем строб E=0
  • если 7-й бит равен единице(контроллер занят), то повторяем операцию снова, если равен нулю — то выставляем порт данных на выход и выходим

Давайте оформим это в виде кода.


uint8_t Busy_Flag = 0;

void Check_Busy(void)
{
	//шина данных - вход с подтяжкой
	LCD_DDR &= ~DATA_BUS;
	LCD_PORT |= DATA_BUS;
	
	//будем читать из lcd
	LCD_PORT |= (1<<RW);
	LCD_PORT &= ~(1<<RS);
	
	do
	{
                //поднимаем строб
		LCD_PORT |= (1<<E);
		_delay_us(2);
                //фиксируем чему равен 7-й бит 
		Busy_Flag = (LCD_PIN & 0X80);
                //опускаем строб
		LCD_PORT  &= ~(1<<E);
		
		_delay_us(1);
		
		LCD_PORT |= (1<<E);
		_delay_us(2);
		LCD_PORT  &= ~(1<<E);
	}
	while (Busy_Flag);
	//шина данных - выход
	LCD_DDR |= DATA_BUS;
	//переводим LCD в режим записи
	LCD_PORT &= ~(1<<RW);

}


Флаг занятости надо опрашивать перед началом любой операции, на этом по флагу занятости всё.
 
Последовательность действий для отправки команд/данных, была описана в прошлой статье и отличается лишь битом RS, для отправки команд RS=0, для отправки данных RS=1, поэтому вынесем общую часть в отдельную функцию.

void Common_Write_Func(uint8_t data)
{
       //переменная для хранения старшей тетрады
	uint8_t temp = (data & 0XF0);
	
        //будем писать
	LCD_PORT &= ~(1<<RW);
        //шина данных на выход
	LCD_DDR |= DATA_BUS;
	
	//затираем прошлую отправку нулями
	LCD_PORT &= ~DATA_BUS;
        //выставляем старшую тетраду в шину
	LCD_PORT |= temp ;
	Strob();
	
	//затираем прошлую отправку нулями
	LCD_PORT &= ~DATA_BUS;
        //выставляем старшую тетраду в шину
	LCD_PORT |= (data << 4);
	Strob();	
}


Тогда отправка команд будет выглядеть следующим образом

void Write_Command(uint8_t data)
{
	Check_Busy();
	LCD_PORT &= ~(1<<RS);
	Common_Write_Func(data);
}

А отправка данных

void Write_Data(uint8_t data)
{
	Check_Busy();
	LCD_PORT |= (1<<RS);
	Common_Write_Func(data);
}

 
В документации на контроллер есть таблица команд, которая позволяет с ним работать
Вывод символов и строк на LCD дисплей 1602A, с управляющим контроллером KS0066U.

Пользуясь этой таблицей, давайте разберёмся как вывести символ на экран.

Для вывода символа на LCD дисплей надо:
  • указать его позицию на экране
  • записать в эту позицию код символа

 
Указать позицию на экране можно с помощью команды, изображённой ниже.
Вывод символов и строк на LCD дисплей 1602A, с управляющим контроллером KS0066U.

Битами AC0 – AC6 кодируется адрес позиции на экране.
 
А записать данные в эту позицию можно с помощью следующей инструкции.
Вывод символов и строк на LCD дисплей 1602A, с управляющим контроллером KS0066U.

Битами D0 – D7 кодируется адрес символа из таблицы
 
Вывод символов и строк на LCD дисплей 1602A, с управляющим контроллером KS0066U.

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

void Draw_String(const char *str)
{
	uint8_t data = 0;
	while (*str)
	{
		data = *str++;
		Write_Data(data);
	}
}

Как известно строка в си оканчивается экранированным нулём('\0'), экранировка означает, что в память запишется непосредственно сам символ, а не его кодировка.
Ниже видно как в памяти хранятся следующие строки.

        Draw_String("hubstub");
	Draw_String(".ru");

Вывод символов и строк на LCD дисплей 1602A, с управляющим контроллером KS0066U.

Функция посимвольно выводит строку на дисплей, пока не встретит его.

А теперь выведем на дисплей название сайта.

#define F_CPU 8000000UL

#define LCD_PORT PORTA
#define LCD_DDR DDRA
#define LCD_PIN PINA

#define DATA_BUS 0XF0

#define RS 0
#define RW 1
#define E  2


#include <avr/io.h>
#include <avr/delay.h>

uint8_t Busy_Flag = 0;

void Check_Busy(void)
{
	//шина данных - вход с подтяжкой
	LCD_DDR &= ~DATA_BUS;
	LCD_PORT |= DATA_BUS;
	
	//будем читать из lcd
	LCD_PORT |= (1<<RW);
	//команды
	LCD_PORT &= ~(1<<RS);
	
	do
	{
		LCD_PORT |= (1<<E);
		_delay_us(2);
		Busy_Flag = (LCD_PIN & 0X80);
		LCD_PORT  &= ~(1<<E);
		
		_delay_us(1);
		
		LCD_PORT |= (1<<E);
		_delay_us(2);
		LCD_PORT  &= ~(1<<E);
	}
	while (Busy_Flag);
	//шина данных - выход
	LCD_DDR |= DATA_BUS;
	//переводим LCD в режим записи
	LCD_PORT &= ~(1<<RW);
	

}

void Strob(void)
{
	LCD_PORT |= (1<<E);
	_delay_us(2);
	LCD_PORT &= ~(1<<E);
}

void Common_Write_Func(uint8_t data)
{
	uint8_t temp = (data & 0XF0);
	
	LCD_PORT &= ~(1<<RW);
	LCD_DDR |= DATA_BUS;
	
	//затираем прошлую отправку нулями
	LCD_PORT &= ~DATA_BUS;
	LCD_PORT |= temp ;
	Strob();
	
	//затираем прошлую отправку нулями
	LCD_PORT &= ~DATA_BUS;
	LCD_PORT |= (data << 4);
	Strob();	
}

void Write_Command(uint8_t data)
{
	
	Check_Busy();
	LCD_PORT &= ~(1<<RS);
	Common_Write_Func(data);
}

void Write_Data(uint8_t data)
{
	Check_Busy();
	LCD_PORT |= (1<<RS);
	Common_Write_Func(data);
}

void Write_Init_Command(uint8_t data)
{
	
	//ножки по которым передаются команды/данные  на выход
	LCD_DDR |= DATA_BUS;
	//будем слать команду
	LCD_PORT &= ~(1<<RS);
	LCD_PORT &= ~(1<<RW);
		
	//затираем прошлую отправку нулями
	LCD_PORT &= ~DATA_BUS;
	//выводим команду в шину
	LCD_PORT |= data;
	Strob();
	_delay_us(100);
		
}

void LCD_Init(void)
{
	_delay_ms(50);
	
	Write_Init_Command(0x20);
	Write_Init_Command(0x20);
	//включаем дисплей, в режиме 2-х линий
	Write_Init_Command(0xC0);
	
	_delay_us(50);
	
	Write_Init_Command(0x00);
	//включаем отображение курсора
	Write_Init_Command(0xE0);
	
	_delay_us(50);
	
	Write_Init_Command(0x00);
	//очищаем дисплей
	Write_Init_Command(0x10);
	
	_delay_ms(2);
	
	Write_Init_Command(0x00);
	//значение DDRAM увеличивается, без сдвига экрана
	Write_Init_Command(0x60);
		
}

__inline void LCD_Clear(void)
{
	Write_Command(0X01);

}

void Draw_String(const char *str)
{
	uint8_t data = 0;
	while (*str)
	{
		data = *str++;
		Write_Data(data);
	}
}


__inline void Set_Ddram_Address(uint8_t address)
{
	Write_Command(address | 0x80);
}


int main(void)
{
	
	LCD_DDR = 0XFF;
	LCD_Init();

	Set_Ddram_Address(0X43);
	Draw_String("hubstub");
	Draw_String(".ru");

    while(1)
    {
        
    }
}


Вывод символов и строк на LCD дисплей 1602A, с управляющим контроллером KS0066U.


А на этом всё, в следующей статье мы попробуем нарисовать свой символ на дисплее.
комментарии
8