Прерывания по таймеру и спящий режим
- Войдите на сайт для отправки комментариев
Ср, 25/11/2015 - 20:58
Всем привет. Делая проект столкнулся с трудностями.
Есть прерывания по таймеру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){
Декремент;
Кусок некого кода
}
Пробовал использовать MsTimer2 и пихать туда set_sleep_mode - в итоге и луп крутится и прерывание работает
во первых чтобы МК засыпал в loop() надо вставить команды на засыпание в режим IDLE
во вторых такие тяжелые функции как Serial.print нельзя ставить внутри обработчиков прерываний иначе у вас начнутся пропуски событий и поломкой всей логики
в третьих вы использовали обычный режим таймера, кто за вас будет грузить нужное значение в счетчик TCNT1? В таком МК как мега328 для вашей задачи есть специальный режим CTC, нужное значение счетчика грузится в OCR1 один раз, обработчик делается не на OVF, а на COMPA
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();