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

Электроника

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

Задача
  1. Создать специализированную функцию для вывода строки на индикатор в определенную позицию
  2. Оформить все функции в виде библиотеки функций
  3. Использовать эту библиотеку для создания примера вывода информации на индикатор
Алгоритм
Важно
Строка — это набор символов, заканчивающийся байтом со значением 0
1. В функцию передаются указатель на строку и номер строки на индикаторе (row) и номер колонки (column)
2. Внутрь функции вписываем установку курсора на позицию row и column

3. Устраиваем перебор всего массива символов (строки), пока не найдем значение ноль

4. Все значащие байты, исключая ноль, передаем в индикатор с кодом транзакции 1
Работа на компьютере
1. Копируем уже созданный проект (например из другого урока) и переименовываем

2. Запускаем проект и переходим в main.c

3. Добавляем функцию, выводящую строку на экран

4. Используем функцию SetCursorLCD для установки курсора на нужную позицию

5. В цикле перебираем все элементы массива
Применение функции
1. Закомментируем предыдущий код

2. В функции main выводим две строки в 1-ю и 2-ю строчку экрана индикатора

3. Строки передаем как ограниченные двойными кавычками наборы символов
  //инициализация дисплея LCD
  InitLCD(ArrIntLCD);

  /*
  //включим курсор мограющий
  DisplayOnOffLCD(1, 1, 1);

  //вывод символов на экран
  SendByte2LCD('A',1);
  SendByte2LCD('B',1);
  SendByte2LCD('C',1);
   */

 print2LCD("Hello", 0, 5);
 print2LCD("world", 1, 5);

  while (1)
  {

	  if(event_5s_flag==1)
	  {//наступило событие для тяжелой обработки - передачи в UAR

 		  sprintf(str_out, "time event\r\n");  //строка послыки
 		  Size_out = strlen(str_out);       	//размер строки
 		  HAL_UART_Transmit(&huart2, str_out, Size_out, 10); //посылаем ответ в компьютер

 		  event_5s_flag=0; //сбросим флаг - обработали событие
	  }
4. Скомпилируем проект и прошиваем устройство

5. Запускаем устройство. Выводятся соответствующие строки
Работа с библиотекой
1. Создаем файл исходного кода lcd.c

2. Создаем заголовочный файл с тем же именем, но с расширением h

3. В файл lcd.c копируем все функции, которые работают с индикатором

4. Из каждой функции копируем заголовок в lcd.h. Не забываем ставить знак ";"

5. Копируем массив шаблонных кодов инициализации lcd
/*
 * lcd.h
 *
 *  Created on: 13 нояб. 2019 г.
 *      Author: Electronics_5
 */

#ifndef INC_LCD_H_
#define INC_LCD_H_
#include "stm32l4xx_hal.h"

void SendByte2LCD(uint8_t byte, uint8_t data_command);
void InitLCD(uint8_t *ArrIntLCD);
void ClearLCD(void);
void ReturnHomeLCD(void);
void EntryModeSetLCD(uint8_t I_D, uint8_t Shift);
void DisplayOnOffLCD(uint8_t D, uint8_t C, uint8_t B);
void CursorDisplayShiftLCD(uint8_t S_C, uint8_t R_L);
void FunctionSetLCD(uint8_t DL, uint8_t N, uint8_t F);
void SetDDRAMAddressLCD(uint8_t Address);
void SetCursorLCD(uint8_t row, uint8_t column);
void print2LCD(char * str, uint8_t row, uint8_t column);


//массив шаблонных кодов команд для инииализации LCD
uint8_t ArrIntLCD[]={0x33, 0x32, 0x08, 0x28,  0x06, 0x01, 0x0C};
#endif /* INC_LCD_H_ */
6. В блоке main поставим в заголовочный файл lcd.h, чтобы функции были доступны для работы в main

7. Компилируем
Возможные ошибки
1. Неизвестный uint8_t. Это один из типов, определение которых содержится в библиотеке HAL
Исправление: скопируем из main.h подключение заголовочного файла, связанного с микроконтроллером, и поставим его в lcd.h и icd.c

2. DB4_Pin. Это означает, что наша библиотека не видит определения линий для индикатора
Исправление: посмотрим, где определены порты. Они определены в заголовочном файле stm32l476xx.h. Подключаем этот заголовочный файл в нашу библиотеку

3. Требование имен выводов, которые мы сами обозначили в конфигураторе
Исправление: эти файлы находятся в main.h, поэтому подключаем в lcd.c заголовочный файл main.h
Важно
После компиляции lcd.c и lcd.h можно отдавать другим разработчикам. Им нужно будет только поменять имена портов и выводов и, возможно, заголовочных файлов для конкретного микроконтроллера
Алгоритм для вывода счетчика секунд
1. Добавляем событие раз в 1 секунду
//событие "раз в 1 сек"
#define HTIM1_EVENT_1s 1000
volatile int32_t htim1_event_1s_count = HTIM1_EVENT_1s; //счетчик тиков таймера для полуения события раз в 1 с
volatile uint8_t event_1s_flag = 0; //флаг события - изначально событие не установленно

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM1)
	{//прерывание из таймера TIM1 - настроен на обновление раз в 1 мс
2. Добавляем обработку этого события, обработчик прерывания
	//генерируем событие на 1 секунд
		htim1_event_1s_count--; //уменьшаем счетчик для события
		if(htim1_event_1s_count==0)
		{//счетчик достиг конуа - генерим событие
			htim1_event_1s_count = HTIM1_EVENT_1s; //установим счетчик в изначальное состояние
			event_1s_flag = 1; //установим флаг события
		}
3. Настраиваем обработчик в главном цикле программы

4. Добавляем счетчик секунд. Это глобальная переменная длинного типа uint32_t sec_counter. Первоначальное значение после загрузки равно 0

5. В обработчике событий раз в секунду увеличиваем счетчик на 1

6. Ставим ограничение счета, чтобы он обнулялся при достижении максимума

7. Формируем строку вывода счетчика на экран индикатора:
  • формируем массив символов
  • вызываем функцию sprintf и передаем ей строчку
  • в спецификаторе строки укажем, в каком виде хотим вывести строку
  • вызываем функцию из библиотеки
  while (1)
  {

	  if(event_5s_flag==1)
	  {//наступило событие для тяжелой обработки - передачи в UAR

 		  sprintf(str_out, "time event\r\n");  //строка послыки
 		  Size_out = strlen(str_out);       	//размер строки
 		  HAL_UART_Transmit(&huart2, str_out, Size_out, 10); //посылаем ответ в компьютер

 		  event_5s_flag=0; //сбросим флаг - обработали событие
	  }

	  if(event_1s_flag==1)
	  {//наступило событие "раз в 1 сек"
		  sec_counter++ ; //считаем секунды
		  if(sec_counter>9999)
			  sec_counter=0; //превысили передел - счет сначала

		 /*
		  char str_sec[6];
		  sprintf(str_sec, "%04d", sec_counter);
		  print2LCD(str_sec, 1, 1);
		*/

 		  event_1s_flag=0; //сбросим флаг - обработали событие
	  }
Алгоритм для вывода счетчика секунд со сдвигом вправо
1. Добавим новое событие раз в 250 с

2. В вызове обработчика вставляем это событие

3. Добавляем обработку этого события в главный цикл программы

4. Добавляем счетчик номера колонки как глобальную переменную. Движение строки будет осуществляться сменой номера колонки

5. Добавляем условие: если номер колонки выйдет за границы экрана, то необходимо обнулить колонку

6. Формируем строку
if(event_1s_flag==1)
	  {//наступило событие "раз в 1 сек"
		  sec_counter++ ; //считаем секунды
		  if(sec_counter>9999)
			  sec_counter=0; //превысили передел - счет сначала

		 /*
		  char str_sec[6];
		  sprintf(str_sec, "%04d", sec_counter);
		  print2LCD(str_sec, 1, 1);
		*/

 		  event_1s_flag=0; //сбросим флаг - обработали событие
	  }



	  if(event_250ms_flag==1)
	  {//наступило событие "раз в 250 мс"



		  char str_sec[15];
		  sprintf(str_sec, "sec count=%04d", sec_counter);

		  if(column>0)
			  print2LCD(" ", 1, column-1);//запись пробела очистки в колонку перед выводом новой строки

		  print2LCD(str_sec, 1, column);//вывод новой строки

		  column++;//увеличиваем номер колонки
		  if(column>16)
			  column=0; //зацикливаем номер колонки

 		  event_250ms_flag=0; //сбросим флаг - обработали событие
	  }

	  /*
		 if ( HAL_UART_Receive(&huart2, pData, Size, 10) == HAL_OK) // ждем пока не примем из UART Size-количество символов (один) блокирующий режим !!!!!
		 {// приняли байт
			 str_in[idx++]=pData[0]; //копируем вновь принятый символ в новое место входного буфера
			 if(idx==SIZE_INPUT-1)   //если превысили размер входного буфера - то начнем с его начала
				idx=0;
7. Сохраняем, компилируем, прошиваем
Теперь мы научились выводить «бегущую строку» на экран индикатора и составлять свою библиотеку функций. Попробуйте проделать основные моменты самостоятельно.
Интерактивное задание
Тест
Для закрепления полученных знаний
пройдите тест
Стартуем!
Для чего используют функцию SetCursorLCD ?
Дальше
Проверить
Узнать результат
Что означает ошибка «неизвестный uint8_t»?
Дальше
Проверить
Узнать результат
Что означает row в функции?
Дальше
Проверить
Узнать результат
Какое первоначальное значение присваивается глобальной переменной uint32_t sec_counter?
Дальше
Проверить
Узнать результат
К сожалению, вы ответили неправильно
Прочитайте лекцию и посмотрите видео еще раз
Пройти еще раз
Неплохо!
Но можно лучше. Прочитайте лекцию и посмотрите видео еще раз
Пройти еще раз
Отлично!
Вы отлично справились. Теперь можете ознакомиться с другими компетенциями
Пройти еще раз