Урок 37
Часть 1
Модуль LCD 16×2 .МЕНЮ
На прошлом занятии мы проделали огромную работу, научившись отслеживать не только статус нажатия или отжатия кнопок, но и тот момент, когда происходит изменение этого статуса и реализовали это на нашем дисплее с кнопками.
Сегодня мы постараемся, используя опыт прошлых занятий, как-то это всё структурировать и, всё-таки, сочинить какую-нибудь навигацию или меню. А там посмотрим, что получится.
Во-первых создадим новый проект. Создадим мы его так же, как и на прошлых занятиях, назвав его LCDBUTTONMENU и выбрав контроллер Atmega8A.
Из предыдущего проекта LCDBUTTONMODE мы скопируем файлы adc.c, adc.h, button.c, button.h, lcd.c, lcd.h и main.h, а также файл протеуса, переименовав его, соответственно в LCDBUTTONMENU.pdsprj.
Также как и на прошлом занятии, мы удалим полностью всё содержимое файла main.c и вставим в него содержимое одноимённого файла из прошлого урока.
Соберём проект и запустим файл протеуса. Поправим в свойствах путь к файлу с прошивкой
Проверим работоспособность прошивки в протеусе, запустив проект. если всё работает, то переходим к проекту и начинаем писать код.
А прошивать мы теперь контроллер будем опять ни из avrdude напрямую, а через меню Atmel Studio. Для этого мы также, как и раньше мы делали в 6 студии, добавим новый пункт меню и пропишем определенную строку. Чтобы добавить новый пункт меню студии, мы идём в меню в пункт «Сервис -> Новые инструменты»
Попадаем в следующий диалог, в котором мы дадим нашему меню название, через обзор показываем путь к прошивальной программе avrdude, именно к командному файлу, а не к тому который запускает GUI, а в следующей строке прописываем вот такую вот команду (можете скопировать отсюда, но, конечно, без кавычек)
«-c usbasp -p m8 -B12 -U flash:w:$(ProjectDir)Debug\$(TargetName).hex:a»
Теперь у нас появилось новый пункт меню в «сервисе» с нашим названием, через который мы и будем впоследствии прошивать контроллер
В файле button.c добавим глобальную переменную
static unsigned char button_cnt[5]={0};
unsigned int tim_cnt;//счетчик тиков таймера
Добавим также счёт этого счётчика в обработчик прерывания от таймера TIMER0_OVF_vect
Read_Button_State(Button_Select);
tim_cnt++;
if(tim_cnt>=1000) tim_cnt=0;
Создадим и добавим в проект файлы menu.c и menu.h. Подключим файл menu.h в файл main.h
#include «button.h»
#include «menu.h»
Также добавим подключение этого файла в файл menu.c и добавим туда две переменные
#include «menu.h»
//————————————————————
extern unsigned int tim_cnt;//счетчик тиков таймера
static unsigned char i=0;
В этом же файле добавим функцию
static unsigned char i=0;
//——————————————————
void MenuProcess(void)
{
_delay_ms(50);
}
//——————————————————
Добавим прототип этой функции в файле menu.c
#define MENU_H_
//————————————————————
void MenuProcess(void);
//————————————————————
Удалим задержку из бесконечного цикла главной функции main(), остальной код в теле данного цикла пока закомментируем, т.к. пригодится. Тажже вызовем в бесконечном цикле нушу только что написанную функцию
while(1)
{
MenuProcess();
// setpos(0,1);
Удалим объявление переменной в main()
unsigned char i=0;
Массив str1 перенесем и немного исправим в файл menu.c, а в источнике удалим
static unsigned char 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 добавим подключение файла main.h и две структуры для запоминания состояния нашей программы (типа в каком меню мы находимся)
#define MENU_H_
//————————————————————
#include «main.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;
}
_delay_ms(50);
Добавим код в первый кейс
case MENU_STATE_IDLE: //старт программы
menu_state = MENU_STATE_WAIT;
clearlcd();
setpos(0,0);
str_lcd(«MENU»);
setpos(0,1);
str_lcd(«Press SELECT»);
break;
Добавим код в следующий кейс
case MENU_STATE_WAIT: //ждем запуска главного меню
if(button_state[Button_Select]&ST_UNPRESSURE)
{
SetButtonState(Button_Select,ST_LOCKED);
ResetButtonState(Button_Select,ST_UNPRESSURE);
SetButtonState(Button_Select,ST_PRESSURE);
//обработка нажатия кнопки
menu_state = MENU_STATE_MAIN;
}
break;
Также уберём всё лишнее из главной функции. Останется только вот это
int main(void)
{
port_ini(); //инициализируем порты
LCD_ini(); //инициализируем дисплей
ADC_Init(); //инициализируем АЦП
Button_ini(); //инициализируем состояние кнопок
sei(); //включим глобальные прерывания
clearlcd(); //очистим дисплей
while(1)
Соберём проект и проверим в протеусе
Теперь начнём реализовывать работоспособность кнопок.
Для этого создадим ещё одну функцию с кейсами
//——————————————————
void MainMenuProcess(void)
{
while (1)
{
switch (main_menu_state)
{
case MAIN_MENU_STATE_IDLE: //старт главного меню
break;
case MAIN_MENU_STATE_WAIT: //Ожидаем выбора меню
break;
case MAIN_MENU_STATE_MM1_WAIT: //ожидание выбора 1 пункта
break;
case MAIN_MENU_STATE_MM2_WAIT: //ожидание выбора 2 пункта
break;
case MAIN_MENU_STATE_MM3_WAIT: //ожидание выбора 3 пункта
break;
case MAIN_MENU_STATE_MM4_WAIT: //ожидание выбора 4 пункта
break;
case MAIN_MENU_STATE_MM5_WAIT: //ожидание выбора 5 пункта
break;
case MAIN_MENU_STATE_EXIT_WAIT: //ожидание выбора пункта EXIT
break;
case MAIN_MENU_STATE_MM1: //выбор пункта 1
break;
case MAIN_MENU_STATE_MM2: //выбор пункта 2
break;
case MAIN_MENU_STATE_MM3: //выбор пункта 3
break;
case MAIN_MENU_STATE_MM4: //выбор пункта 4
break;
case MAIN_MENU_STATE_MM5: //выбор пункта 5
break;
case MAIN_MENU_STATE_EXIT: //выбор пункта EXIT
break;
}
}
}
//——————————————————
Добавим ей прототип в этом же файле сверху
#include «menu.h»
//————————————————————
void MainMenuProcess(void);
Вызовем данную функцию в предыдущей функции:
case MENU_STATE_MAIN://запуск главного меню
main_menu_state=MAIN_MENU_STATE_IDLE;
MainMenuProcess();
break;
Заполним первый кейс в функции MainMenuProcess
case MAIN_MENU_STATE_IDLE: //старт главного меню
setpos(0,0);
for(i=0;i<3;i++)
{
str_lcd(str1[i]);
}
setpos(0,1);
for(i=0;i<3;i++)
{
str_lcd(str1[i+3]);
}
_delay_ms(50);
ResetButtonState(Button_Select,ST_LOCKED);
main_menu_state = MAIN_MENU_STATE_WAIT;
break;
Тепрь можно собрать код и проверить работоспособность кнопки Select в протеусе.
Всё работает.
Со следующими кейсами мы поработаем в следующей части урока.
Предыдущий урок Программирование МК AVR Следующая часть
Приобрести программатор USBASP USBISP с адаптером можно здесь USBASP USBISP 3.3 с адаптером
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Добавить комментарий