Работа attachInterrupt

Protas
Offline
Зарегистрирован: 18.03.2018

Здравствуйте подскажите можно ли вообще в данном коде реализовать сигналы после "case 45...360" длинной 10 секунд каждый? В этом коде получается, что delay вообще не работает, я так понимаю из-за attachInterrupt. Но всеже может можно как-то реализовать сигнал 10 секунд?

volatile boolean flag;
volatile unsigned int val;

void setup() {
 Serial.begin (115200);
 pinMode (2, INPUT_PULLUP);
 pinMode (3, INPUT_PULLUP);
 pinMode (13, OUTPUT);
 attachInterrupt (1, start, FALLING); 
 val=0;
}

void loop() {
 if (flag) {
  encoder ();
  
  //delay (500);
 }
}
void start () {
  flag = 1;
  }

void encoder () {
   attachInterrupt (0, scet, FALLING);
        }
void scet () {
     
    if (val >= 0 && val <= 360){
        val++; 
     switch (val) {
      case 10: Serial.println ("Metka_2");
      sig();
      Serial.println ("RABOTA_2");
      break;
      case 90: Serial.println ("Metka_3");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 135: Serial.println ("Metka_4");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 180: Serial.println ("Metka_1");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 225: Serial.println ("Metka_2");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 270: Serial.println ("Metka_3");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 315: Serial.println ("Metka_4");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 360: Serial.println ("Metka_1");
      sig();                                       // тут надо сигнал 10 секунд
      Serial.println ("RABOTA_1");
      break;
    } 
    
    Serial.println(val);
   
 }
   else {
       val=0;
        scet ();
 }
}

void sig () {
  digitalWrite (13, HIGH);
      delay (10000);
      Serial.println ("10_sek");
      digitalWrite (13, LOW);
}

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Сигнал 10 секунд (и даже больше) реализовать можно. 

Но, разумеется, не следует пихать его внутрь прерывания.

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

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Возьмите  за правило внутри функции обработчика прерывания не работают не delay ни millis. Сам обработчик scet должен быть как можно короче всмысле проделанной работы

Protas
Offline
Зарегистрирован: 18.03.2018

Спасибо) А как правильно вынести ( куда писать код ). 

P.S. Только сильно не пинайте!

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukommentarii

Учитесь на здоровье

Извиняйте не понял. Подождите объяснят

Protas
Offline
Зарегистрирован: 18.03.2018

Спасибо за ссылку, но я имел ввиду свой код в #1 посте. как правильно написать сигнал в коде, что бы он небыл в прерывании?

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Вот эта часть кода в обработчике не нужна

switch (val) {
      case 10: Serial.println ("Metka_2");
      sig();
      Serial.println ("RABOTA_2");
      break;
      case 90: Serial.println ("Metka_3");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 135: Serial.println ("Metka_4");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 180: Serial.println ("Metka_1");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 225: Serial.println ("Metka_2");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 270: Serial.println ("Metka_3");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 315: Serial.println ("Metka_4");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 360: Serial.println ("Metka_1");
      sig();                                       // тут надо сигнал 10 секунд
      Serial.println ("RABOTA_1");
      break;
    } 

У вас много повторяющихся фрагментов и "лишнмх" условий 

Думаю достаточно

 

if (val = n) Serial.print ("Metka_");  Serial.println("m");
      sig();

char m - символ(0,1,2) , n - текущее значение val

 

Protas
Offline
Зарегистрирован: 18.03.2018

Спасибо, но все же мне нужен сигнал 10 секунд при определенных значениях val. Как его сделать?

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Посмотрите, attachInterrupt объявляется в setup. В мраке функций надо отыскать свет :) Да и #1

volatile boolean flag = 0;
volatile unsigned int val = 0;

void setup() {
 Serial.begin (115200);
 pinMode (2, INPUT_PULLUP);
 pinMode (3, INPUT_PULLUP);
 pinMode (13, OUTPUT);
 attachInterrupt (0, scet, FALLING);
 attachInterrupt (1, start, FALLING); 

}

void loop() {
  if (flag) 
  {
    encoder(); // произошло прерывание
    flag = 0; // не забываем опустить флаг
  }

}

void start () {
  flag = 1;
}

void encoder () {
  // как бы разрешаеш выполняться тому что в scet
}

void scet () {
     
    if (val >= 0 && val <= 360){
        val++; 
     /*switch (val) {
      case 10: Serial.println ("Metka_2");
      sig();
      Serial.println ("RABOTA_2");
      break;
      case 90: Serial.println ("Metka_3");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 135: Serial.println ("Metka_4");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 180: Serial.println ("Metka_1");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 225: Serial.println ("Metka_2");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 270: Serial.println ("Metka_3");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 315: Serial.println ("Metka_4");
      sig();                                       // тут надо сигнал 10 секунд
      break;
      case 360: Serial.println ("Metka_1");
      sig();                                       // тут надо сигнал 10 секунд
      Serial.println ("RABOTA_1");
      break;
    } */
    
    Serial.println(val);
   
 }
   else {
       val=0;
        scet ();
 }
}

// тут нужна совсем другая конструкция
void sig () {
  digitalWrite (13, HIGH);
      //delay (10000);
      Serial.println ("10_sek");
      digitalWrite (13, LOW);
}

 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Расскажите подробно как вы хотите чтобы работал ваш код. Подозреваю что у вас 2 кнопки на пинах 2, 3 подтянуты к питанию. Сигнал 10 секунд можно вынести в отдельный блок и сделать с помощью millis

Protas
Offline
Зарегистрирован: 18.03.2018

Да, Вы правы, у меня 2 кнопки - это имитация энкодера. Т.е. при нажатии кнопки на пине 3, дуина начинает считать импульсы с энкодера ( их 360 за оборот) по пину 2, а при достяжении углов 10, 90, 135, 180, 225, 270, 315 и 360 (0) должны быть сформированны сигналы каждый по 10 секунд, но счет энкодера не должен прекращаться.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

То есть нажали одну и через время другую на 3 пине и процесс пошел? Сигнал - это загорелся на 10 секунд светодиод на 13 пине и затем по окончании счета потух верно?

 

Protas
Offline
Зарегистрирован: 18.03.2018

Кнопка на пине 3 - старт отсчета импульсов с энкодера ( в данный момент у меня не энкодер а просто кнопка, как иммитация энкодера)

Кнопка на пине 2 - считывает импульсы с экодера ( в данный момент с кнопки)

При приходе (пример) 10-ого импульса - загорается 13 led pin на 10 секунд, но в это самое время счет продолжается, и при появлении 90-ого импулься 13 led pin снова загорается на 10 секунд. И так пока не перестанешь клацать на кнопку (т.е. пока энкодер не остановит свое вращение)

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Ясно, сегодня я уже вам не помогу. Вам еще нужно доработать код чтобы все было на своих местах. И еще попробуйте вначале сделать проще проверить со значением val допустим 10 идет или не идет сигнал. Затем уже делайте отдельную функцию, case там правде лишний

Protas
Offline
Зарегистрирован: 18.03.2018

В том-то и дело что сигнал идет на 13 пин, но длинна его зависит от времени между импульсами 10 и 11. Т.е. медленее нажимать на кнопку на 2 пине, то 13 пин горит дольше и наоборот)) Т.е. если поставить энкодер, то при его вращении длина импульса на 13 пине будет зависить от скорости вращения энкодера. 

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014
Не совсем понял про длину импульса - так как у Вас сигнал на 13м пине (согласно первого поста) стоит строго 10 секунд и нигде не вижу считывания длины импульса!
По поводу вопроса в начале темы - могу предложить такую правку
volatile boolean flag;
volatile unsigned int val;

void setup() {
  Serial.begin (115200);
  pinMode (2, INPUT_PULLUP);
  pinMode (3, INPUT_PULLUP);
  pinMode (13, OUTPUT);
  attachInterrupt (1, start, FALLING);
  attachInterrupt (0, scet, FALLING);
  val = 0;
}

void loop() {
  if (flag) {
    scet2 ();
  }
}

void start () {
  flag = 1;
}

void scet () {
  if (flag)
  {
    val++;
  }
}

void scet2 () {
  if (val >= 0 && val <= 360) {
    switch (val) {
      case 10: Serial.println ("Metka_2");
        sig();
        Serial.println ("RABOTA_2");
        break;
      case 90: Serial.println ("Metka_3");
        sig();                                       // тут надо сигнал 10 секунд
        break;
      case 135: Serial.println ("Metka_4");
        sig();                                       // тут надо сигнал 10 секунд
        break;
      case 180: Serial.println ("Metka_1");
        sig();                                       // тут надо сигнал 10 секунд
        break;
      case 225: Serial.println ("Metka_2");
        sig();                                       // тут надо сигнал 10 секунд
        break;
      case 270: Serial.println ("Metka_3");
        sig();                                       // тут надо сигнал 10 секунд
        break;
      case 315: Serial.println ("Metka_4");
        sig();                                       // тут надо сигнал 10 секунд
        break;
      case 360: Serial.println ("Metka_1");
        sig();                                       // тут надо сигнал 10 секунд
        Serial.println ("RABOTA_1");
        break;
    }
    Serial.println(val);
  }
  else {
    val = 0;
    //scet ();
  }
}

void sig () {
  digitalWrite (13, HIGH);
  delay (10000);
  Serial.println ("10_sek");
  digitalWrite (13, LOW);
}

 

 

Protas
Offline
Зарегистрирован: 18.03.2018

Vosara, спасибо огромное, код заработал как надо!

nik182
Offline
Зарегистрирован: 04.05.2015

Можно короче и без delay.

volatile unsigned int flag=0;
volatile unsigned int val=0;
volatile unsigned int val_const[7]={90,135,180,225,270,305,360};
volatile unsigned long time_off,currentMillis,startTime;
volatile unsigned long currentMillis1,startTime1;

void setup() {
 Serial.begin (115200);
 pinMode (2, INPUT_PULLUP);
 pinMode (3, INPUT_PULLUP);
 pinMode (13, OUTPUT);
 currentMillis1=startTime1=millis();
}

void scet () {
  val++; 
  for (byte i=0;i<7;i++) if (val_const[i]==val) {time_off+=5000; break;};       
  if ( val > 360) val=0; 
}
void loop() {
 switch (flag) { 
  case 0 : if (digitalRead(3)==LOW) { flag = 1; attachInterrupt (0, scet, FALLING);}; break; 
  case 1 : if (val > 9) { flag =2; digitalWrite(13,HIGH); time_off=5000;startTime=millis();}; break; 
  case 2 : if (((currentMillis = millis()) - startTime) > time_off) {flag=0; digitalWrite(13,LOW); detachInterrupt (0); val=0;}; break; 
 }
// if (((currentMillis1 = millis()) - startTime1) > 1000) { Serial.println (val);Serial.println (time_off); startTime1=currentMillis1;}; 
}