Некорректно if или attachInterrupt/detachInterrupt... не пойму.

Sacred
Offline
Зарегистрирован: 30.05.2016


Други, подскажите, в чём проблема?
В программе использую прерывание на кнопку. Чтобы исключить дребезг и вообще отключить повторное прерывание до окончания обработки первого, отключаю его по 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;
}

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

"если закомментить в конце блока включение прерывания (29 строка), то вся конструкция (if) не сработает при запуске программы ни разу"

Где меняется переменная event? Правильно, в обработчике strob_on_off. Так? Если это обработчик не подключен, то по какой причине должен будет меняться переменная event?

 

Sacred
Offline
Зарегистрирован: 30.05.2016

Обработчик включается в setup, строка 17, до 29ой при первом запуске дело доходить не должно, прерывание должно обрабатываться по крайней мере один раз, оно ещё не выключено (в случае закомментированной 29ой), до первого вхождения в if.

dhog1
Offline
Зарегистрирован: 01.03.2016

1. interrupt_off внесите в strob_on_off()

2. digitalRead(button) излишне. В strob_on_off() вы попадаете по любому изменению уровня на пине. Нажали кнопку - первый вход, отпустили кнопку - второй вход, каждый вход в прерывание соответствует определенному уровню на пине, т.е. состоянию кнопки. Можно завести переменную, которая просто меняет свое состояние при каждом вхождении в прерывание, это заменит чтение кнопки.

3. В loop() весьма большие паузы, прерывание меж тем отключено. Возможно пропустить отпускание кнопки.

Sacred
Offline
Зарегистрирован: 30.05.2016
1. Пробовал отключать прерывания как рекомендуете, как–то не стабильно 
после этого работало, даже засомневался, можно–ли так.
 
2. Ага.
 
3. За это отвечает строка 27, выключает в любом случае.
 
Знаете какой глюк ещё ловится… после запуска платы частота контроллера как 
у черепахи, сигналы растягиваются в 2–3 раза, ситуацию спасает только 
резет, после этого всё как надо. Глюк конкретно моей дуни?
Питание через raw, 8 вольт.
 
Вообще ушел от прерывания, глючно работает, по логике косяков вроде нет, но работает из рук вон плохо.
Сделал по простому:
const byte button = 2;
const byte relay = 10;
boolean strob = false;
const int long_press = 300;
const byte short_press = 60;
const byte pause = 70;
#define relay_on_short digitalWrite(relay, HIGH); delay(short_press); digitalWrite(relay, LOW)
#define relay_on_long digitalWrite(relay, HIGH); delay(long_press); digitalWrite(relay, LOW)

void setup()
{
  pinMode(relay, OUTPUT);
  pinMode(button, INPUT_PULLUP);
}

void loop()
{
  if (!digitalRead(button) && !strob) strob_on();
  if (digitalRead(button) && strob) strob_off();
}

void strob_on()
{
  relay_on_short;
  delay(pause);
  relay_on_long;
  strob = true;
  delay(500);
}

void strob_off()
{
  relay_on_short;
  delay(pause);
  relay_on_short;
  strob = false;
  delay(150);
}

 

 

Logik
Offline
Зарегистрирован: 05.08.2014

Очень правильное решение. Теперь только делеи осталось поубирать, оптимизировать для красоты и нормалек. Через прерывания принципиально возможно, но не нужно и геморно, что Вы отлично проилюстрировали.

dhog1
Offline
Зарегистрирован: 01.03.2016

1. Не я рекомендую. Если нужно отключить прерывание в контексте его срабатывания, делается это в самом прерывании.

3. В первом скетче строка 27 не получит управления, если пропущено событие "кнопка отпущена" (переключение переменной event). В вашем случае это 1 сек. "мертвого" времени", т.е. кнопку нужно держать дольше, чтобы ловилось ее отпускание.

Глюк комментировать не могу, потому что не понял его причины.

Ну заработало с реле, и хорошо.

Sacred
Offline
Зарегистрирован: 30.05.2016

Вместо делеев миллисы в цикле покрутить? Вот чувствую, что так будет правильнее, но не могу понять почему, прерывания всё равно не используются, общения по шине нет, с датчиков ничего не ловится, может и нет тогда смысла? Или для соблюдения идеологии?

Запись и чтение пинов через порты перепишу, для пущей красоты))

Sacred
Offline
Зарегистрирован: 30.05.2016

dhog1 пишет:

3. В первом скетче строка 27 не получит управления, если пропущено событие "кнопка отпущена" (переключение переменной event). В вашем случае это 1 сек. "мертвого" времени", т.е. кнопку нужно держать дольше, чтобы ловилось ее отпускание.


Не, 27 в любом случае проверится, она штатно после 26ой прочекается, а там проверка, что если кнопка не нажата, а строб продолжает стробить, то нужно принять меры основываясь только на этом. Работает 100%.

dhog1 пишет:

Глюк комментировать не могу, потому что не понял его причины.

Ну заработало с реле, и хорошо.


Тоже не могу понять((( Вероятно глюк железки в районе кварца.

dhog1
Offline
Зарегистрирован: 01.03.2016

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

Logik
Offline
Зарегистрирован: 05.08.2014

Sacred пишет:
Вместо делеев миллисы в цикле покрутить?

Нет. Делать по аналогии с  http://arduino.ru/tutorials/BlinkWithoutDelay

 

Sacred пишет:
Вот чувствую, что так будет правильнее, но не могу понять почему, прерывания всё равно не используются, общения по шине нет, с датчиков ничего не ловится, может и нет тогда смысла? Или для соблюдения идеологии? Запись и чтение пинов через порты перепишу, для пущей красоты))

https://ru.wikipedia.org/wiki/KISS_(принцип) Прерывание механизм мощный и быстрый. Для кнопки это не нужно и вредно т.к. дребезг проявится, с ним чегото надо делать, или другие прерывания, возможно требующие быстрой обработки будут тормозить пока обработчик кнопки выполнится. И все это легко в правильной архитектуре решается опросом из лупа пару десятков раз в секунду.

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