Создание меню с помощью программы FLProg / Блог компании FLProg / Хабр

Меню с помощью библиотеки m2tklib

Как собрать и запрограммировать робота на Arduino(Freeduino, Roboduino, Seeduino …).

Используем Wiring и Processing.


Реклама

Вернуться в Arduino и другие Xduino

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

Меню с помощью библиотеки m2tklib

past0r » 07 апр 2012, 15:13

Доброго времени суток!
Появилась задача: создание меню для Arduino. За основу взял Arduino, экранчик ks0108 ну и "блок" кнопочек сделанных на разнице сопротивления.
Для программной реализации меню решил взять библиотеку m2tklib
Но все застопорилось на том, что данная библиотека заточена на работу с кнопки подключенными к разным входам на МК.
Была некая доработка библиотеки, после чего библиотека стала работать с событиями Arduino. Но как заставить библиотеку вопринимать эти события я не понимаю. помогите пожалуйста разобраться с примером!

За основу возьмем пример идущий в составе самой библиотеки под названием Combo.pde

Код: Выделить всё • Развернуть

Кусок скетча отвечающего за распознование нажатия определенной кнопки:

Код: Выделить всё • Развернуть

Как их связать, подскажите пожалуйста, заранее благодарен!!!

зы Примеров у автора библиотеки я не нашел, кроме этого (m2esarduinoir.c).

past0r
 
Сообщения: 1
Зарегистрирован: 07 апр 2012, 14:50

Вернуться к началу

вот правильный, рабочий скетч. Осторожно! РУССКИЙ ТЕКСТ!!#include <Button.h>#include <TimerOne.h>#include <LCD_1602_RUS.h>LCD_1602_RUS lcd(0x3F, 16, 2);Button encoderA (2,4);Button encoderB (3,4);Button encoderButton (6,40);long pos = 0;int menu;void setup() { lcd.init();lcd.backlight();Timer1.initialize(250);Timer1.attachInterrupt(timerInterrupt, 250);menu = 0;}void loop() {if(menu == 0){ if(pos <= 0){pos = 0;} if(pos >= 1){pos = 1;} lcd.setCursor(2,0); lcd.print(L"Настройки"); lcd.setCursor(2,1); lcd.print(L"Параметры"); if(pos == 0){ lcd.setCursor(0,0); lcd.print(">");} else{ lcd.setCursor(0,0); lcd.print(" ");} if(pos == 1){ lcd.setCursor(0,1); lcd.print(">");} else{ lcd.setCursor(0,1); lcd.print(" ");} if(encoderButton.flagClick == true && pos == 0){ encoderButton.flagClick = false; menu = 1; pos = 0; lcd.clear(); }} if(menu == 1){ if(pos <= 0){pos = 0;} if(pos >= 1){pos = 1;} lcd.setCursor(4,0); lcd.print(L"НАСТРОЙКИ"); lcd.setCursor(2,1); lcd.print(L"ВКЛ"); lcd.setCursor(8,1); lcd.print(L"ВЫКЛ"); if(pos == 0){ lcd.setCursor(0,1); lcd.print(">");} else{ lcd.setCursor(0,1); lcd.print(" ");} if(pos == 1){ lcd.setCursor(6,1); lcd.print(">");} else{ lcd.setCursor(6,1); lcd.print(" ");} if(encoderButton.flagClick == true && pos == 0){ encoderButton.flagClick = false; menu = 0; pos = 0; lcd.clear(); } }} void timerInterrupt() { encoderA.filterAvarage(); // вызов метода фильтрации encoderB.filterAvarage(); // вызов метода фильтрации encoderButton.filterAvarage(); // вызов метода фильтрации// обработка сигналов энкодера if( encoderA.flagClick == true ) { encoderA.flagClick= false; if( encoderB.flagPress == true) { // против часовой стрелки pos—; } else { // по часовой стрелке pos++; } } }Выкладывают и даже не проверяют на работоспособность, а люди классы ставят))я бы 1000 дизлайков поставил, если бы было можно…



Несколько месяцев назад на хабре появилась статья «Реализация многоуровневого меню для Arduino с дисплеем» /. «Но погодите, — подумал я, — Я написал такое меню еще шесть лет назад»!
В далеком 2009 году, я написал первый проект на базе микроконтроллера и дисплея под названием «Автомат управления освещением», для которого потребовалось создать такую оболочку меню, в которую влезет тысяча конфигов, а то и более. Проект был успешно рожден, компилируется и способен работать до сих пор, а оболочка менюОС пошла кочевать из проекта в проект, используя лучшие практики Ущербно-Ориентированного программирования. «Хватит это терпеть» сказал я, и переписал код.
Подкатом вы найдете legacy-код отборного качества, сказ о том, как я его переписал, а также инструкции для тех, кто захочет это использовать.

Требования и возможности менюОС

Для начала определимся с требованиями, которые мы предъявляем к меню:

  1. простота использования, кнопки влево-вправо, вверх-вниз, назад-вперед.;
  2. древовидная структура любой адекватной глубины (до 256);
  3. общее количество пунктов меню, которого хватит всем (10^616);
  4. редактирование настроек;
  5. запуск программ.
  6. простенький встроенный диспетчер задач.

А еще, необходимо чтобы все это как можно меньше весило, было неприхотливо к ресурсам и запускалось на любой платформе(пока есть для AVR, работает с GLCD и текстовым LCD).
Теоретически, с соответствующими драйверами, данное менюОС можно просто взять и подключить к RTOS.

Файловая структура

В качестве примера, будем разбирать следующую структуру меню(слева номер пункта):

Главным догматом менюОС является «Все есть файл». Да будет так.
У каждого файла есть тип, название, родительская папка, прочие параметры
Опишем структурой:

Для каждого файла определим 4 байта в массиве fileData:

  1. type,
  2. parent, он не очень нужен, так как вся информация есть в хлебных крошках, но остался как legacy
  3. mode1, два параметра, специфичных для каждого типа файла
  4. mode2
type == T_FOLDER

Основным файлом является папка. Она и позволяет создать древовидную структуру всего меню.
Самая главная здесь — корневая папка под номером нуль. Что бы не произошло, в итоге мы вернемся в нее.
Параметрами папки являются

В корневой папке 0 лежат файлы 1 и 2, всего 2 штуки.
Опишем ее так:

type == T_DFOLDER

В Папке 3 лежит несколько копий одной и той же программы, однако с разными ключами запуска.
Например, в автомате управления освещением имеется возможность установить до 64 суточных программ, с 16 интервалами в каждой. Если описывать каждый пункт, потребуется 1024 файла. На практике достаточно двух. А хлебные крошки скормим программе в виде параметров.

Нехитрая математика подсказывает нам, что если все 256 файлов будут динамическими папками с максимальным числом копий, общее число пунктов меню в системе составит 256^256 = 3.2 x 10^616. Этого ТОЧНО хватит на любой адекватный и не очень случай.

type == T_APP

Приложение.

Его задача — прописаться в диспетчере задач (встроенном или внешнем), перехватить управление кнопками и править.

type == T_CONF

Конфиг-файл, ради которого и затеян весь сыр-бор. Позволяет устанавливать булево или числовое значение какого-либо параметра. Работает с int16_t.

У конфига есть свой массив configsLimit, где на каждый конфиг приходится три int16_t числа конфигурации:

  1. Cell ID — Стартовый номер ячейки памяти для хранения данных. Все данные занимают два байта.
  2. Minimum — минимальное значение данных
  3. Maximum — максимальное значение данных.

Например, в ячейку 2 можно записать число от -100 до 150, тогда строка примет вид:

type == S_CONF

Интересный(но оставшийся пока только в старом коде) конфиг, работает в связке с T_SFOLDER

type == T_SFOLDER

Особый вид папки вынесен ближе к конфигу, так как является одной из его разновидностей.
Представьте себе, у вас в системе зашита возможность работы по RS-485 по протоколам A,B или C. Помещаем в папку кучку файлов вида S_CONF и выбираем из них необходимый. Более того, когда мы зайдем в папку вновь, курсор подсветит активный вариант.
mode1, mode2 аналогичны для T_FOLDER. Дочерними файлами являются только T_SCONF

Результаты рефакторинга

Я не ставил перед собой задачу пересмотра архитектуры, во многих местах я даже оставил логику работы как есть. Есть весьма забавные костыли.
Основная задача — перебрать систему так, чтобы ее использование в новых проектах было простым. В итоге:

  1. Выделил работу с аппаратной частью как минимум в отдельные функции в отдельном файле. В HWI вошли:
  2. Переписаны модули под классы. Спрятано в private все что только можно, унифицирован внешний вид, Фишка с классами и более-менее унифицированным интерфейсом потом пригодится.
  3. «Добавлен» интерфейс для работы с RTOS. Вернее, штатный диспетчер задач довольно просто заменить на любой другой.
  4. Банально прибрался в коде, сделал его более понятнее, убрал магические числа, улучшил интерфейс. Теперь его не стыдно показать.

Модуль настройки часов мне было лень переписывать под hwi. Все равно его нужно полностью переделывать. Он ужасен.
Как проходил рефакторинг, можно наглядно увидеть в репозитории.

Создание своего проекта

Настройка проекта включает в себя следующие пункты:

Создание файлов

Создадим массивы по ранее рассмотренной структуре

Создадим массив для конфигов:

Настройка кнопок

Я предпочитаю подключать кнопки с замыканием на землю и подтягивающим резистором к питанию, который всегда в наличии в МК.

В файле hw/hwdef.h укажем названия регистров и расположение кнопок:

Настройка дисплея

Сейчас проект тащит за собой библиотеку GLCDv3, что не есть хорошо.

Исторически так сложилось.
Ссылка на google-code — https://code.google.com/p/glcd-arduino

Создание приложения

Рассмотрим пример приложения, использующий базовые функции меню.
menuos/app/sampleapp.cpp

Создадим класс со следующей структурой:

И набросаем основные функции:

Обертки:

Обработчик кнопок:

И функция, которая будет вызываться каждую секунду:

Теперь в menu.cpp пропишем, что по номеру 2 будет вызываться наша программа:

Соберем проект и посмотрим, что у нас получилось:

То же самое для визуалов

Подробная и слегка занудная инструкция по файловой структуре и архитектуре, а также пример работы в видеоматериале.

Ссылки и репозитории

Проект собран в среде программирования Atmel Studio, но настанет тот день и он будет форкнут и под Eclipse. Актуальная версия проекта доступна в любом репозитории(Резервирование).

  1. Репозиторий на GitHub: https://github.com/radiolok/menuosv1
  2. Репозиторий на Bitbucket: https://bitbucket.org/radiolok/menuosv1
  3. GLCDv3: http://habrahabr.ru/post/203646/
  4. openLCD:https://bitbucket.org/bperrybap/openglcd/

Добавить комментарий

Закрыть меню