Помогите советом. Прерывание цикла.
- Войдите на сайт для отправки комментариев
Доброго времени суток. Помогите, пожалуйста, советом по организации прерывания.
Суть такая. Пытаюсь соорудить что-то типа LED контроллера.
Схема отладки:
1. UNO
2. Тактовая кнопка, притянута к земле, подключена на второй pin.
3. RGB светодиоды:
redled = 3;
greenled = 5;
blueled = 6;
Что хотелось бы увидеть. Диоды мигают по какому-то своему алгоритму, при нажатии кнопки происходит переключение программы "мигалки".
Например. Мигает красный, нажал кнопку - замигал зеленый, еще раз нажал - замигал синий, еще раз нажал - стали мигать RGB по очереди.
Программист я неопытный. Гуглил, читал, в итоге пришел к одному варианту, который больше всего напоминает то, что я хочу, но и с ним немного что-то не так.
По порядку
int switchPin = 2;
int redled = 3;
int greenled = 5;
int blueled = 6;
volatile int LEDstate = 0;
char colors[3] = {redled, greenled, blueled}; //Засунул в массив для удобства обращения через циклы
void setup()
{
pinMode(blueled, OUTPUT);
pinMode(redled, OUTPUT);
pinMode(greenled, OUTPUT);
pinMode(switchPin, INPUT);
attachInterrupt(0, LEDstateSwitch, LOW);
}
//Мигаем три раза цветом по выбору
void anyblink(int x){
for(int i=0;i<3;i++){
digitalWrite(colors[x], HIGH);
delay(1000);
digitalWrite(colors[x], LOW);
delay(1000);
}
}
//Мигаем бесконечно цветом по выбору
void anyblink(int x){
int tmp_LEDstate = LEDstate;
while(tmp_LEDstate == LEDstate){
for(int i=0;i<3;i++){
digitalWrite(colors[x], HIGH);
delay(1000);
digitalWrite(colors[x], LOW);
delay(1000);
}
}
}
//Три красных, три зеленых, три синих
void anyblink_all(){
for(int i=0;i<3;i++){
anyblink(i);
}
}
//В лупе - код, который запускает определенную функцию, в зависимости от значения LEDstate
//LEDstate принимает значения от [0-3], а каждое нажатие кнопки увеличивает значение на 1
//Если значение LED state становится больше 3, то присваиваем значение "0"
//Таким образом, переключаем программы мигалок по кругу
void loop() {
if (LEDstate > 3) //Проверяем, не превышено ли максимальное значение
{
LEDstate = 0;
}
else
{
if (LEDstate == 0) //Три красных свистка
{
anyblink(0);
}
else if (LEDstate == 1) //Три зеленых
{
anyblink(1);
}
else if (LEDstate == 2) //Три синих
{
anyblink(2);
}
else if (LEDstate == 3)//Три красных, три зеленых, три синих.
{
anyblink_all();
}
}
}
//Обработка прерывания с дебонсом и увеличением значения LEDstate на 1
void LEDstateSwitch()
{
static unsigned long millis_prev;
if(millis()-100 > millis_prev) LEDstate++;
millis_prev = millis();
}
Получается на выходе следующее. Если берем функцию с тремя вспышками, то прерывается только та вспышка, с которой совпало нажатие кнопки, оставшиеся срабатывают, и только после этого происходит переключение программы. Если не совсем понятно, то на примере:
Мигает красный, который должен мигнуть три раза по условиям функции. Если нажимаем во время первой вспышки из трех, прерывается только первая вспышка, диод моргает еще два раза красным и после этого включается зеленая мигалка.
Если берем функцию anyblink_all(), которая, напоминаю, должна мигнуть три раза красным, три зеленым, и три синим, то попытавшись ее прервать на красном, увидим, как она домаргивает зеленым и синим и только потом начинается выполнение следующей функции.
В случае с infiniteblink(), бесконечным циклом, переключение вообще не происходило, если не добавлять условие
int tmp_LEDstate = LEDstate; while(tmp_LEDstate == LEDstate)
после обработки прерывания, программа продолжается с прерванного места, т.е после прерывания функция продолжится до конца.
надо взводить флаг и постоянно проверять его в цикле, если он взведен, делать break. А прерывание может происходить в _любом_ месте цикла
Не уверен, что правильно Вас понял, но спасибо :)
Добвил в начало каждой функции
Дабы зафиксировать текущее состояние режима. А в конце каждой итерации цикла включил проверку
Получилось вот так:
void infiniteblink(int x){ int tmp_LEDstate = LEDstate; while(tmp_LEDstate == LEDstate){ digitalWrite(colors[x], HIGH); delay(1000); digitalWrite(colors[x], LOW); delay(1000); } } //------------------------------------------ void anyblink(int x){ for(int i=0;i<3;i++){ int tmp_LEDstate = LEDstate; digitalWrite(colors[x], HIGH); delay(1000); digitalWrite(colors[x], LOW); delay(1000); if(tmp_LEDstate != LEDstate) break; } } //------------------------------------------ void anyblink_all(){ int tmp_LEDstate = LEDstate; for(int i=0;i<3;i++){ anyblink(i); if(tmp_LEDstate != LEDstate) break; } }Только все еще не пойму, почему при выставлении триггера прерываний в LOW, все задержки половинятся. Похоже, что в функции delay() что-то скипается, раз кнопка поднята.
В общем, вроде работает основная часть. Если есть более изящный способ воплотить мою идею, буду рад увидеть :)
Код написан канешно не очень но я его поправил. Попробуйте
#define switchPin 2 #define redled 3 #define greenled 5 #define blueled 6 volatile int LEDstate = 0; volatile int tmp_LEDstate = 0; char colors[3] = {redled, greenled, blueled}; //Засунул в массив для удобства обращения через циклы void setup() { pinMode(blueled, OUTPUT); pinMode(redled, OUTPUT); pinMode(greenled, OUTPUT); pinMode(switchPin, INPUT); attachInterrupt(0, LEDstateSwitch, FALLING); } //Обработка прерывания с дебонсом и увеличением значения LEDstate на 1 void LEDstateSwitch() { LEDstate++; } //Мигаем бесконечно цветом по выбору void anyblink(int x) { for (int i = 0; i < 3; i++) { digitalWrite(colors[x], HIGH); delay(1000); digitalWrite(colors[x], LOW); delay(1000); if (tmp_LEDstate != LEDstate) { tmp_LEDstate = LEDstate; break; } } } //Три красных, три зеленых, три синих void anyblink_all() { for (int i = 0; i < 3; i++) { anyblink(i); if (tmp_LEDstate != LEDstate) { tmp_LEDstate = LEDstate; break; } } } //В лупе - код, который запускает определенную функцию, в зависимости от значения LEDstate //LEDstate принимает значения от [0-3], а каждое нажатие кнопки увеличивает значение на 1 //Если значение LED state становится больше 3, то присваиваем значение "0" //Таким образом, переключаем программы мигалок по кругу void loop() { if (LEDstate > 3) //Проверяем, не превышено ли максимальное значение { LEDstate = 0; } else { if (LEDstate == 0) //Три красных свистка { anyblink(0); } else if (LEDstate == 1) //Три зеленых { anyblink(1); } else if (LEDstate == 2) //Три синих { anyblink(2); } else if (LEDstate == 3)//Три красных, три зеленых, три синих. { anyblink_all(); } } }1 ошибка это delay();
2 ошибка это останавливать delay() прерыванием.
Ну делай - это само собой. А если без далай то тогда так
#define switchPin 2 #define redled 3 #define greenled 5 #define blueled 6 volatile int LEDstate = 0; volatile int tmp_LEDstate = 0; unsigned long millis_prev; int kol = 0; int volume = 0; int kolor = 0; char colors[3] = {redled, greenled, blueled}; //Засунул в массив для удобства обращения через циклы void setup() { pinMode(blueled, OUTPUT); pinMode(redled, OUTPUT); pinMode(greenled, OUTPUT); pinMode(switchPin, INPUT); attachInterrupt(0, LEDstateSwitch, FALLING); } //Обработка прерывания с дебонсом и увеличением значения LEDstate на 1 void LEDstateSwitch() { LEDstate++; } //Мигаем бесконечно цветом по выбору void anyblink(int x) { digitalWrite(colors[x], !digitalRead(colors[x])); } void loop() { if (tmp_LEDstate != LEDstate) { kol = 0; kolor = 0; volume = 0; tmp_LEDstate = LEDstate; for (int i = 0; i < 3; i++) { digitalWrite(colors[i], LOW); } } if (LEDstate > 3) //Проверяем, не превышено ли максимальное значение { LEDstate = 0; } if (LEDstate < 3 && kol < 6) // { if (millis() - millis_prev >= 1000) { anyblink(LEDstate); millis_prev = millis(); kol++; } } else if (LEDstate == 3 && kol < 6)//Три красных, три зеленых, три синих. { if (millis() - millis_prev >= 1000) { if (volume == 6)kolor++, volume = 0; if (kolor > 2)kolor = 0; anyblink(kolor); volume++; millis_prev = millis(); } } }Я сделал так Полный скетч здесь https://yadi.sk/d/rbJvpZqd3Bvw4h
А это головной файл
Благодарю за внимание, но некорректно работает без этого
void LEDstateSwitch() { static unsigned long millis_prev; if(millis()-50 > millis_prev) LEDstate++; millis_prev = millis(); }Да и, не понимаю пока почему, но при всех типах прерывания, кроме LOW, смена LEDstate происходит при как при нажатии, так и при отпускании кнопки. Т.е. за один цикл нажатия, происходит +2 к LEDstate.
Пропробывай
void LEDstateSwitch() { cli(); static unsigned long millis_prev; if(millis()-50 > millis_prev) LEDstate++; millis_prev = millis(); sei(); }может, в millis() опять неявно прерывания разрешаются?
Ну делай - это само собой. А если без далай то тогда так
Я сделал так Полный скетч здесь https://yadi.sk/d/rbJvpZqd3Bvw4h
А это головной файл
Спасибо, это уже круто. Необходимо время для осмысления :) Совсем другой уровень.
Пропробывай
void LEDstateSwitch() { cli(); static unsigned long millis_prev; if(millis()-50 > millis_prev) LEDstate++; millis_prev = millis(); sei(); }может, в millis() опять неявно прерывания разрешаются?
Вечером попробываю, спсибо!
Пропробывай
void LEDstateSwitch() { cli(); static unsigned long millis_prev; if(millis()-50 > millis_prev) LEDstate++; millis_prev = millis(); sei(); }может, в millis() опять неявно прерывания разрешаются?
пробую: millis_prev = 5; if(6 - 50 > 5) O_O;
if((millis()-millis_prev)>50) LEDstate++; else return;Благодарю за внимание, но некорректно работает без этого
void LEDstateSwitch() { static unsigned long millis_prev; if(millis()-50 > millis_prev) LEDstate++; millis_prev = millis(); }Да и, не понимаю пока почему, но при всех типах прерывания, кроме LOW, смена LEDstate происходит при как при нажатии, так и при отпускании кнопки. Т.е. за один цикл нажатия, происходит +2 к LEDstate.
Это у Вас идет дребезг контактов а с millis дребезг устраняется. Так что отавляйте это полезно
Ну, да. я это и имел ввиду. Там закомменчено в коде, что тут дебонс идет.
Вот. тут хотел уточнить. Какова роль переменных kol и volume?
kol-перебор цвета(красн. син.зелен) volume-количество морганий
kol-перебор цвета(красн. син.зелен) volume-количество морганий
А я так понял. что перебор цвета, это kolor, а у kol ОДЗ [0:5]
Да Вы правы vulume выполняла тоже что и kol можно обойтись без нее. Поэтому я применил ее в другое где она нужнее
#define switchPin 2 #define redled 3 #define greenled 5 #define blueled 6 volatile int LEDstate = 0; volatile int tmp_LEDstate = 0; unsigned long millis_prev; int kol = 0; bool volume = 0; int kolor = 0; char colors[3] = {redled, greenled, blueled}; //Засунул в массив для удобства обращения через циклы void setup() { pinMode(blueled, OUTPUT); pinMode(redled, OUTPUT); pinMode(greenled, OUTPUT); pinMode(switchPin, INPUT); attachInterrupt(0, LEDstateSwitch, FALLING); } //Обработка прерывания с дебонсом и увеличением значения LEDstate на 1 void LEDstateSwitch() { LEDstate++; } //Мигаем бесконечно цветом по выбору void anyblink(int x) { volume = !volume; digitalWrite(colors[x], volume); } void loop() { if (tmp_LEDstate != LEDstate) { kol = 0; kolor = 0; volume = 0; tmp_LEDstate = LEDstate; for (int i = 0; i < 3; i++) { digitalWrite(colors[i], LOW); } } if (LEDstate > 3) //Проверяем, не превышено ли максимальное значение { LEDstate = 0; } if (LEDstate < 3 && kol < 6) // { if (millis() - millis_prev >= 1000) { anyblink(LEDstate); millis_prev = millis(); kol++; } } else if (LEDstate == 3 && kol <= 6)//Три красных, три зеленых, три синих. { if (millis() - millis_prev >= 1000) { if (kol == 6)kolor++, kol = 0; if (kolor > 2)kolor = 0; anyblink(kolor); kol++; millis_prev = millis(); } } }kol-перебор цвета(красн. син.зелен) volume-количество морганий
Мда... "Найдите 10 отличий" (с)
color - цвет, value - значение/величина.