Arduino зависает при использовании прерываний на энкодер

lennen
Offline
Зарегистрирован: 10.11.2015
Это стоит в Loop:

//Обработка энкодера
  rotating = true;                                              // reset the debouncer
  
  // Print changes
  if (lastReportedPos != encoderPos) {                          // verify if encoder position has changed
    Serial.print(F("Position: "));
    int tem = (encoderPos % 16);
    //Serial.println(encoderPos % 16, DEC);                       // print counter for the dial (values 0..15)
    Serial.println(tem);
    lastReportedPos = encoderPos;                               // update new position
    if(tem>1 and tem <17) 
    {Speed_of_rotation = Speed_of_rotation - tem;}
  }

  if (millis() - timing > Speed_of_rotation){ // Вместо 10000 подставьте нужное вам значение паузы 
  timing = millis();
      
  // ----- has the display asked for data
  //if (Serial.available() > 0)
  //{
  //  Char = Serial.read();               // read character

    // ----- send data to display whenever a send character ('S') is received
    //if (Char == 'S')
    //{
      // ----- measure distances
      measure();


      // ----- rotate beam to next ping position
      rotate();

     // ----- send the results to the display
      //Serial.print(Azimuth);
      //Serial.print(',');
      //Serial.print(Distance1);
      //Serial.print(',');
      //Serial.print(Distance2);
      //Serial.print(',');
      //Serial.println(Direction);

      softSerial.print("a:");
      softSerial.print(Azimuth);
      softSerial.print(";");
      softSerial.print(Distance1);
      softSerial.print(";");
      softSerial.print(Distance2);
      softSerial.print(";");
      softSerial.println(Direction);

      //Вывод расстояния на светодиоды
      leds(Distance1);
}
     

   
  Использую порты 2 и 3 и библиотеку для энкодера KY-40      
 
pinMode(encoderPinA, INPUT_PULLUP);
  pinMode(encoderPinB, INPUT_PULLUP);
  pinMode(clearButton, INPUT_PULLUP);

  // Encoder pins on interrupt
  attachInterrupt(digitalPinToInterrupt(encoderPinA), doEncoderA, CHANGE);
  attachInterrupt(digitalPinToInterrupt(encoderPinB), doEncoderB, CHANGE);

 

Программа исправно работает, пока не начинаешь вращать энкодер. Начал - программа зависла. С чем может быть связано? Я читал, что с Delay или millis могут быть проблемы, но не понял, все же, что мешает программе выполняться и как это исправляется.

lennen
Offline
Зарегистрирован: 10.11.2015
Файл прерывания прилагается. Суть в том, что энкодер сначала работает, а зависать начинает только на некотором моменте, но это происходит всегда, программа виснет.

// ***************************************************************
// This implementation based on  
// "Another Interrupt Library THAT REALLY WORKS" by rafbuff
// http://playground.arduino.cc/Main/RotaryEncoders 

// interrupt service routine vars
bool A_set = false;
bool B_set = false;

// ***************************************************************

// Interrupt on A changing state
void doEncoderA() {
  // debounce
  if ( rotating ) delay (1);                  // wait a little until the bouncing is done

  // Test transition, did things really change?
  if ( digitalRead(encoderPinA) != A_set ) {  // debounce once more
    A_set = !A_set;

    // adjust counter + if A leads B
    if ( A_set && !B_set ) encoderPos += 1;

    rotating = false;  // no more debouncing until loop() hits again
  }
}

// ***************************************************************

// Interrupt on B changing state, same as A above
void doEncoderB() {
  if ( rotating ) delay (1);                  // wait a little until the bouncing is done

  if ( digitalRead(encoderPinB) != B_set ) {  // debounce once more
    B_set = !B_set;
    
    //  adjust counter - 1 if B leads A
    if ( B_set && !A_set ) encoderPos -= 1;

    rotating = false;  // no more debouncing until loop() hits again
  }
}

// ***************************************************************

 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Сделайте миниманьльный скетч воспроизводящий вашу проблему. И приведите его целиком. Что бы можно было откомпилировать и попробовать.

А вообще, я не исповедую учение гласящее "никогда не используйте delay()", иногда его использование вполне допустимо. Но delay() в прерывании.... Это очень, очень плохая идея.

sadman41
Offline
Зарегистрирован: 19.10.2016

1) delay() использует для подсчета времени micros()
2) micros() читает значение системной переменной timer0_overflow_count.
3) timer0_overflow_count изменяется по прерыванию таймера #0
4) при выполнении обработчика прерывания другие прерывания не обслуживаются.

В Interrupt handler doEncoderA или doEncoderB timer0_overflow_count - не меняется, micros() возвращает одно и то же значение, delay() никогда не завершается.