Не работает больше одного return; в функции

morningstar
Offline
Зарегистрирован: 29.03.2021

Здравствуйте, видел, что тема немедленного выхода из режимов гирлянды на ардуино уже обсуждалась и не только здесь. Но у меня вопрос в следующем. Имеется режим, немного длинный во времени. Я изменяю номер режима с помощью прерывания. В этом длинном режиме я сделал проверку номера через некоторый интервал и если режим не совпадает, выхожу из функции через return. 

Проблема вот в чём. Первая проверка работает, я проверил, из функции выходит нормально. А вот вторая проверка уже нет. Когда номер меняется, из функции не выходит. Если удалить первый return, второй уже работает. Больше одного return отказывается работать и мне не понятно почему... Если вы знаете почему, прошу вашей помощи. Очень благодарен за уделенное время!

void mode2() {
  paint(L1, speed2, red_row);
  paint(L2, speed2, red_row);
  paint(L3, speed2, red_row);
  paint(L4, speed2, red_row);
  delay(250);
  paint(L5, speed2, red_row);
  if (mode != 2) return; // этот работает
  delay(250);
  paint(L1, speed2, green_row);
  paint(L2, speed2, green_row);
  paint(L3, speed2, green_row);
  paint(L4, speed2, green_row);
  delay(250);
  paint(L5, speed2, green_row);
  if (mode != 2) return; // этот не работает
  delay(250);
  paint(L1, speed2, blue_row);
  paint(L2, speed2, blue_row);
  paint(L3, speed2, blue_row);
  paint(L4, speed2, blue_row);
  delay(250);
  paint(L5, speed2, blue_row);
  if (mode != 2) return; // этот не работает
  delay(250);
}

 

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

А с чего бы ему работать? И в чем фишка трех одинаковых условий? Вы вообще понимаете, чего наворотили? 

morningstar
Offline
Зарегистрирован: 29.03.2021

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

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

morningstar, опишите простыми русскими словами что вы хотите сделать пошагово. Например так: возможны № редимов работы устройства. Если включен режим 1 - делаем то-то. Если включен режим 2 - вызываем пожарных. Если режим не определен не делаем ничего.

А так у вас махровый собачий бред понаписан без возможности даже предположить, как это задумано

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

"Режим немного длинный во времени" в цитатник ящитаю 

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

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

я бы запретил новичкам, не знакомым с миллис - использовать прерывания. Это мешает им правильно писать программы.

 

ТС, чтобы обеспечить выход из "режимов. немного длинных по времени" - перепишите программу без делеев. Считайте, что такого механизма, как "прерывание" - в МК просто нет. И подумайте, как решить вашу задачу без него.

 

morningstar
Offline
Зарегистрирован: 29.03.2021

У меня светодиодная rgb матрица 3х3. Я написал для неё несколько режимов. Имеется переменная mode, котоаря хранит номер эффекта от 0 до 6. В цикле lool() есть конструкция switch, которая по сохраненному значению mode вызывает ту или иную функцию с режимом. Значение в mode изменяется через прерывание кнопкой. Все работает хорошо, но с одной неприятностью. Некоторые режими длинные по времени и если я нажал кнопку и значение режима изменилось (mode++), то после прерывания код выполняется с места прерывания. Приходится ждать пока весь режим не отработает и не включится следующий. Это занимает некоторое время. Я пытался сделать проверку и выход в некоторых местах в режиме.

Если надо весь код, вот: https://pastebin.com/P2uaU4iT

rkit
Offline
Зарегистрирован: 23.11.2016

volatile
Ну и всю функцию можно переписать циклом, а лучше машиной состояний.

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

b707 пишет:

я бы запретил новичкам, не знакомым с миллис - использовать прерывания. Это мешает им правильно писать программы.

Я хотел об этом написать, но подумал, что ТС с вероятностью 99,9% не писал сам код на прерываниях, а пытается модифицировать скопипизженный в интернетах.

Автор! Ставь флаг режима в прерывании, если тебе так надо, но обрабатывай НЕ в прерывании структурой switch-case

morningstar
Offline
Зарегистрирован: 29.03.2021

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

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

morningstar пишет:

А по поводу запрета прерываний, нельзя так все запрещать, может кому-то прерывания действительно нужны (не про себя)

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

morningstar
Offline
Зарегистрирован: 29.03.2021

Rumata пишет:

Я хотел об этом написать, но подумал, что ТС с вероятностью 99,9% не писал сам код на прерываниях, а пытается модифицировать скопипизженный в интернетах.

Из интернета только взял динамическую индикацию и решение антидребезга, которое не очень корректно работает

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

И автор! Кто тебя ТАК учил оформлять switch-case?? Почитай уже книжку по С++, хотя бы по операторам потока

kolyn
Offline
Зарегистрирован: 18.01.2019

morningstar пишет:

 А по поводу запрета прерываний, нельзя так все запрещать, может кому-то прерывания действительно нужны 

Перерегистрировался?))

morningstar
Offline
Зарегистрирован: 29.03.2021

Мне сказали посмотреть как были реализованы режимы в светодиодных кубах, первая ссылка была на светодиодный куб Гайвера. У него было так...

Rumata пишет:

Автор! Ставь флаг режима в прерывании, если тебе так надо, но обрабатывай НЕ в прерывании структурой switch-case

Не совсем понял, что вы имели ввиду, простите

morningstar
Offline
Зарегистрирован: 29.03.2021

kolyn пишет:

Перерегистрировался?))

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

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

morningstar пишет:

Не совсем понял, что вы имели ввиду, простите

Плохо совсем.  Короче, прерывание - нафиг. ВАМ они не то, что не нужны, они вам противопоказаны. Кнопку обрабатывать в лупе. 

kolyn
Offline
Зарегистрирован: 18.01.2019

morningstar пишет:

kolyn пишет:

Перерегистрировался?))

Нет, впервые на этом форуме, про запрещать перывания новичкам ничего не слышал

Не ври, ливинг тичер)))

 

morningstar
Offline
Зарегистрирован: 29.03.2021

Rumata пишет:

"Режим немного длинный во времени" в цитатник ящитаю 

Ну, наверное хорошая цитата будет

Rumata пишет:

В прерывании выставляйте только флаг режима. 

Я так и сделал, только один флаг меняю в прерывании:

void count() {
  if (millis() - 100 > millis_prev) {
    if (mode < 6) mode++;
    else mode = 0;
  }
  millis_prev = millis(); 
}

 

morningstar
Offline
Зарегистрирован: 29.03.2021

Я и не вру. Ливинг тичер?

morningstar
Offline
Зарегистрирован: 29.03.2021

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

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

morningstar пишет:

 Только нажатию кнопки помешает делей, который там много где)

Придется от делея избавиться. Он не нужен

Нужно курить тему блинк без делея 

kolyn
Offline
Зарегистрирован: 18.01.2019

morningstar пишет:

Я и не вру. Ливинг тичер?

Правда не знаешь? Я почти верю.

morningstar пишет:

 Когда делал выключатель на esp8266 во время ожидания подключения к AP без прерывания, чтобы выключатель выключал во время этого ожидания, не обошлось

И эта фраза - случайность

morningstar
Offline
Зарегистрирован: 29.03.2021

kolyn пишет:

Правда не знаешь? Я почти верю.

И эта фраза - случайность

Я не знаю что такое этот тичер, код для того выключателя я не тырил из интернета (ну только смотрел примеры и пытался сделать своё). Управление через веб сделал с помощью вебсокетов. Вроде работает нормально, пока не жаловался. Но все еще не понимаю почему меня принимают за какого-то другого человека. Расскажете?

morningstar
Offline
Зарегистрирован: 29.03.2021

Rumata пишет:

Нужно курить тему блинк без делея 

От делея избавиться могу, за исключением места в динамической индикации. Его я взял из интернета: https://habr.com/ru/post/129569/

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

morningstar пишет:

От делея избавиться могу, 

Странная ситуация складывается. Делей мешает работе вашего алгоритма, но вы не хотите от этой пакости отказаться. Остается терпеть и не жаловаться

morningstar
Offline
Зарегистрирован: 29.03.2021

Вот я попытался избавиться. Когда функция выполняется заново, выполняется только первая часть до второго if. Поэтому я сделал флаг, который изменяется и если он изменился, часть кода, которая уже выполнилась, больше не выполняется, так по кругу.

byte flag_mode2 = 0; // инициализация флага в начале программы

void mode2() {
  Serial.print("Mode: ");
  Serial.println(mode);
  if (millis() - current_time > 250 && flag_mode2 == 0) { // проверка миллис и флага
    current_time = millis();
    paint(L1, speed2, red_row);
    paint(L2, speed2, red_row);
    paint(L3, speed2, red_row);
    paint(L4, speed2, red_row); 
    flag_mode2 = 1; // изменение флага на следующий
  }
  if (millis() - current_time > 250 && flag_mode2 == 1) {
    current_time = millis();
    paint(L5, speed2, red_row);
    flag_mode2 = 2; 
  }
  if (millis() - current_time > 250 && flag_mode2 == 2) {
    current_time = millis();
    paint(L1, speed2, green_row);
    paint(L2, speed2, green_row);
    paint(L3, speed2, green_row);
    paint(L4, speed2, green_row);
    flag_mode2 = 3;
  }
  if (millis() - current_time > 250 && flag_mode2 == 3) {
    current_time = millis();
    paint(L5, speed2, green_row);
    flag_mode2 = 4;
  }
  if (millis() - current_time > 250 && flag_mode2 == 4) {
    current_time = millis();
    paint(L1, speed2, blue_row);
    paint(L2, speed2, blue_row);
    paint(L3, speed2, blue_row);
    paint(L4, speed2, blue_row);
    flag_mode2 = 5;
  }
  if (millis() - current_time > 250 && flag_mode2 == 5) {
    current_time = millis();
    paint(L5, speed2, blue_row);
    flag_mode2 = 0;
  }

 

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

morningstar

Вам нужно еще управлять состоянием (стадиями). Можете попробовать почитать о конечных автоматах .Конечные автоматы в C++ в блоге Личный опыт разработки ПО (devexp.ru)

morningstar
Offline
Зарегистрирован: 29.03.2021

Rumata пишет:

Можете попробовать почитать о конечных автоматах

Когда-то проходил практику от университета, мне дали задание изучать плисы. Еле научился на нем сделать гирлянду из четырех светодиодов. Следущим были режимы на конечном автомате)) Я его так и не смог осилить. Наверное, время грызть знания пришло... Спасибо за ссылку

P.S. Делей все таки реальное зло! Обычно стараюсь его не использовать, но чет поперло меня на него. Без использования делей из режима выходит сразу же, как завершится анимация, они у меня короткие. Это немного помогло решить мою проблему. Но после прокрутки режимов, этот режим начинается с места где закончился, нужно как-то обновить флаг

Всем спасибо за помощь и советы!

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

morningstar пишет:

Не работает больше одного return; в функции

И хорошо! Структурное программирование запрещает использование более одного return. Камасутра ... тьфу, блин ... MISRA - тоже! Так и не используйте - будьте правильным и прогрессивным!

kolyn
Offline
Зарегистрирован: 18.01.2019

morningstar пишет:

kolyn пишет:

Правда не знаешь? Я почти верю.

И эта фраза - случайность

Я не знаю что такое этот тичер,

Расскажете?

Да. Чел, который умеет прерывания и ЕСП и не может справиться с делай ооочень похож на троля)). И судя по тому, что интернетом ты пользоваться умеешь тема с ретюрн возникнуть не могла сама по себе. Если ошибся - извини, если нет - не обессудь...

morningstar
Offline
Зарегистрирован: 29.03.2021

kolyn пишет:

Если ошибся - извини, если нет - не обессудь...

Та все нормально, в esp не приходилось делать делей, разве что есть такая проблема, когда он все таки нужен, я применял нехороший способ програмного рестарта мк, делая вызов void(* resetFunc) (void) = 0;

Если перед этим что-то отправляется в монитор порта, оно не выводит это, не успевает что-ли. Вот тут и помогал делей в несколько миллисекунд. 

А так, я ни кого не троллил, это моя реальная проблема которую я пытаюсь решить

Upper
Offline
Зарегистрирован: 23.06.2020

morningstar пишет:

А так, я ни кого не троллил, это моя реальная проблема которую я пытаюсь решить

Для не тролля вы слишком покладисты, учитывая агрессивный тупизм Rumata

kolyn
Offline
Зарегистрирован: 18.01.2019

Upper пишет:

Для не тролля вы слишком покладисты

+100500

rkit
Offline
Зарегистрирован: 23.11.2016

morningstar пишет:

А так, я ни кого не троллил, это моя реальная проблема которую я пытаюсь решить

Всё нужное для решения было дано больше часа назад, так что неправда.

kolyn
Offline
Зарегистрирован: 18.01.2019

rkit пишет:

morningstar пишет:

А так, я ни кого не троллил, это моя реальная проблема которую я пытаюсь решить

Всё нужное для решения было дано больше часа назад, так что неправда.

В названии темы толсто

 

morningstar
Offline
Зарегистрирован: 29.03.2021

Ну... возможно до меня долго доходило. От делей избавился везде кроме функции динамической индикации, там присутствует delayMicroseconds(400), 400 микросекунд ардуино ничего не делает, возможно это критично, не знаю. Там просто цикл for и реализовать там без delay возможно для меня будет сложновато. 

А еще наверное дурной тон хранить каждый отдельный символ (допустим кадр анимации) в отдельном массиве. При сознании большого количества кадров анимации для разных режимов эти массивы плодятся. 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

morningstar пишет:

А еще наверное дурной тон хранить каждый отдельный символ (допустим кадр анимации) в отдельном массиве.  

Да нет - тон нормальный при наличие памяти. А так она очень быстро кончается.

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

Меня все-таки шокирует заголовок темы.

В самом деле, если мы один раз зашли в функцию, то вряд ли можем выйти из нее более одного раза. Если зашли во второй раз - то тоже выйти можем только единожды.

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

morningstar
Offline
Зарегистрирован: 29.03.2021

Я до этого момента избегал return. Спасибо за объяснение