Прерывания по таймеру и спящий режим

ermvad
Offline
Зарегистрирован: 25.11.2015

Всем привет. Делая проект столкнулся с трудностями.

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

 

Весь код:

#include <OneWire.h>
#include <DallasTemperature.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/power.h>
#define ONE_WIRE_BUS 10
OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

int i = 2;
int Tmax=50, Tmin=51;
String cmd;

struct Tsensor {
  public:
    uint8_t* Taddress;
    float T;
    void Measure(){
      sensors.requestTemperatures();
      T = sensors.getTempC(Taddress);
      Serial.print(" sensor temp: ");
      Serial.println(T);
    }
    Tsensor(uint8_t a[]): Taddress(a) {}
};

struct Relay {
  public:
    bool stat;
    int pin;
    Relay(bool s, int p) {
      stat = s;
      pin = p;
    }
};

struct Cam {
  public:
    String cmd;
    bool CamFlag;
    int pin;
    int wakeup_period;
    int Timer_WD;
    int Timer_Rep;
    void CamPowerON(){
      if(CamFlag){
        digitalWrite(pin,LOW);
        delay(10000);
        digitalWrite(pin,HIGH);
        Timer_WD=180;
        CamFlag=1;
      }
    }
    void CamPowerOFF(){
      delay(10000);
      CamFlag=0;
      digitalWrite(pin,LOW);
    }
    void DecrementTimers(){
      Timer_WD--;
      //Timer_Rep--;
    }
    void ReadCMD(){
      if (Serial.available()) {
        cmd = Serial.readString();
        if (cmd == "SET_WATCHDOG") {Serial.println(cmd);}
        else if (cmd == "POWEROFF") {Serial.println(cmd);}
        else if (cmd == "CHECKBATTERY") {Serial.println(cmd);}
        else if (cmd == "SET_TIMER") {Serial.println(cmd);}
        else if (cmd == "CHECK_TIMER") {Serial.println(cmd);}
        else if (cmd == "SET_WAKEUP_PERIOD") {Serial.println(cmd);}
        else if (cmd == "SINCHRONIZE_TIMER") {Serial.println(cmd);}
        else if (cmd == "SET_MIN_BATTERY") {Serial.println(cmd);}
        else if (cmd == "RESET_WATCHDOG") {Serial.println(cmd);}
        else if (cmd == "CHECK_WATCHDOG") {Serial.println(cmd);}
        else if (cmd == "SET_FIRST_WATCHDOG") {Serial.println(cmd);}
        else if (cmd == "POWERDOWN_BATTERY") {Serial.println(cmd);}
        else if (cmd == "CHECK_FIRST_WATCHDOG") {Serial.println(cmd);}
        else if (cmd == "CHECK_FLAG") {Serial.println(cmd);}
        else if (cmd == "CHECK_WAKEUP_PERIOD") {Serial.println(cmd);}
        else if (cmd == "SET_MIN_BAT_L") {Serial.println(cmd);}
        else if (cmd == "SET_MIN_BAT_H") {Serial.println(cmd);}
        else if (cmd == "SET_START_BAT_LEV") {Serial.println(cmd);}
      }
    }
    Cam(){
      Timer_WD=180;
      pin=7;
    }
};

uint8_t f[2][8] = {{0x28, 0xFF, 0x79, 0x54, 0x71, 0x15, 0x01, 0x09}, {0x28, 0xFF, 0xC2, 0x63, 0x74, 0x15, 0x03, 0x71}};
Tsensor ThermalSensor[2] = {f[0], f[1]};
Relay OptRelay[2] = {{false, 5}, {false, 6}};
Cam Camera;

/*void Measure(){
  for(i=0;i<2;i++){
    sensors.requestTemperatures();
    ThermalSensor[i].T = sensors.getTempC(ThermalSensor[i].Taddress);
    Serial.print(" sensor temp: ");
    Serial.println(ThermalSensor[i].T);
  }
}*/

void HeatingCheck() {
  for (i = 0; i < 2; i++) {
    if (ThermalSensor[i].T < Tmin && OptRelay[i].stat == false) {
      digitalWrite(OptRelay[i].pin, LOW);//on
      OptRelay[i].stat == true;
    }
    if (ThermalSensor[i].T > Tmax && OptRelay[i].stat == true) {
      digitalWrite(OptRelay[i].pin, HIGH);//off
      OptRelay[i].stat == false;
    }
  }
}
void setup() {
  cli();   
  TCCR1A = 0; 
  TCCR1B = 0;
  TIMSK1 |= (1 << TOIE1);
  TCNT1=0x0BDC;
  TCCR1B |= (1 << CS12);
  sei();
  Serial.begin(9600);
  sensors.begin();
  for (i = 0; i < 2; i++) {
    sensors.setResolution(ThermalSensor[i].Taddress, 9);
    pinMode(OptRelay[i].pin, OUTPUT);
    digitalWrite(OptRelay[i].pin, HIGH); //change
  }
}
ISR(TIMER1_OVF_vect){
  for(i=0;i<2;i++){
    ThermalSensor[i].Measure();
  }
  //HeatingCheck();
  Camera.DecrementTimers();
  //Camera.ReadCMD();
  Serial.print("WD "); Serial.println(Camera.Timer_WD);
}
void loop() {
}

 

Что интересует меня:

ISR(TIMER1_OVF_vect){
     Декремент;
     Кусок некого кода
}

 

ermvad
Offline
Зарегистрирован: 25.11.2015

Пробовал использовать MsTimer2 и пихать туда set_sleep_mode - в итоге и луп крутится и прерывание работает

axill
Offline
Зарегистрирован: 05.09.2011

во первых чтобы МК засыпал в loop() надо вставить команды на засыпание в режим IDLE

во вторых такие тяжелые функции как Serial.print нельзя ставить внутри обработчиков прерываний иначе у вас начнутся пропуски событий и поломкой всей логики

в третьих вы использовали обычный режим таймера, кто за вас будет грузить нужное значение в счетчик TCNT1? В таком МК как мега328 для вашей задачи есть специальный режим CTC, нужное значение счетчика грузится в OCR1 один раз, обработчик делается не на OVF, а на COMPA

ermvad
Offline
Зарегистрирован: 25.11.2015

axill, списибо за ответ. Я читал про режим СТС на забугорном форуме, попробую применить. Хм, а можно использовать библиотеку MsTimer2 для упрощения, или все таки регистрами оперировать? Как я понял в луп надо засунуть это:

set_sleep_mode(SLEEP_MODE_PWR_SAVE);   // sleep mode is set here

   sleep_enable();          // enables the sleep bit in the mcucr register
                            // so sleep is possible. just a safety pin

   sleep_mode();            // here the device is actually put to sleep!!
                            // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP

   sleep_disable();