Некорректно if или attachInterrupt/detachInterrupt... не пойму.
- Войдите на сайт для отправки комментариев
Други, подскажите, в чём проблема?
В программе использую прерывание на кнопку. Чтобы исключить дребезг и вообще отключить повторное прерывание до окончания обработки первого, отключаю его по detachInterrupt.
В loop'e всего одно условие которое обрабатывается ТОЛЬКО в случае наступления прерывания (изменение состояния кнопки), в самом начале этого блока отключаю прерывание до лучших времён, делаю дела, и под конец включаю, но, внимание вопрос: если закомментить в конце блока включение прерывания (29 строка), то вся конструкция (if) не сработает при запуске программы ни разу, т.е. прерывание будет отключенным, хоть в сетапе явно включено. Т.е. каким–то образом внутри if'a программа несанционированно прогоняется при старте, доказательство того переменная "debug", которая объявлена в начале в "0", но при первом выводе (28 строка) уже "2", хоть инкремент на единицу производится только в одном месте, в теле этого условия. Что это? Глюк компиля? Как бороться? А может в четыре утра я свой косяк какой не вижу, или чего не догоняю?
P.S. дуня Pro Micro (Leonardo)
Скетч:
const byte button = 2; const byte relay = 10; volatile boolean event = false; //флаг наступления прерывания по кнопке — замыкание/размыкание boolean strob = false; //Включен в данный момент стробоскоп или нет const int long_press = 300; // продолжительность длинного импульса const byte short_press = 100; // продолжительность короткого импульса const byte pause = 100; // пауза между импульсами byte debug = 0; #define interrupt_on attachInterrupt(digitalPinToInterrupt(button), strob_on_off, CHANGE) #define interrupt_off detachInterrupt(digitalPinToInterrupt(button)) void setup() { Serial.begin(9600); pinMode(relay, OUTPUT); //Подключение реле pinMode(button, INPUT_PULLUP); //Висит кнопка pin-GND, норм.разомкн. interrupt_on; } void loop() { if (event) //Прерывание произошло, кнопку нажал или отпустил { interrupt_off; //Отключение прерываний во имя борьбы с дребезгом и вообще, чтоб не вмешивалось. event = false; //Чтоб сюда не заглядывал до следуюшего события if (!digitalRead(button) && !strob) strob_on(); //Событие — "Кнопку нажал", "Строб выключен" -> Прогоняем комбинацию, включаем строб if (digitalRead(button) && strob) strob_off(); //Событие — "Кнопку отпущена", но строб включен -> выключаем debug++; Serial.println(debug); interrupt_on; //возобновляем реацию на кнопку } } // Комбинация для включения стробоскопа void strob_on() { digitalWrite(relay, HIGH); delay(short_press); digitalWrite(relay, LOW); delay(pause); //короткий сигнал digitalWrite(relay, HIGH); delay(long_press); digitalWrite(relay, LOW); //длинный сигнал delay(500); strob = true; //строб включен } // Комбинация для ВЫключения стробоскопа void strob_off() { digitalWrite(relay, HIGH); delay(short_press); digitalWrite(relay, LOW); delay(pause); //короткий сигнал digitalWrite(relay, HIGH); delay(short_press); digitalWrite(relay, LOW); //короткий сигнал delay(200); strob = false; //строб выключен } // Сигнал о прерывании Замыкание или размыкание кнопки void strob_on_off() { event = true; }
"если закомментить в конце блока включение прерывания (29 строка), то вся конструкция (if) не сработает при запуске программы ни разу"
Где меняется переменная event? Правильно, в обработчике strob_on_off. Так? Если это обработчик не подключен, то по какой причине должен будет меняться переменная event?
Обработчик включается в setup, строка 17, до 29ой при первом запуске дело доходить не должно, прерывание должно обрабатываться по крайней мере один раз, оно ещё не выключено (в случае закомментированной 29ой), до первого вхождения в if.
1. interrupt_off внесите в strob_on_off()
2. digitalRead(button) излишне. В strob_on_off() вы попадаете по любому изменению уровня на пине. Нажали кнопку - первый вход, отпустили кнопку - второй вход, каждый вход в прерывание соответствует определенному уровню на пине, т.е. состоянию кнопки. Можно завести переменную, которая просто меняет свое состояние при каждом вхождении в прерывание, это заменит чтение кнопки.
3. В loop() весьма большие паузы, прерывание меж тем отключено. Возможно пропустить отпускание кнопки.
Очень правильное решение. Теперь только делеи осталось поубирать, оптимизировать для красоты и нормалек. Через прерывания принципиально возможно, но не нужно и геморно, что Вы отлично проилюстрировали.
1. Не я рекомендую. Если нужно отключить прерывание в контексте его срабатывания, делается это в самом прерывании.
3. В первом скетче строка 27 не получит управления, если пропущено событие "кнопка отпущена" (переключение переменной event). В вашем случае это 1 сек. "мертвого" времени", т.е. кнопку нужно держать дольше, чтобы ловилось ее отпускание.
Глюк комментировать не могу, потому что не понял его причины.
Ну заработало с реле, и хорошо.
Вместо делеев миллисы в цикле покрутить? Вот чувствую, что так будет правильнее, но не могу понять почему, прерывания всё равно не используются, общения по шине нет, с датчиков ничего не ловится, может и нет тогда смысла? Или для соблюдения идеологии?
Запись и чтение пинов через порты перепишу, для пущей красоты))
3. В первом скетче строка 27 не получит управления, если пропущено событие "кнопка отпущена" (переключение переменной event). В вашем случае это 1 сек. "мертвого" времени", т.е. кнопку нужно держать дольше, чтобы ловилось ее отпускание.
Не, 27 в любом случае проверится, она штатно после 26ой прочекается, а там проверка, что если кнопка не нажата, а строб продолжает стробить, то нужно принять меры основываясь только на этом. Работает 100%.
Глюк комментировать не могу, потому что не понял его причины.
Ну заработало с реле, и хорошо.
Тоже не могу понять((( Вероятно глюк железки в районе кварца.
Да, вы правы, строка 27 первого скетча "застрахована" от пропуска события. Ну это так пишу, "для порядка".
Нет. Делать по аналогии с http://arduino.ru/tutorials/BlinkWithoutDelay
https://ru.wikipedia.org/wiki/KISS_(принцип) Прерывание механизм мощный и быстрый. Для кнопки это не нужно и вредно т.к. дребезг проявится, с ним чегото надо делать, или другие прерывания, возможно требующие быстрой обработки будут тормозить пока обработчик кнопки выполнится. И все это легко в правильной архитектуре решается опросом из лупа пару десятков раз в секунду.
Бывают ситуации когда прерывание по кнопке для микроконтроллера оправдано, но очень не часто.