Внешнее прерывание и прерывание цикла

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

Добрый день!

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

Проблема в следующем:

int p = 100;
int m = 1;
int o = 0;

void setup() {
pinMode(2, INPUT);
digitalWrite(2, HIGH);
attachInterrupt(0, mm, FALLING);
}

void loop() {

 switch (m){
  case 1:
    for(int i=0; i<m; i++){in();}  break;  //выполняется 1 раз
  case 2:
    for(int i=0; i<m; i++){in();}  break;  //выполняется 2 раза
  case 3:
    for(int i=0; i<m; i++){in();}  break;  //выполняется 3 раза
  case 4:
    for(int i=0; i<m]; i++){in();}  break;  //выполняется 4 раза
 }
}

void mm(){
  m++;
  if(m>4){m=1;}
}

void in(){
  o = 10; st();
  o = 20; st();
  o = 30; st();
  o = 40; st();
}

void st(){delay(o);}

Программа выше, убрано всё лишнее, оставлен алгоритм работы, вывод2(прерывание0) замыкается кнопкой на землю, при этом значение m меняется сразу, но выхода из текущего цикла for не происходит. Если идет выполнение цикла for в case 4, которое выполняется, в данном примере, 4 раза, каждый раз занимает, допустим 1 минуту, итого весь цикл работает 4 минуты, если нажать кнопку на 1й минуте, m поменяется, но switch не переключит case пока цикл for не закончится.

Это такая особенность ардуины или есть варианты? Желательно, после срабатывания прерывания прервать выполнение текущего for и обработать switch согласно новой m.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

BoBo4kA, начнём с того, что переенные, изменяемые в прерывании принято квалифицировать как волатайл.

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

Разницы я не заметил, как определить переменную, и, исходя из описания прерываний, счёл данный параметр не нужным, т.к. переменная меняется не только в функции прерывания(этого не видно в привиденном коде). Если подскажите, в чем разница, буду благодарен.

Gres
Gres аватар
Offline
Зарегистрирован: 26.03.2013

Аппаратно дребезг устраняете?

vde69
Offline
Зарегистрирован: 10.01.2016

на мой взгляд не важно почему цикл не прерывается при уменьшении (предположим, что m кешируется в регистре AX проца)

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

vde69
Offline
Зарегистрирован: 10.01.2016

да и вообще про стек параметров при вызовах операторов и функций надо почитать и прикинуть как в этот стек вклиниваются прерывания...

Radjah
Offline
Зарегистрирован: 06.08.2014

BoBo4kA пишет:

Разницы я не заметил, как определить переменную, и, исходя из описания прерываний, счёл данный параметр не нужным, т.к. переменная меняется не только в функции прерывания(этого не видно в привиденном коде). Если подскажите, в чем разница, буду благодарен.

Вместо риса взяли гречку, вместо рыбы свинину и завернули всё в лаваш. Почему суши на вкус не такие?

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

Для понимания проблемы рабочий код:

bool m = 1;
byte o = B0000;
int f = 10;

void setup() {
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
pinMode(2, INPUT);
digitalWrite(2, HIGH);
attachInterrupt(0, mm, FALLING);
}

void loop() {
   switch (m){
  case 0:
    for(int i=0; i<f; i++){f1();}
    break;
  case 1:
    for(int i=0; i<f; i++){f2();}
    break;
   }
}

void mm(){
  m=!m;
  digitalWrite(13,m);
}

void f1(){
  o = B0001; s();
  o = B0010; s();
  o = B0100; s();
  o = B1000; s();
}

void f2(){
  o = B1000; s();
  o = B0100; s();
  o = B0010; s();
  o = B0001; s();
}

void s(){
  digitalWrite(4, bitRead(o,0));
  digitalWrite(5, bitRead(o,1));
  digitalWrite(6, bitRead(o,2));
  digitalWrite(7, bitRead(o,3));
  delay(100);
}

Мигает светодиодами на ногах 4,5,6,7, 13й(на плате) показывает состояние переменной m, которая меняется нажиманием кнопки(дребезг, в данном случае, не критичен, т.к. мы видим состояние)

цикл выполняется f раз, за один проход "крутит" светодиоды в одну или в другую сторону, при переключении сначало "докручивает цикл и только потом меняет направление (отрабатывает switch). Возможен ли такой вариант реализации, при которой будет проверять switch сразу при срабатывании прерывания не докручия for?

Radjah, рис с гречкой, в данном случе, неуместны, т.к. я не вижу проблему в работе программы, в то время как вкусовые ощущения от продуктов я различаю.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

BoBo4kA пишет:

 Возможен ли такой вариант реализации, при которой будет проверять switch сразу при срабатывании прерывания не докручия for?

Вы изначально строите алгоритм недружелюбный к быстрой смене функции. Тем не менее можно сделать то, о чём вы говорите не переписывая всё с ноля. Сделайте переменную i глобальной. уберите "int" из циклов. В void mm() добавьте строку i=f; После этого нажатие кнопки будет запускать другую программу почти мгоновенно.

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

Идею понял, спасибо! )

BoBo4kA
Offline
Зарегистрирован: 15.01.2016

Возникла другая проблема дальше, но её удалось решить, способ, предложенный dimax'ом помог.

Проблема была в том, что в switch/case есть другой for, который запускался и вызывал задержку, решение в выделении отдельных переменных под каждый for case'a

bool m = 1;
byte o = B0000;
int f = 10;
int i = 0;
int j = 0;

void setup() {
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
pinMode(2, INPUT);
digitalWrite(2, HIGH);
attachInterrupt(0, mm, FALLING);
}

void loop() {
  i=0;
  j=0;
  switch (m){
  case 0:
    for(i=i; i<f; i++){f1();}
    for(j=j; j<f; j++){f3();}
    break;
  case 1:
    for(i=i; i<f; i++){f2();}
    for(j=j; j<f; j++){f4();}
    break;
   }
}

void mm(){
  m=!m;
  digitalWrite(13,m);
  i=f;
  j=f;
}

void f1(){
  o = B0001; s();
  o = B0010; s();
  o = B0100; s();
  o = B1000; s();}

void f2(){
  o = B1000; s();
  o = B0100; s();
  o = B0010; s();
  o = B0001; s();}

void f3(){
  o = B0011; s();
  o = B0110; s();
  o = B1100; s();
  o = B1001; s();}

void f4(){
  o = B1100; s();
  o = B0110; s();
  o = B0011; s();
  o = B1001; s();}

void s(){
  digitalWrite(4, bitRead(o,0));
  digitalWrite(5, bitRead(o,1));
  digitalWrite(6, bitRead(o,2));
  digitalWrite(7, bitRead(o,3));
  delay(100);}

 

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

BoBo4kA пишет:

Разницы я не заметил, как определить переменную, и, исходя из описания прерываний, счёл данный параметр не нужным, т.к. переменная меняется не только в функции прерывания(этого не видно в привиденном коде). Если подскажите, в чем разница, буду благодарен.

Запомните раз и навсегда, если какая-либо переменная изменяется в обработчике прерываения, её нужно объявлять c volatile. Не важно, меняется ли эта переменная где-то ещё. Если сомневаетесь - информации в интернете достаточно, найдите и почитайте.