Управление ЖК дисплеем 1602 при помощи сдвигового регистра 74HC595


• О проекте
• Обратная связь
• Полезные ссылки
• Полезные программы
• Друзья сайта


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

E.J.SanYo: Джойстик для денди на stm32
Поковырялся в исх...

Алексей: Джойстик для денди на stm32
А это знает тольк...




           

Библиотека для AVR





AXLIB Генератор





Помощь сайту


   
				

Управление ЖК дисплеем 1602 при помощи сдвигового регистра 74HC595

	
	
	

Дата: 27 Октября 2015. Автор: Алексей

	
	
В библиотеке AXLIB есть набор функций для работы с дисплеем используя этот регистр как шлюз.

Помнится как-то я писал про Управление LCD 1602 по шине I2C. Микросхемка PCF8574 конечно интересная штука, да вот нашел я ей альтернативу. Знакомьтесь, сдвиговый регистр с защелкой 74HC595. Чем он хорош. Первое что меня порадовало так это цена. PCF8574 стоит в районе 90-120 рублей, а 74РС595 около 12 рублей. Почти на порядок дешевле. Многие могут возразить, мол данный регистр односторонний. Да, я согласен. но цель данной статьи именно в использовании в одну сторону. То есть управлять ЖК дисплеем кидая ему команды и данные, без чтения из него какой-либо информации. Проще говоря я заменил PCF8574 на 74HC595. Правда для управления регистром нужно выделить 4 вывода МК, но зато можно использовать любые пины и порты, в отличии от PCF8574 которая привязана жестко к I2C (правда я обычно использую программный i2c и мне все равно какой порт и пин.). Второй камень в огород PCF8574 это скорость. 74HC595 на много быстрее чем шина I2C. Ну что же, довольно лирики, переходим к делу. Регистр:

Регистр 74HC595

И по русски)))

Регистр 74HC595


Q0...Q7 Параллельный выход данных.
GND, VCC Питание микросхемы.
Q7' Выход переноса для каскада регистров.
OE Включение микросхемы. 0-включена, 1-выключена.
MR Сброс данных в регистре.
SH_CP Стробирование.
ST_CP Защелка.
DS Вход данных.

А теперь давайте поговорим об алгоритме работы регистра. Для того чтобы включить и начать работать с микросхемой, нужно прижать к GND вывод ОЕ, ST_CP и SH_CP, а MR подтянуть к питанию. В этом случае микросхема готова получать данные в регистр. Для ввода данных, байт необходимо подавать старшим битом вперед на вход DS регистра. Как только на входе DS выставляется первый бит, нужно подтянуть к питанию вход SH_CP, а затем прижать его к GND. Далее выставить на DS следующий бит и снова дернуть SH_CP. И так 8 раз пока весь байт не запишется в регистр. Для того чтобы наш байт вылез наружу через параллельный порт, необходимо подтянуть к питанию вход ST_CP, а затем снова прижать его к GND. Для того чтобы стереть все данные в регистре нужно выполнить следующие действия. Прижать вывод MR к GND, тем самым стереть данные в регистре, а для того чтобы стереть данные на выходном порту, необходимо не отпуская MR подтянуть к плюсу вывод ST_CP, а потом оба вывода отпустить, MR к плюсу, а ST_CP к GND. Таким образом стираются все данные в регистре. Если дергать просто вывод MR, то стираться данные будут только в самом регистре, а на параллельном порту будут висеть старые данные. Вот как-то так. А теперь подключаем ЖК дисплей к регистру вот по такой схеме.

Схема включения МК+ЖК+регистр

По крупнее

А теперь программа.

#define REGISTR_RESET	0	// Разряд сброса регистра
#define REGISTR_CLK		1	// Разряд стробирования
#define REGISTR_SHIFT	2	// Разряд защелки
#define REGISTR_DATA		3	// Разряд данных

#define REGISTR_PORT	PORTD
#define REGISTR_DDR	DDRD

Здесь мы определились с ножками МК.

// Инициализация регистра
void reg_74hc595_init(void)
{
REGISTR_DDR |= (1 << REGISTR_RESET) | (1 << REGISTR_CLK) | (1 << REGISTR_SHIFT)
| (1 << REGISTR_DATA); 
// Настройка разрядов порта на вывод
REGISTR_PORT &= ~(1 << REGISTR_CLK);
REGISTR_PORT &= ~(1 << REGISTR_SHIFT);
REGISTR_PORT |= (1 << REGISTR_RESET);
}

Данная функция настраивает ножки МК на выход, а затем подтягивает ножку сброса к 1, а защелку и строб к 0.

// Функция сброса регистра
void reg_74hc595_reset(void)
{
	REGISTR_PORT &= ~(1 << REGISTR_RESET);
	REGISTR_PORT |= (1 << REGISTR_SHIFT);
	REGISTR_PORT &= ~(1 << REGISTR_SHIFT);
	REGISTR_PORT |= (1 << REGISTR_RESET);
}

Данная функция стирает все данные в регистре. Алгоритм я уже описывал выше, а это его реализация в коде.

// Вункция вывода байта через регистр
void reg_74hc595_byte(char data)
{	
	for(char i=0; i<8; i++)
	{
		if((data << i) & 0x80) // Выставляем по очереди, начиная со старшего, разряды
		{
			REGISTR_PORT |= (1 << REGISTR_DATA);	// Если 1
		}
		else
		{
			REGISTR_PORT &= ~(1 << REGISTR_DATA);	// Если 0
		}
		REGISTR_PORT |= (1 << REGISTR_CLK);	// Стробирование
		REGISTR_PORT &= ~(1 << REGISTR_CLK);
	}
	REGISTR_PORT |= (1 << REGISTR_SHIFT);	// Защелка
	REGISTR_PORT &= ~(1 << REGISTR_SHIFT);
}

А вот эта функция по интереснее. Здесь мы получаем требуемый байт для вывода через регистр, затем загоняем его в цикл с 8 итерациями. В данном цикле мы сначала сдвигаем данные влево на количество равное индексу цикла, затем логичеки умножаем на 0x80 и если получившееся значение не равно нулю, то выставляем на линию DS единицу. В противном случае ноль. После дергаем ножку стробирования. После того как закончится цикл и наш байт запишется в регистр, мы дергаем ножку защелки, тем самым выводим данные наружу. В принципе можно пользоваться данными функциями и для любых других целей, например зажигать светодиоды или управлять светодиодным индикатором. Но мы возвращаемся к нашей задаче.
Программа для вывода данных на ЖК.

#define LCD_RS	0
#define LCD_E	1

// Команды
#define LCD_E_0(data)		(data &= ~(1 << LCD_E))	// Е в ноль
#define LCD_E_1(data)		(data |= (1 << LCD_E))		// Е в единицу
#define LCD_COM(data)	(data &= ~(1 << LCD_RS))	// Запись команды 
#define LCD_DATA(data)	(data |= (1 << LCD_RS))	// Запись данных


Тут для удобства обзовем выводы строба и выбора команда/дата и пропишем четыре макроса для выставления нужных состояний этих выводов.

// Передача команды дисплею
void lcd1602_com(char com)
{
	LCD_COM(com);					// Запись команды
	reg_74hc595_byte(LCD_E_1(com));	// Выставить Е
	reg_74hc595_byte(LCD_E_0(com));	// Сбросить Е
	_delay_ms(2);						// После команды пауза
}

Данная функция передает команду дисплею.

// Инициализация дисплея
void lcd1602_init(char lcd)
{
	switch (lcd)
	{
		case 0: lcd = 0xC0; break;
		case 1: lcd = 0xD0; break;
		case 2: lcd = 0xE0; break;
		case 3: lcd = 0xF0; break;
	}
	
	_delay_ms(20);			// После включения питания подождать 20 мс
	
	lcd1602_com(0x30);		// Переход в 4-х битный режим
	_delay_us(40);
	lcd1602_com(0x30);		// Переход в 4-х битный режим
	_delay_us(40);
	lcd1602_com(0x30);		// Переход в 4-х битный режим
	_delay_us(40);
	lcd1602_com(0x20);		// Переход в 4-х битный режим
	_delay_us(40);
	lcd1602_com(0x20);		// Установка параметров
	lcd1602_com(0x80);		// Установка параметров
	lcd1602_com(0x00);		// Выключаем дисплей
	lcd1602_com(0x80);		// Выключаем дисплей
	lcd1602_com(0x00);		// Очищаем дисплей
	lcd1602_com(0x10);		// Очищаем дисплей
	lcd1602_com(0x00);		// Устанавливаем режим ввода данных
	lcd1602_com(0x60);		// Устанавливаем режим ввода данных
	lcd1602_com(0x00);		// Включаем дисплей с выбранным курсором
	lcd1602_com(lcd);		// Включаем дисплей с выбранным курсором
}

Данная функция инициализирует дисплей. Собственно она ничего интересного не делает, а лишь передает команду, за командой для переводя дисплея в 4 битный режим. Так же учитывает все временные интервалы. В общем это полная копия алгоритма из документации на дисплей. Одно исключение составляет последняя команда. Она принимает значение переданной функции для определения как будет выглядеть курсор.

// Функция передачи байта дисплею
void lcd1602_char_out(char data)
{
	char temp = 0;

	temp = (data & 0xF0);				// Передача старших 4 бит
	LCD_DATA(temp);					// Передача данных
	reg_74hc595_byte(LCD_E_1(temp));	// Выставить Е
	reg_74hc595_byte(LCD_E_0(temp));	// Сбросить Е
	
	temp = (data << 4);				// Передача младших 4 бит
	LCD_DATA(temp);						// Передача данных
	reg_74hc595_byte(LCD_E_1(temp));	// Выставить Е
	reg_74hc595_byte(LCD_E_0(temp));	// Сбросить Е
	
	_delay_ms(2);						// После командная пауза
}

Эта функция передает байт ЖК дисплею по 4-х битовому закону. Нюансы. Во первых здесь необходимо создать временную переменную, так как мы будем постоянно записывать бит строба с учетом того что для внесения изменений в регистре, необходимо переписывать весь байт. Следующим делом мы записываем во временную переменную передаваемый байт и логически умножаем его на 0xF0, тем самым избавляемся от младших 4-х бит. Затем пихаем его в регистр меняя лишь бит строба. Далее снова записываем во временную переменную передаваемый байт, но теперь уже не умножая,а двигая влево на 4 разряда. Это нужно чтобы мы передали младшие 4 разряда.

// Функция передачи строки
void lcd1602_str_out(char *str)
{
	while((*str) != '\0')
	{
		lcd1602_char_out(*str);
		str++;
        }
}

Данная функция всего навсего выводит строку на ЖК дисплей. А теперь что в основной функции main().

int main(void)
{
	
	reg_74hc595_init();
	
	lcd1602_init(0);
	lcd1602_str_out("WWW.AVRKI.RU");

	
    while(1)
    {

    }
}

А вот и все))) Инициализируем регистр и ЖК дисплей, а затем выводим строку.

Вывод строки на ЖК дисплей.

Архив с проектом.

В библиотеке AXLIB есть набор функций для работы с дисплеем используя этот регистр как шлюз.

Небольшое кино на данную тему.

JW Player goes here



Игорь    20.04.16 17:13

Наверное надо подключать по SPI, не будет никакой ногодрыг забирать ресурсы процессора, ну и, у SPI скорость может достигать половины тактовой процессора.

Алексей    20.04.16 18:09

А если нужен SPI. Универсальность достигается как раз не привязанностью к ногам. Плюс ногодрыг ресурсы не забирает. Это из темы, что легче, толкать тележку или тянуть за собой.

Игорь    21.04.16 16:04

Возможно Вы правы.Тут https://habrahabr.ru/post/274895/ несколько иной способ реализации и возникает вопрос возможна ли работа в 8 бит режиме.

Алексей    21.04.16 16:51

Можно, но нужно два регистра. Один для управления, а второй для шины данных.

Игорь    21.04.16 17:34

В main_init.h // 74HC595 | LCD // ------------------ // | Q2 | RS | // ------------------ // | Q3 | E | // ------------------ а работает Q0 Q1

Алексей    21.04.16 18:34

У меня все работает. Фото 1 Фото 2

Игорь    22.04.16 10:09

У меня заработало как в статье A0 и A1.

Алексей    22.04.16 10:18

Странно. Но в любом случае скоро выходит генератор кода и там вообще не нужно будет заморачиваться с файлами и настройками.

Игорь    22.04.16 10:21

Если не использовать SPI то может быть использовать другую схему подключения например как эта kazus.ru/articles/470.html. Как думаете какие у нее недостатки. И возможно ли Вашу библиотеку доработать до этой схемы.

Алексей    22.04.16 10:45

Здесь важна аппаратная часть регистра. Если с защелкой такое прокатит, то можно. Но опять же, зачем вешать вывод Е напрямую от мк. Или это влияет на работу регистра? Если да, то это опять шило на мыло, так как и там и тут для управления нужно 3 вывода МК.




Чтобы вставить ссылку используйте форму вида[url]http://www.адрес.ru[/url][text]текст ссылки[/text]
Чтобы вставить код используйте форму вида[code]код[/code]

Имя:   





  








Вверх


Рейтинг@Mail.ru Яндекс.Метрика