Урок 63
Часть 1
Модуль LCD 16×2. МЕНЮ
На последнем занятии по модулю LCD с кнопками мы проделали огромную работу, научившись отслеживать не только статус нажатия или отжатия кнопок, но и тот момент, когда происходит изменение этого статуса и реализовали это на нашем дисплее с кнопками.
Сегодня мы постараемся, используя опыт прошлых занятий, как-то это всё структурировать и, всё-таки, сочинить какую-нибудь навигацию или меню. А там посмотрим, что получится.
Проект был сделан из предыдущего проекта LCDBUTTONMODE и назван LCDBUTTONMENU.
Запустим новый проект в Cube MX и, ничего в нём не меняя и не трогая, сгенерируем проект для Keil и откроем его.
Настроим программатор на авторезет, подключим файлы button.c и lcd.c к дереву проекта и соберём проект.
Отключим оптимизацию и попытаемся, ещё раз собрав проект, прошить контроллер. чтобы убедиться. что всё работает
Добавим ещё одну глобальную переменную в файл main.c
volatile uint16_t adctim_cnt=0;
volatile uint16_t menutim_cnt=0;
Она будет нам нужна для мигания пункта меню.
Добавим также код в обработчик ADC
if(adctim_cnt>1000)
{
adctim_cnt=0;
if(menutim_cnt>400)
{
menutim_cnt=0;
HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_12);
}
menutim_cnt++;
TIM_Callback();
}
Пока помигаем зелёным светодиодом, чтобы оценить скорость мигания. Учитываем то, что пункты будут мигать вдвое быстрее.
Соберём проект, прошьём контроллер и посмотрим.
Теперь создадим и добавим в проект файлы menu.c и menu.h самым обычным образом. Подключим файл menu.h в файл main.h
#include «button.h»
#include «menu.h»
Также подключим файл menu.h в файл menu.c, а также добавим там пару переменных
#include «menu.h»
//———————————————-
extern uint16_t menutim_cnt;//счетчик для мигания пунктов
static uint8_t i=0;
Содержимое файла menu.h
#ifndef MENU_H_
#define MENU_H_
//————————————————
#include «stm32f4xx_hal.h»
#include «stdint.h»
//————————————————
#endif /* MENU_H_ */
Подключим в него также библиотеки дисплея и кнопок
#include «stdint.h»
#include «lcd.h»
#include «button.h»
Добавим функцию в файле menu.c
static uint8_t i=0;
//———————————————-
void MenuProcess(void)
{
HAL_Delay(50);
}
Добавим для этой функции прототип в заголовочном файле
#include «stdint.h»
//————————————————
void MenuProcess(void);
//————————————————
Удалим задержку из бесконечного цикла главной функции main(), остальной код в теле данного цикла пока закомментируем, т.к. пригодится. Тажже вызовем в бесконечном цикле нашу только что написанную функцию
while (1)
{
MenuProcess();
// adc_value=ADC_Data;//занесём результат преобразований в переменную
Удалим объявление переменной в main()
uint8_t i=0;
Массив str1 перенесем и немного исправим в файл menu.c, а в источнике удалим
static uint8_t i=0;
//———————————————-
char str1[6][11]=
{
«MM_1 \0»,
«MM_2 \0»,
«MM_3 \0»,
«MM_4 \0»,
«MM_5 \0»,
«EXIT \0»
};
//———————————————-
В файле menu.h добавим две структуры для запоминания состояния нашей программы (типа в каком меню мы находимся)
#include «stdint.h»
//————————————————
typedef enum {
MENU_STATE_IDLE = 0,
MENU_STATE_WAIT,
MENU_STATE_MAIN,
}MENU_StateTypeDef;
typedef enum {
MAIN_MENU_STATE_IDLE = 0,
MAIN_MENU_STATE_WAIT,
MAIN_MENU_STATE_MM1,
MAIN_MENU_STATE_MM2,
MAIN_MENU_STATE_MM3,
MAIN_MENU_STATE_MM4,
MAIN_MENU_STATE_MM5,
MAIN_MENU_STATE_EXIT,
MAIN_MENU_STATE_MM1_WAIT,
MAIN_MENU_STATE_MM2_WAIT,
MAIN_MENU_STATE_MM3_WAIT,
MAIN_MENU_STATE_MM4_WAIT,
MAIN_MENU_STATE_MM5_WAIT,
MAIN_MENU_STATE_EXIT_WAIT
}MAIN_MENU_StateTypeDef;
//————————————————
Добавим ещё две инициализированных переменных в файл menu.c
«EXIT \0»
};
MENU_StateTypeDef menu_state = MENU_STATE_IDLE;
MAIN_MENU_StateTypeDef main_menu_state = MAIN_MENU_STATE_IDLE;
В файле menu.c в функцию MenuProcess добавим следующий код, отслеживающий текущее состояние программы
void MenuProcess(void)
{
switch (menu_state)
{
case MENU_STATE_IDLE: //старт программы
break;
case MENU_STATE_WAIT: //ждем запуска главного меню
break;
case MENU_STATE_MAIN: //запуск главного меню
break;
}
HAL_Delay(50);
Добавим код в первый кейс
case MENU_STATE_IDLE: //старт программы
menu_state = MENU_STATE_WAIT;
LCD_Clear();
LCD_SetPos(0,0);//спозиционируем курсор
LCD_String(«MENU»);
LCD_SetPos(0,1);
LCD_String(«Press SELECT»);
break;
Можно собрать проект, прошить его в МК и проверить отображение данных строк.
В следующей части нашего урока мы продолжим работу со следующими кейсами данной функции, а также начнём писать ещё одну очень интересную функцию, которая будет управлять всеми пунктами меню.
Предыдущий урок Программирование МК STM32 Следующая часть
Отладочную плату можно приобрести здесь STM32F4-DISCOVERY
Дисплей с кнопками можно приобрести здесь Дисплей LCD 16×2 с кнопками
Смотреть ВИДЕОУРОК (нажмите на картинку)
Добрый день, Владимир! Если не трудно, то неплохо бы промежуточные варианты прошивки выкладывать! Говорю потому что там порой бывает что часть кода теряется и для возврата в промежуточный код много времени тратится и не всегда удачно!
Добрый день! Мне обычный код не так просто выкладывать, а Вы хотите промежуточный. Я вообще всегда был против всякого выкладывания кода. Люди начинают надеяться на готовый код, из-за этого материал не усваивается. Думаю, прекращать надо с выкладыванием кода, тогда вопросы все отпадут.
Это не претензия — это пожелание! Мне трудно с Вами спорить! Вы в этом ПРОФИ! Вам и так спасибо что тратите на нас время! Более того Вы в данном случае исходите безусловно из того чтобы не донимали вопросами по коду. Так все равно будут донимать по другим вопросам. Я же со своей точки зрения, поскольку в чем то я был все же в этой жизни ПРОФИ, и мне именно то что у ВАС есть коды нравиться не менее, чем сами уроки. Поскольку масса примеров есть, а кода нет и списывать его с экрана уйма времени, а сходу запомнить идею в моем возрасте уже проблема. Это для тех кому до 30. А для разных категорий учеников — разные методы и подходы, не хочется повторять банальности.
Спасибо Вам большое за труд!
Очень не хватает общих слов, которые бы помогли понять в целом принцип работы и создания меню. Какие структуры нужны, в каком количестве? Сколько и каких функций? Как они взаимодействуют друг с другом? Это всё приходится выуживать самостоятельно, хотя это как мне кажется самая ценная информация конкретно для этого урока.