Прерывания в классе

vlad072
Offline
Зарегистрирован: 01.08.2017

Нужно отследить сигнал от датчика удара. Во время удара на порты D2 (сильный удар) и D3 (слабый удар) постуавют серии коротких частых импульсов нулевого потенциала. Решил оформить это дело в следующейм объекте:

class Shock {
  private:
    static volatile byte _st;
    static void hi() {
      detachInterrupt(0);
      _st = 2;
    }
    static void lo() {
      detachInterrupt(1);
      _st |= 1;
    }
  public:
    oid reset_() {
    _st = 0;
    attachInterrupt(0, hi, FALLING);
    attachInterrupt(1, lo, FALLING);
    }
    void disable() {
      detachInterrupt(0);
      detachInterrupt(1);
    }    
    byte state() {
    if (_st == 1) 
      for (int _t = millis()+100; _t > millis();)
        if (_st > 1) return 2;
    if (_st > 2) _st = 2;
    return _st;
    }
};
Shock shock;

Что бы не пропустить сигнал повесил на порты прерывания. В main() проверяю не сработал ли датчик вызывая метод shock.state(), затем после обработки (длительное время - десятки секунд) позвращаю объект в мсходное состояние методом shock.reset().

Пробдема 1: Компилятор ругаетсяна "несуществующую переменную shock::_st, которая объявлена вполне себе корректно. Вынес переменную в глобвльные, скомпилилось, по вылезла

Проблема 2: При слабых ударах всё работает коректно, но если удар довольно сильный (много импульсов на обоих портых), цикл main() зависает на в двух вариантах: а) на неопределённое время, риздупляется без внешних воздействий через N-ное количество секунд/минут и б) до следующего (не обязательно первого, бывает и третьего и десятого) сильного удара (длительной серии множественных импульсов на портах).

Кто подскажет решение проблем?

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vlad072 пишет:

Кто подскажет решение проблем?

Никто, пока не будет полного кода. Как описана _st? Что делается в прерывании? Сколько экземпляров класса создаётся? Всё секретно!

Сделайте короткий, но полный (запускабелтный) код в котором проблема проявляется. Тогда моно будет говорить.

Пока же могу только предположить, что у Вас два эземпляра объекта, так? А переменная _st одна, хотя по логике у каждого экземпляра должна быть совя. Вот экземпляры и гадят друг другу.

vlad072
Offline
Зарегистрирован: 01.08.2017

И переменная и обработчики прерываний описаны в листинге выше. Экземпляр конечно же один (тоже в листинге).

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Зачем вводить прерывание в класс. Сделайте отдельно. Обработчик конкретного прерывания дергает определеный метод определеного класса. И все.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Виноват, не заметил. Но код всё равно нужен, я хочу его запустить и увидеть проблему сам.

Да, кстати, код в строке №24 чреват ошибкой при переходе значения миллис через 0.

vlad072
Offline
Зарегистрирован: 01.08.2017
//....................................

class Shock {
  private:
    static volatile byte _st; // переменная хранения состояния
    static void hi() {        // обработчик сильного удара
      detachInterrupt(0);
      _st = 2;
    }
    static void lo() {        // обработчик слабого удара
      detachInterrupt(1);
      _st |= 1;
    }
  public:
    void reset() {             // перезапуск слежения за датчиком с обнулением состояния
      _st = 0;
      attachInterrupt(0, hi, FALLING);
      attachInterrupt(1, lo, FALLING);
    }
    void disable() {    // отключить датчик удара
      detachInterrupt(0);
      detachInterrupt(1);
    }    
    byte state() {      // возвращает текеущее состояние
    if (_st == 1) 
      for (int _t = millis()+100; _t > millis();) // после получения сигнала о слабом ударе
        if (_st > 1) return 2;                    //  100мс ждём сигнала о сильном,поскольку в любом случае
                                                  // сигнал сначала появляется на "слабом" ПИНе
    if (_st > 2) _st = 2;
    return _st;
    }
};
Shock shock;

//..........................................

void main() {
//..........................................
  byte shockState = shock.state();
  if (shockState != 0) {
    dispatchAlert("shock", shockState );
    shock.reset();
  }
//..........................................
} // end main
//........................................
dispatchAlert(String msg, byte param ) {
  // позвонить мне на мобилу, сказать что был удар и транслировать
  // звук с микрофона на объекте, пока я не положу трубку
}

 

vlad072
Offline
Зарегистрирован: 01.08.2017

qwone пишет:

Зачем вводить прерывание в класс. Сделайте отдельно. Обработчик конкретного прерывания дергает определеный метод определеного класса. И все.

Что бы разгрузить "основной" код программы, ибо там уже сам чорт ногу сломит

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

vlad072 пишет:
Что бы разгрузить "основной" код программы, ибо там уже сам чорт ногу сломит

Если у вас в квартире бардак, то сходите в гости и сделаете там тоже, что и дома. То что Вы делаете не разгружает, а загружает код еще больше.

vlad072
Offline
Зарегистрирован: 01.08.2017

qwone пишет:

vlad072 пишет:
Что бы разгрузить "основной" код программы, ибо там уже сам чорт ногу сломит

Если у вас в квартире бардак, то сходите в гости и сделаете там тоже, что и дома. То что Вы делаете не разгружает, а загружает код еще больше.

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
class Cl_AAA {
  public:
    void bim() {}
    void bom() {}
};
Cl_AAA AAA;
void bim() {
  AAA.bim();
}
void bom() {
  AAA.bom();
}
//------------------
void setup() {
  attachInterrupt(0, bim, CHANGE);
  attachInterrupt(1, bom, CHANGE);
}

void loop() {

}
/**/

Через классы код будет похожим, только здесь получится static методы класса

class Cl_AAA {
  public:
    static void bim() {}
    static void bom() {}
    static void init() {
      attachInterrupt(0, bim, CHANGE);
      attachInterrupt(1, bom, CHANGE);
    }
};
Cl_AAA AAA;

//------------------
void setup() {
  AAA.init();
}

void loop() {

}
/**/

 

vlad072
Offline
Зарегистрирован: 01.08.2017

ЕвгенийП пишет:

код в строке №24 чреват ошибкой при переходе значения миллис через 0.

Очень похоже кстати на проблемы с таймером, поскольку тот же диод индикации включенной охранки в основном цикле перстаёт мигать:

void main() {
//..............
  led.set( armed && ((millis() & 0x3ff) > 0x370) );
//............

Можно подробней, что Вы имели в виду?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vlad072 пишет:

Можно подробней, что Вы имели в виду?

http://arduino.ru/forum/programmirovanie/velikoe-perepolnenie-millis

vlad072
Offline
Зарегистрирован: 01.08.2017

Интересное "расследование", положу в копилку )) У меня таких участков кода полно, причём довольно кричичных, например чреватых пожаром. А свою проблему я кажется увидел сам, завтра проверю. Ёмаё, прямо навиду она и никто не обратил внимания. Какой же millis() к чёрту int, это же unsigned long, или dword как я его для себя по привычке переопределяю. И компилятор промолчал же гад.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

У вас просто слишком много прерываний возникает, вы об этом не думали? На каждый фронт - прерывание.

vlad072
Offline
Зарегистрирован: 01.08.2017

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