Теоретический вопрос, концептуальный. Про структуру программы.

GreenBug
Offline
Зарегистрирован: 25.04.2018

Всем привет. Не судите строго, только начинаю, но хочу делать все правильно.

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

 

Итак: Устройство, две кнопки, исполнительный механизм и индикаторные светодиоды. Есть несколько (четыре) режимов работы, в зависимости от того, в каком режиме сейчас устройство - меняется реакция на кнопки. 

Вот в голове крутится каноническое "Разбиваем программу на логические блоки. Сначала опрос кнопок и присваивание значений переменным. Потом логика, вычисления. Потом команды исполнительным механизмам."

ОК, пишем первый блок, с программным антидребезгом и присвоением значений переменным prevBtnState btnState и flagBtn

Но поскольку в зависимости от того, в каком режиме находится устройство меняется реакция на действия и состояние - то получается, что надо опрашивать кнопки в каждом режиме? 

Т.е. в первом режиме надо отлавливать короткое и длинное нажатие кнопки 2 - меню и управление. А длинное нажатие или отпускание после короткого таймера кнопки 1 будет переводить устройство во второй и в третий  режимы.

Во втором режиме надо отлавливать факт нажатия любой из кнопок.

В третьем - факт отпускания  кнопки (ну или факт того, что она нажата и ее держат).

 

И у меня получается, что я не могу обойтись без дополнительного опроса кнопок внутри режимов. 

 

Вопрос: допустимо ли такое? Или у меня где-то глобальная ошибка в логике?

 

 

 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Подпишусь

b707
Offline
Зарегистрирован: 26.05.2017

GreenBug - Вам нужно кардинально переосмыслить логику программы. То, что вам поможет, называется "конечные автоматы". Гуглите и читаете для посинения.

Предупреждаю, некоторое время потребуется, чтобы въехать в идею. Но как втянетесь - дальше будет несложно.

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
//---кнопки-----------------------------
typedef void (*pDo)();
class Cl_btn {
  protected:
    byte pin;
    bool state;
    unsigned long past;
    void set(bool s) {
      state = s;
      past = millis();
      if (s == true) Do();
    }
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init() {
      pinMode(pin, INPUT_PULLUP);
      set(false);
    }
    void run() {
      if (millis() - past >= 100)
        switch (state) {
          case false:
            if (!digitalRead(pin))set(true);
            break;
          case true:
            if (digitalRead(pin))set(false);
            if (millis() - past >= 300)set(false);
            break;
        }
    }
};
Cl_btn    BtnS(/*пин*/2);  //кнопка селект
Cl_btn    BtnU(/*пин*/3);  //кнопка верх
//--------------- меню---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
const byte page0 = 0;
const byte page1 = 10;
const byte page2 = 20;
const byte page3 = 30;
byte page;
unsigned long past;
void goPage(byte p) {
  past = millis();
  page = p;
  switch (page) {
    case page0:
      Serial << "\npage0";
      BtnS.Do = [] {goPage(page1);};
      BtnU.Do = [] {};
      break;
    case page1:
      BtnS.Do = [] {goPage(page2);};
      BtnU.Do = [] {};
      Serial << "\npage1";
      break;
    case page2:
      BtnS.Do = [] {goPage(page3);};
      BtnU.Do = [] {};
      Serial << "\npage2";
      break;
    case page3:
      BtnS.Do = [] {goPage(page0);};
      BtnU.Do = [] {};
      Serial << "\npage3";
      break;
  }
}
void menu_init() {
  Serial.begin(9600);
  goPage(page0);
}
void menu_run() {}
void setup() {
  BtnS.init();
  BtnU.init();
  menu_init();
}

void loop() {
  BtnS.run();
  BtnU.run();
  menu_run();
}

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

рисуй таблицу состояний и переходы между ними

nik182
Offline
Зарегистрирован: 04.05.2015

Не стоит подходить кононически к программе для МК. Изначальная идея МК вообще не подразумевала классического програмирования. Это сейчас, когда памяти стало много, у неофитов возникают иллюзии что можно как в винде програмируя классчески получить программу размером несколько мег для сложения 2+2. Тем не мении до сих пор можно купить МК, для которых нет даже СИ компилятора из за невозможности его реализации в связи со слишком маленьким размером памяти МК. Ну и какое каноническое програмирование для них? В зависимости от конкрентной задачи методы и способы програмирования могут быть разными. Про Вашу задачу уже подсказали какой метод оптимальный. Но он не единственный, можно и классически, но мне кажется что с конечным автоматом будет проще и короче программа.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

nik182, я бы сказал обратное. Новички не знают классическое программирование. Оно что для МК что больших ЭВМ похоже. Не умеют внятно сформулировать ТЗ, а и с развитием технологии надеются на "джина из тырнета". Чему и была причина создания этой темы.

Гриша
Offline
Зарегистрирован: 27.04.2014

GreenBug пишет:

Итак: Устройство, две кнопки, исполнительный механизм и индикаторные светодиоды. Есть несколько (четыре) режимов работы, в зависимости от того, в каком режиме сейчас устройство - меняется реакция на кнопки. 

есть 5 подпрограмм (функций) которые находятся в функции loop. в первой мы получаем состояние кнопок и можем вызывать ее из других функций.

есть некая переменная, которая указывает какую функцию выполнить сейчас, изменяя эту переменную меняем "режимы работы" можно использовать Оператор Switch или  Оператор If и обрабатывать  (реагировать на кнопки) согласно алгоритму в этих функциях. 

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

вариантов масса, частенько выбор пути реализации алгоритма сложнее самой программы... тут только опыт в помощь.  

Гриша
Offline
Зарегистрирован: 27.04.2014

ШУТКА: Первоклассникам было поручено ДЗ написать алгоритм "как попасть к первому уроку в школу",  никто не получил 5. На вопрос родителей почему так? - ответ: никто не написал первым пунктом "проснутся утром"... вот так они и ходят в школу..

Для тех, кто не в теме обучения - первоклассники "занимаются" примитивными алгоритмами и составляют их  как подраздел обучения "логика и мышление". 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

1 косяк ТС - что переключает режимы. 2 косяк ТС куда и в какой форме отправлять результаты . Без знания этих вещей писать программу бесмысленно.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Родное сердце! А какой у тебя бэкграунд? В том смысле, что какой у тебя прошлый опыт программирования?

Варианты:

1. Никакого, я оператор метлы и лопаты. (это шутка, ежели чо);

2. Среднее специальное образование, станочник ЧПУ;

3. Веб, не к ночи будет помянут;

4. 1С, СУБД и прочий шаманизм ;) ;

5. GUI туда же Андроид и игры;

6. Ну и призовое место - системщик!

---------------

В зависимости от этого и советы. для 5 и 6 советы, скорее всего вообще не нужны.

Писать можно в автоматном стиле, с таблицей состояний. Можно - в объектном, если памяти хватает. Кто же, акромя тебя, знает - что тебе понять проще?

==========================

Вот если не умничать, то твоя задача стандартная. События ложатся в очередь, автомат их обрабатывает, вочдог следит за зависаниями. Так 99.9% всех бытовых устройств сделано. Если нужен приоритет событий - то новое событие тонет в очереди до своего уровня приоритета. Так-то, ежели вааще, то есть книжки по программированию... тот же Кнут(эт фамилие такое) пока не устарел! ;)))

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

GreenBug пишет:
И у меня получается, что я не могу обойтись без дополнительного опроса кнопок внутри режимов. 

Вопрос: допустимо ли такое? Или у меня где-то глобальная ошибка в логике?

Ваше последнее предположение соответствует истине.

В Вашей программе должны в цикле один за другим выполняться два блока:

1. Опрашивает кнопки и запоминает их состояние.

2. В зависимости от состояния устройства производит реакцию на кнопки (т.е. на то, что запомнено на 1-м шаге), и, возможно, смену состояния устройства.

И так по кругу.

Клапауций 003
Offline
Зарегистрирован: 20.07.2019

GreenBug пишет:

И у меня получается, что я не могу обойтись без дополнительного опроса кнопок внутри режимов. 

та, да - никогда такого не было, и вот - опять. философ.

код где?

!на моей памяти - это примерно 14-й, который хочет, но не может.

Гриша
Offline
Зарегистрирован: 27.04.2014

Клапауций 003 пишет:

код где?

уважаемый, зачем вы запретили это:

GreenBug пишет:

И у меня получается, что я не могу обойтись без дополнительного опроса кнопок внутри режимов.

Вопрос: допустимо ли такое? Или у меня где-то глобальная ошибка в логике?

от того и нет кода... тут вопрос в алгоритме - которого нет...

Клапауций 003
Offline
Зарегистрирован: 20.07.2019

ок. дабы голословно не глумиться - читай тему с этого #556 конца в начало. там длинные/короткие нажатия, даблклики, удержания, отпускания. кароче - всё, что можно было высосать из одной тактовой кнопки.

по сути вопроса: алгоритм следующий - опрашивается пин кнопки, переменная состояния пина вместе с параметрами фильтра дребезга, кликов, даблкликов, таймеров отпускания-удержания и, уже не помню чего, пересылается в экземляр класса кнопки и там интерпретируется в переменные кликов, удержаний, прочего.

GreenBug
Offline
Зарегистрирован: 25.04.2018

Привет всем, извините, что вчера не смог ответить - дети отвлекли, исправляюсь.
Отвечать буду по порядку.

Код пока в процессе, в его нынешнем состоянии его выкладывать стыдно, но выложу - обещаю.

qwone - за пример кода спасибо, но вопрос был по теории, насколько правильно мое понимание.

Теперь уже ясно, что понимание было в корне неверным. 

Я в итоге пошел по пути, подсказанному  DetSimen, Гришей и wdrakula (ответ 1 - оператор метлы и лопаты :-)): Шаг.1 - нарисована таблица состояний и внятно указано какие события приводят к смене состояния.              Шаг 2. операторами if-else перебираются состояния (режимы работы), в них прописываются и реакция на нажатия и переходы в другое состояние.     Шаг 3. Все действия внутри режима(-ов) загнаны в отдельные функции, и эти функции просто вызываются внутри режима (из режима)

Таким образом все получилось именно по блокам!

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

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

Третий блок - функции работы.

Таким образом ни в блоке 2, ни в блоке 3 не происходит опроса кнопок/датчиков. Т.е. именно сначала опрос, потом обработка результатов опроса, потом собственно выполнение программы. 

СПАСИБО! Мыслить меня в правильном направлении натолкнули - спасибо.

 

P.S. Клапауций 003 - класс титановый велосипед прекрасен, но! В своем первом устройстве я вообще не использовал антидребезг. Потому, что на на старт оно ловило длииинное нажатие, а на остановку - любое.  В нынешнем я хочу все написать сам, не использую сторонних наработок (ну кроме разве что библиотеки сервы :-)) Вчера я уже запутался в обработке антидребезга и логике работы устройства, смешал все и впал в ступор.     А вот далее - буду с удовольствием применять и сторонние библиотеки, и классы, но сначала сам, иначе это не спортивно.

P.S. Код выложу, обещаю. Как только он придет к не столь постыдномцу виду.

 

Гриша
Offline
Зарегистрирован: 27.04.2014

GreenBug пишет:

P.S. Клапауций 003 - класс титановый велосипед прекрасен, но!  1) В своем первом устройстве я вообще не использовал антидребезг. Потому, что на на старт оно ловило длииинное нажатие, а на остановку - любое. 2) В нынешнем я хочу все написать сам, не использую сторонних наработок (ну кроме разве что библиотеки сервы :-)) 

и зря вы так решили...

1) "ловил длинные нажатия" - аналог антидребезга...

2) предложенная разработка приведена к виду библиотеки и может использоваться как библиотека, по своей сути ничем не уступает библиотеки для работы с сервой. 

 :))) вы еще с классом титанового велика разберитесь сперва. Научитесь его правильно применять. Вот если в нем вам все понятно и вы его уверенно и правильно используете, тогда и самому можно подобные вещи писать под свои задачи. 

Ну, и если еще не смотрели, загляните в этот топик - Работа с кнопками. В помощь новичку.