Интерфейс пользователя. Знакосинтезирующие индикаторы

Электроника

Давайте рассмотрим, как происходит программирование параллельных интерфейсов, и на реальном примере изучим технологии использования индикатора 1602
Глоссарий
Для успешного освоения материала рекомендуем вам изучить следующие понятия:
Пользовательский интерфейс
(интерфейс пользователя, UI) Интерфейс, обеспечивающий передачу информации между пользователем-человеком и программно-аппаратными компонентами компьютерной системы
Электронный индикатор
электронное показывающее устройство, предназначенное для визуального контроля за событиями, процессами и сигналами
Знакосинтезирующий индикатор
индикатор, в котором информация, предназначенная для зрительного восприятия, отображается с помощью одного или совокупности дискретных элементов. К знакосинтезирующим относятся, например, все сегментные индикаторы, в том числе семисегментные, и матричные индикаторы
Матричный индикатор
разновидность знакосинтезирующего индикатора, в котором элементы индикации сгруппированы по строкам и столбцам. Матричный индикатор предназначен для отображения символов, специальных знаков и графических изображений в различных устройствах
Графический индикатор
наиболее сложный тип индикаторов, позволяющий передавать как символьную информацию, так и рисунки
Видеолекция
Конспект

Знакосинтезирующие индикаторы
Знакосинтезирующие индикаторы 1602 являются наиболее распространенными. Они имеют 16 символов по горизонтали и 2 строчки по вертикали. Обычно у таких индикаторов параллельный интерфейс, и мы будем использовать один из таких индикаторов в четырехпроводной схеме.

В индикатор передаются два вида транзакций:

  1. команды, которые позволяют настраивать индикатор
  2. коды символов, которые отображаются на индикаторе

Задача
  1. Создание функции для различных видов транзакций
  2. Создание функции для инициализации индикатора по шаблонному набору команд
  3. Создание оберток функций для каждой команды из спецификации индикатора
Алгоритм
Реализуем функцию посылки транзакции в четырехпроводном режиме.
Она будет принимать два значения:

  1. byte (само значение, которое передается в индикатор)
  2. data_command (тип транзакции)
Важно
Если data_command не равно 0, то это данные для индикатора, и мы должны сбросить линию RS, в противном случае нужно установить линию RS
//посылка byte в LCD, 4-х проводный режим
//data_command: 0 - команда LCD, 1 - данные LCD
void SendByte2LCD(uint8_t byte, uint8_t data_command)
{
	if(data_command!=0)
	{
		//данные LCD
		HAL_GPIO_WritePin(GPIOA, RS_Pin, GPIO_PIN_SET); //сброс RS
	}
	else
	{
		//команада LCD
		HAL_GPIO_WritePin(GPIOA, RS_Pin, GPIO_PIN_RESET); //установка RS
	}
	//HAL_Delay(1);

	//посылка старшей тетрады byte в старшие линийй данных DB7...DB4
	HAL_GPIO_WritePin(GPIOC, DB7_Pin, (byte & 0x80) !=0 ? GPIO_PIN_SET:GPIO_PIN_RESET); //старший (7) бит byte шлем в  DB7
	HAL_GPIO_WritePin(GPIOC, DB6_Pin, (byte & 0x40) !=0 ? GPIO_PIN_SET:GPIO_PIN_RESET); //6 бит byte шлем в  DB6
	HAL_GPIO_WritePin(GPIOB, DB5_Pin, (byte & 0x20) !=0 ? GPIO_PIN_SET:GPIO_PIN_RESET); //5 бит byte шлем в  DB5
	HAL_GPIO_WritePin(GPIOA, DB4_Pin, (byte & 0x10) !=0 ? GPIO_PIN_SET:GPIO_PIN_RESET); //4 бит byte шлем в  DB4
	//HAL_Delay(1);

	//импульс на линии E - для OLED LCD может быть очень коротким
	HAL_GPIO_WritePin(GPIOA, E_Pin, GPIO_PIN_RESET); //0
	//HAL_Delay(1);
	HAL_GPIO_WritePin(GPIOA, E_Pin, GPIO_PIN_SET); //1
	//HAL_Delay(1);
	HAL_GPIO_WritePin(GPIOA, E_Pin, GPIO_PIN_RESET); //0
	//HAL_Delay(1);

	//посылка младшей тетрады byte в старшие линийй данных DB7...DB4
	HAL_GPIO_WritePin(GPIOC, DB7_Pin, (byte & 0x08) !=0 ? GPIO_PIN_SET:GPIO_PIN_RESET); //3 бит byte шлем в  DB7
	HAL_GPIO_WritePin(GPIOC, DB6_Pin, (byte & 0x04) !=0 ? GPIO_PIN_SET:GPIO_PIN_RESET); //2 бит byte шлем в  DB6
	HAL_GPIO_WritePin(GPIOB, DB5_Pin, (byte & 0x02) !=0 ? GPIO_PIN_SET:GPIO_PIN_RESET); //1 бит byte шлем в  DB5
	HAL_GPIO_WritePin(GPIOA, DB4_Pin, (byte & 0x01) !=0 ? GPIO_PIN_SET:GPIO_PIN_RESET); //младший (0) бит byte шлем в  DB4
	//HAL_Delay(1);

	//импульс на линии E - для OLED LCD может быть очень коротким
	HAL_GPIO_WritePin(GPIOA, E_Pin, GPIO_PIN_RESET); //0
	HAL_Delay(1);
	HAL_GPIO_WritePin(GPIOA, E_Pin, GPIO_PIN_SET); //1
	HAL_Delay(1);
	HAL_GPIO_WritePin(GPIOA, E_Pin, GPIO_PIN_RESET); //0
	//HAL_Delay(1);

}
1. Для инициализации индикатора в штатном режиме формируем массив шаблонных кодов для инициализации LCD OLED
Важно
Перед тем как что-то менять в индикаторе, необходимо его выключить, изменить параметры индикатора и потом снова включить
//массив шаблонных кодов команд для инииализации LCD
uint8_t ArrIntLCD[]={0x33, 0x32, 0x08, 0x28,  0x06, 0x01, 0x0C};


//Инициализация LCD
void InitLCD(uint8_t *ArrIntLCD)
{
	for(uint8_t i=0; i<7; i++) //цикл по всем элментам массива кодов инициализации LCD
	{
		SendByte2LCD(ArrIntLCD[i], 0); //шлем байт в LCDб тип - команда
		HAL_Delay(10); //задержка, т.к. в внутри LCD некоторые команды обрабатываются долго
	}
}
2. После этого сделаем функции обертки для команд, которые есть в спецификации индикатора
//очистка LCD
void ClearLCD(void)
{
	SendByte2LCD(0x01, 0);
}

//возврат курсора "домой"
void ReturnHomeLCD(void)
{
	SendByte2LCD(0x02, 0);
}

//режим сдвига курсора и сдвига отображения при записи символа
//информация о бите I_D: 0 – сдвигать курсор влево, иначе – вправо
//информация о бите Shift: 0 – не сдвигать отображение, иначе – сдвигать
void EntryModeSetLCD(uint8_t I_D, uint8_t Shift)
{
	//добавление информации о битах в команду
	SendByte2LCD(0x04 + (I_D!=0? 0x02:0x00) + (Shift!=0? 0x01:0x00), 0);
}
3. Реализуем включение и выключение LCD и сдвиг курсора
//включение выключение LCD
// информация о бите D: 0 – выключить, иначе – включить
// информация о бите С: 0 – курсор не виден, иначе – курсор виден
// информация о бите B: 0 – курсор не мигает, иначе – курсор мигает
void DisplayOnOffLCD(uint8_t D, uint8_t C, uint8_t B)
{
	//добавление информации о битах в команду
	SendByte2LCD(0x08 + (D!=0? 0x04:0x00) + (C!=0? 0x02:0x00) + (B!=0? 0x01:0x00), 0);
}

// однократный сдвиг курсора и сдвига отображения
// информация о бите S_C: 0 – двигать курсор, иначе – двигать экран
// информация о бите R_L: 0 – двигать влево, иначе – двигать вправо
void CursorDisplayShiftLCD(uint8_t S_C, uint8_t R_L)
{
	//добавление информации о битах в команду
	SendByte2LCD(0x10 + (S_C!=0? 0x08:0x00) + (R_L!=0? 0x04:0x00), 0);
}
4. Установим параметры шины LCD
//установка параметров шины LCD
// информация о бите DL: 0 – 4-х проводный режим, 8-и проводный режим
// информация о бите N: 0 – 1 строка, иначе – 2 строки
// информация о бите F: 0 – шрифт 5x8, иначе – шрифт 5x11
void FunctionSetLCD(uint8_t DL, uint8_t N, uint8_t F)
{
	//добавление информации о битах в команду
	SendByte2LCD(0x20 + (DL!=0? 0x10:0x00) + (N!=0? 0x08:0x00) + (F!=0? 0x04:0x00), 0);
}
5. Подключим установку адреса, в который будут записываться данные LCD, и установим курсор для выхода на LCD
//установка адреса, в который будем записывать данные LCD
// Address – номер адреса 7 бит
void SetDDRAMAddressLCD(uint8_t Address)
{
	//добавление информации о битах в команду с ограничением адреса в 7 бит
	SendByte2LCD(0x80 + (Address & 0x7F), 0);
}

// установка курсора для вывода на LCD
// row – номер строки 0…1
// column – номер колонки 0…15
void SetCursorLCD(uint8_t row, uint8_t column)
{
	uint8_t Address = 0; 	//инициализация адреса записи данных

	if(row==0)
		Address = 0; 		//первая строка начинается с этого адреса
	if(row==1)
		Address = 0x40; 	//вторая строка начинается с этого адреса

	Address+= (column & 0x0F); //добавим в адрес номер столбца с его ограничением его значения

	// установим адрес записи данных
	SetDDRAMAddressLCD(Address);
}
Важно
SetCursorLCD — некая обертка, которая позволяет сдвигать курсор в желаемую позицию
Работа на компьютере
1. Копируем проект предыдущей задачи, меняем имя и запускаем

2. В проекте открываем конфигурацию и проверяем все порты

3. Открываем main.c и добавляем код

  • создаем функцию посылки транзакций
  • устанавливаем четыре порта
  • формируем короткий импульс единички. Сперва его сбрасываем, потом устанавливаем и снова сбрасываем
  • аналогично устанавливаем значение для младшей тетрады byte. Меняем битовые маски для контроля
4. Формируем массив шаблонных кодов для инициализации
5. Создаем функцию, которая перебирает все эти значения и высылает их транзакциями в индикатор
Важно
После каждой транзакции делаем задержку 10 мс, так как некоторые команды могут выполняться очень долго
6. Для каждой команды согласно спецификации создаем отдельный вызов
Важно
Установка адреса — это запись определенной позиции в памяти, для того чтобы мы могли выводить позицию на индикаторе
7. Вызываем инициализацию дисплея, например, вызов установки моргающего курсора

8. Делаем запись трех значений, например, ABC
9. Компилируем
Тестирование
С начальной позиции выводятся символы ABC, и устанавливается моргающий курсор для текущей позиции.
Важно
Если индикатор показывает неверную информацию, то прежде всего попробуйте отключить его от компьютера и подключить заново. Иногда индикатору требуется аппаратный сброс
Мы рассмотрели знакосинтезирующий индикатор типа 1602 и написали для него функции посылки транзакций и функции обертки для настройки. Предлагаем проверить, как хорошо вы запомнили материал.
Интерактивное задание
Тест
Для закрепления полученных знаний пройдите тест
Стартуем!
Какие транзакции передаются в знакосинтезирующий индикатор 16.02?
Дальше
Проверить
Узнать результат
Что означает data_command в функции посылки транзакции в четырехпроводном режиме?
Дальше
Проверить
Узнать результат
Для чего необходимо сформировать массив шаблонных кодов для инициализации LCD OLED?
Дальше
Проверить
Узнать результат
Почему после каждой транзакции нужно делать задержку 10 мс?
Дальше
Проверить
Узнать результат
Что такое установка адреса?
Дальше
Проверить
Узнать результат
К сожалению, вы ответили неправильно
Прочитайте лекцию и посмотрите видео еще раз
Пройти еще раз
Неплохо!
Но можно лучше. Прочитайте лекцию и посмотрите видео еще раз
Пройти еще раз
Отлично!
Вы отлично справились. Теперь можете ознакомиться с другими компетенциями
Пройти еще раз