Добрый вечер!Помогите пожалуйста. Не могу разобраться с принудительным выходом из цикла while вот часть кода управления Смысл в том что есть семь режимов моргания гирлянды переключающихся циклично по кругу кнопкой все работает как надо переключения происходят нормально с режима regim == 0 по режим regim == 7 в котором прописан автомат переключения по таймеру как только заходим в цикл while он начинает непрерывно выполнять режимы по цепочке и когда надо нажав кнопку вернуться в режим regim == 0 этого не происходит. Вопрос вот в чем как через кнопку в любой момент прервать всю цепочку циклов и выйти в режим regim == 0 ? Помогите пожалуйста! Код огромный весь приводить нет смысла самое главное есть. Код (C++): #include "FastLED.h" #include <FastLED.h> #if FASTLED_VERSION < 3001000 #error "Requires FastLED 3.1 or later; check github for latest code." #endif #define ButPin 7 #define DATA_PIN 8 #define CLOCK_PIN 9 #define LED_TYPE WS2801 #define COLOR_ORDER GRB #define NUM_LEDS 25 #define BRIGHTNESS 255 CRGB leds[NUM_LEDS]; #define UPDATES_PER_SECOND 100 #define MASTER_BRIGHTNESS 125 #define STARTING_BRIGHTNESS 120 #define FADE_IN_SPEED 32 #define FADE_OUT_SPEED 20 #define DENSITY 255 #define FRAMES_PER_SECOND 25 #define ZOOMING_BEATS_PER_MINUTE 61 #define PURP 0xFF23FF #define ORAN 0xFF0C00 #define GREN 0x00FFD8 #define WHIT 0xCCCCCC const CRGBPalette16 HalloweenColors_p ( PURP, PURP, PURP, PURP, ORAN, ORAN, ORAN, ORAN, PURP, PURP, PURP, PURP, GREN, GREN, GREN, WHIT ); CRGBPalette16 gCurrentPalette( HalloweenColors_p ); #define BLENDING NOBLEND int flag = 0; int regim = 0; #define TWO_SIN_H #define BLENDING NOBLEND CRGBPalette16 currentPalette; TBlendType currentBlending; extern CRGBPalette16 myRedWhiteBluePalette; extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM; int RED[5]; int GREEN[5]; int BLUE[5]; uint8_t max_bright = 255; uint8_t colour; int center = 0; int step = -1; uint8_t myfade = 255; #define maxsteps 16 uint8_t bgcol = 0; int thisdelay = 100; unsigned long currentTime = millis(); unsigned long TimeNext = 24000; unsigned long TimeNext1 = 18000; unsigned long TimeNext2 = 48000; void setup() { pinMode(CLOCK_PIN, OUTPUT); pinMode(DATA_PIN, OUTPUT); for (int i = 0; i < 25; i++) { RED[i] = 0; BLUE[i] = 0; GREEN[i] = 0; } pinMode(ButPin, INPUT); delay(3000); FastLED.addLeds<WS2801, RGB>(leds, NUM_LEDS); FastLED.addLeds<WS2801, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS); FastLED.setBrightness(BRIGHTNESS); currentPalette = RainbowColors_p; currentBlending = LINEARBLEND; FastLED.setBrightness(max_bright); } void loop() { if (digitalRead(ButPin) == HIGH && flag == 0) { regim ++; flag = 1; if (regim > 7) { regim = 0; } } if (digitalRead(ButPin) == LOW && flag == 1) { flag = 0; } if (regim == 0) { pride(); FastLED.show(); } if (regim == 1) { chooseColorPalette(); colortwinkles(); FastLED.show(); FastLED.delay(20); } if (regim == 2) { PeriodicallyChooseNewColorPalettes(); MixBeatPalette(); DrawOneFrameUsingBeatPalette(); FastLED.show(); FastLED.delay(30); } if (regim == 3) { discostrobe(); FastLED.show(); delayToSyncFrameRate( FRAMES_PER_SECOND); } if (regim == 5) { ChangePalettePeriodically(); static uint8_t startIndex = 0; startIndex = startIndex + 1; /* motion speed */ FillLEDsFromPaletteColors( startIndex); FastLED.show(); FastLED.delay(1000 / UPDATES_PER_SECOND); } if (regim == 4) { for (int i = 0; i < 25; i++) { RED[i] = 255; GREEN[i] = 255; BLUE[i] = 255; updatestring(); RED[i] = 0; GREEN[i] = 0; BLUE[i] = 0; delay(50); } } if (regim == 6) { EVERY_N_MILLISECONDS(thisdelay) { ripple(); } show_at_max_brightness_for_power(); } if (regim == 7) { currentTime = millis(); while (millis() - currentTime <= (TimeNext + TimeNext2)) { everchanging(); } currentTime = millis(); while (millis() - currentTime <= (TimeNext + TimeNext1)) { ColorTwinkles(); } currentTime = millis(); while (millis() - currentTime <= TimeNext) { PalBeat(); } currentTime = millis(); while (millis() - currentTime <= TimeNext) { DIscStrobe(); } currentTime = millis(); while (millis() - currentTime <= (TimeNext + TimeNext2)) { ColorPal(); } currentTime = millis(); while (millis() - currentTime <= TimeNext) { MapTwinkle(); } currentTime = millis(); while (millis() - currentTime <= TimeNext) { for (int i = 0; i < 25; i++) { RED[i] = 255; GREEN[i] = 255; BLUE[i] = 255; updatestring(); RED[i] = 0; GREEN[i] = 0; BLUE[i] = 0; delay(50); } } } } void everchanging()//0 { pride(); FastLED.show(); } void ColorTwinkles()//1 { chooseColorPalette(); colortwinkles(); FastLED.show(); FastLED.delay(20); } void PalBeat()//2 { PeriodicallyChooseNewColorPalettes(); MixBeatPalette(); DrawOneFrameUsingBeatPalette(); FastLED.show(); FastLED.delay(30); } void DIscStrobe ()//3 { discostrobe(); FastLED.show(); delayToSyncFrameRate( FRAMES_PER_SECOND); } void ColorPal ()//4 { ChangePalettePeriodically(); static uint8_t startIndex = 0; startIndex = startIndex + 1; /* motion speed */ FillLEDsFromPaletteColors( startIndex); FastLED.show(); FastLED.delay(1000 / UPDATES_PER_SECOND); } void MapTwinkle()//5 { EVERY_N_MILLISECONDS(thisdelay) { ripple(); } show_at_max_brightness_for_power(); }
Слишком длинный кусок, вряд ли кто то будет вчитываться. Вставьте именно то место которое интересует.
Сократил количество режимов с 8 до трех для наглядности что сделано Код (C++): void loop() { if (digitalRead(ButPin) == HIGH && flag == 0) { regim ++; flag = 1; if (regim > 7) { regim = 0; } } if (digitalRead(ButPin) == LOW && flag == 1) { flag = 0; } if (regim == 0) // void everchanging { pride(); FastLED.show(); } if (regim == 1) //void ColorTwinkles { chooseColorPalette(); colortwinkles(); FastLED.show(); FastLED.delay(20); } // в этом месте заходит в цикл и от сюда с помощью кнопки не вернуться в начало if (regim == 7) { currentTime = millis(); while (millis() - currentTime <= (TimeNext + TimeNext2)) { everchanging(); } currentTime = millis(); while (millis() - currentTime <= (TimeNext + TimeNext1)) { ColorTwinkles(); } } } void everchanging()// regim == 0 { pride(); FastLED.show(); } void ColorTwinkles()//regim == 1 { chooseColorPalette(); colortwinkles(); FastLED.show(); FastLED.delay(20); }
Сократил, нужно как то дописать цикл while чтоб при нажатии кнопки выскакивал в состояние переменой regim ==0 Все что мог применить пробовал но самостоятельно не получилось.
Попробуйте как то так: Код (C++): while ((millis() - currentTime <= (TimeNext + TimeNext2)) and (!digitalRead(ButPin))) { everchanging(); } Если будет сразу выскакивать уберите "!". Со вторым while то же самое и после них "regim = 0", если я правильно понял задачу.
Это первое что я пробовал это работает но не так перескакивает с цикла на цикл и пока не пройдешь все восемь циклов while в режим regim ==0 не попадешь приходиться 7 раз нажать кнопку
Было и так while (millis() - currentTime <= (TimeNext + TimeNext2) && flag) в теле цикла прописывал нажатие кнопки делал выход break; тоже не помогло или может знаний не хватает
flag не изменяется внутри цикла из которого надо выпасть при нажатии кнопки, с чего он будет влиять на него? Попробуйте мой вариант все же.
Такой вариант как у вас я пробовал он заставляет нажимать кнопку восемь раз пока не закончатся циклы только после этого он переходит в режим ноль while (millis() - currentTime <= TimeNext && !digitalRead(ButPin))
по логике получается выполняем everchanging(); в теле цикла while пока пока разность миллис и карент тайм не станет равной тайм некст или не нажата кнопка как только цикл заканчивается спускается ниже на строчку а там уже выполняем ColorTwinkles(); и так далее
А задача состоит в том что не зависимо от того какой из этих циклов бы не выполнялся давим кнопку и идем в режим ноль.
Ну вариант только один, постоянно опрашивать кнопку и выпадать при ее нажатии. Опрос делать либо внутри цикла с прерыванием его в случае чего или и условии цикла, как сделал я. Какие еще могут быть варианты? Ах ну да, еще можно повесить кнопку на прерывание, где будет задан режим 0, но цикла это не прервет без изменений условий. Кстати, я не заметил разницы между вашими циклами по таймеру и обычным delay(), в чем их смысл. если выполняется единственная задача в теле, которая никак не меняется.
Я пробовал такой вариант но знаний не хватает правильно и грамотно раставить по своим местам. Флаг как раз прерывал цикл while (millis() - currentTime <= (TimeNext + TimeNext2) && flag) а ниже прописывал if (digitalRead(ButPin) == HIGH ) { regim = 0; break; } everchanging(); } Но от нехватки грамотности не получалось у меня правильно выставить флаг то проскакивал этот режим то заходил и моментально выходил из него
В данном случае: Код (C++): if (digitalRead(ButPin) == HIGH ) { regim = 0; break; } everchanging(); } break вообще не нужен.
В общем, у вас логика программы странная изначально. Вроде бы есть попытка сделать правильно, но в итоге сделано как обычно, то есть без псевдомногозадачности. Смесь ежа с ужом. Надо бы понять что программа делать должна чтобы пересмотреть алгоритм полностью.
Ну я еще только учусь Имеется одна кнопка переключения восьми режимов каждое следуюшее нажатие пошагово переключает режимы с первого по седьмой восьмой режим по таймеру переключает эти семь режимов автоматически в заданное время единственная проблема с восьмого режима нет выхода на первый помогает только ресет
Прошу прощение, за вмешательство в вашу беседу, но надеюсь быть полезным. Прежде, чем предлагать конкретные решения, давайте взглянем на задачу: нужно по нажатию кнопки менять режим мигания гирлянды, есть 6 режимов "мигания" и 7ой -- это перебор шести режимов с определенным интервалом времени. Так? (Если нет, то постараюсь удалить это сообщение). Исходя из этой постановки задачи могу предложить следующее решение: 'sanik', Вы уже реализовали 6 режимов. Вместо 7-го режима нужно добавить два "мастер режима": мигание гирлянды в одном из 6-и режимов; мигание гирлянды со сменой режимов с определенным интервалом времени. Как это реализовать в коде (не знаю как код выглядит сейчас -- отталкиваюсь от кода из стартового топика): все изменения касаются функции 'loop()'; что бы не плодить переменных, все режимы будут храниться в уже существующей переменной 'regim', но примем соглашение -- биты 0 .. 2 - это режим мигания, 3-й бит - это индикатор "мастер режима"; удаляем всё, что связано с условием 'if (regim == 7)', но не далеко -- кое что понадобиться; меняем обработчик нажатия кнопки: Код (C++): if (digitalRead(ButPin) == HIGH && flag == 0) { flag = 1; if (regim & 8) // находимся во втором "мастер режиме" { // нужно сменить на первый regim = 0; } else // находимся в первом "мастер режиме" { // сменяем режим мигания regim ++; if (regim > 6) // если перебрали все 6 режимов { // меняем "мастер режим" на второй regim = 8; } } } добавляем код смены режимов мигания по истечении определенного интервала времени во втором "мастер режиме" (сразу после обработки нажатия/отжатия кнопки): Код (C++): if (regim & 8) // если находимся во втором "мастер режиме" { // здесь надо в соответствии с прошедшим временем переключать режим // то, что делалось в исходном коде (топик №1) в условии 'if (regim == 7)', // но нужно только переключать режимы, например: if (millis() - currentTime <= (TimeNext + TimeNext2)) { regim = 8 + 3; // установили 4-й режим мигания из 6-и } else if (millis() - currentTime <= (TimeNext + TimeNext1)) { regim = 8; // установили 1-й режим мигания из 6-и } // ЭТО ПРИМЕР. Конкретную логику смены режимов по времени -- думайте сами } остальные проверки оформляем следующим образом: Код (C++): if ((regim & 7) == 0) { // мигаем в первом режиме ........ } else if ((regim & 7) == 1) { // мигаем во втром режиме } else if ...... и так далее Это первый шаг на пути решения задачи. Следующая проблема -- смена режимов и опрос кнопки будет происходить не сразу, а после выполнения "миганий" (тех, что прописаны в условиях if (regim == 0) .. if (regim == 6) ) и, если продолжительность "миганий" довольно длительная, эта проблема может стать причиной отсутствия реакции на нажатие кнопки. Для решения проблемы "отсутствия реакции на нажатие кнопки", лучше использовать прерывания (например в UNO -- кнопку повесть на пин 2 или 3): основной поток программы -- функция 'loop()' -- отвечает за мигание гирлянды в соответствии с режимами и "мастер режимами"; прерывание по нажатию кнопки сменяет режимы. 'DrProg' как-то сетовал, что не знает где прерывания применить.....