Режим Sleep и пробуждение

M@@}{

✩✩✩✩✩✩✩
5 Май 2021
7
0
Доброго времени суток Уважаемые Форумчане.

Пишу программу (сигнализатор событий, а проще говоря простенькую сигнализацию) под Arduino PRO mini.
На борту платы модем и датчик на размыкание.
Пока плата питается от LiIon, далее сделаю нормальное питание. (Но питание от батареи должно быть предусмотрено).
У контроллера есть 2 режима работы
1) нормальный, при возникновении события происходит звонок
2) режим глубокого сна, контроллер принимает только команды от модема

Реализовать такой режим работы я попытался отключением прерывания INT1 (на которое приходит сигнал о разрыве цепи )

так вот проблема с которой я столкнулся: контроллер при отключении прерывания INT1 и уходе в сон все равно просыпается при изменении состояния на ноге D3 (INT0) но подпрограмму обработки прерывания алгоритм не заходит. Скорее всего это прерывание (пробуждение) вызвано прерываниями "PCINT" (которые мало известны в среде IDE) попытки отключить прерывания "PCINT" не увенчались успехом.
В примере сделана вырезка отвечающая за работу режима Sleep
Я пытался использовать стандартные библиотеки IDE и библиотеку GyverPower.h, результат один и тот же.
помогите разобраться что я делаю не так. где моя ошибка?
необходимо чтобы при отключенном прерывании INT1 и изменению состоянии ноги D3 контроллер спал.

режим SLEEP:
#include <SoftwareSerial.h>
#include <GyverPower.h>
//#include <avr/sleep.h>
//#include <avr/power.h>

#define RINGPIN 2
#define DTRPIN 6
#define RSTPIN 9
#define DETECTPIN 3
#define RX_PIN 4
#define TX_PIN 5
#define DETECTLEVELDP CHANGE                        // уровень детекции пина 3 рост/падение RISING
//RISING (рост) – срабатывает при изменении сигнала на пине с LOW на HIGH
//FALLING (падение) – срабатывает при изменении сигнала на пине с HIGH на LOW
#define DETECTLEVEL HIGH                            // настраиваем с чем сравнимать детекцию идет в комплекте с предыдущим параметром DETECTLEVELDP CHANGE
//#define TIME_COUNT_BEFORE_SLEEP 55000               // 55 сек
#define TIME_COUNT_BEFORE_SLEEP 10000               // 10 сек
volatile boolean intFlagRing = false;               // флаг входящего сообщения от модема
volatile boolean intFlagDetect = false;             // Флаг сообщения на RINGPIN (2 нога)
volatile unsigned long interputPINtime;             // время для иключения дребезга на входе DETECTPIN
volatile unsigned long TimeCountBeforeSleep;        // время покоя модуля преред переходом в спящий режим (сон)
char inSerial[40];
int i = 0;

SoftwareSerial SerialModem(RX_PIN, TX_PIN); // RX, TX

void setup() {

  pinMode(DETECTPIN, INPUT_PULLUP);                 // 3 нога внешнее прерывание INPUT
  pinMode(RINGPIN, INPUT);                          // GSM Ring
  pinMode(LED_BUILTIN, OUTPUT);                     // диод
  digitalWrite(RINGPIN, HIGH);                      // RING включили подтягивающий резистор
  digitalWrite(LED_BUILTIN, HIGH);                  // зажигаем светодиод
  //set_sleep_mode(SLEEP_MODE_STANDBY);             // Определяем режим сна SLEEP_MODE_STANDBY
  //set_sleep_mode(SLEEP_MODE_PWR_DOWN);            // Определяем режим сна SLEEP_MODE_PWR_DOWN

  power.hardwareDisable(PWR_ADC | PWR_TIMER1); // см раздел константы в GyverPower.h, разделяющий знак " | "

  power.setSleepMode(POWERDOWN_SLEEP);
  power.bodInSleep(false); // рекомендуется выключить bod во сне для сохранения энергии (по умолчанию false - выключен!!)

  // открываем последовательный порт для мониторинга действий в программе
  Serial.begin(9600);
  while (!Serial) {
  }

  SerialModem.begin(9600);
  while (!SerialModem) {
  }
  Serial.print("Serial all init OK\r\n");
  PCICR  |= (0 << PCIE2) | (0 << PCIE1) | (0 << PCIE0); // отключение периваний Pin Change Interrupts, PCINT
  PCMSK0 |= (0 << PCINT7)  | (0 << PCINT6)  | (0 << PCINT5)  | (0 << PCINT4)  | (0 << PCINT3)  | (0 << PCINT2)  | (0 << PCINT1)  | (0 << PCINT0);
  PCMSK1 |= (0 << PCINT14) | (0 << PCINT13) | (0 << PCINT12) | (0 << PCINT11) | (0 << PCINT10) | (0 << PCINT9)  | (0 << PCINT8);
  PCMSK2 |= (0 << PCINT23) | (0 << PCINT22) | (0 << PCINT21) | (0 << PCINT20) | (0 << PCINT19) | (0 << PCINT18) | (0 << PCINT17) | (0 << PCINT16);

  printReg();
  delay(50);
  EnableDisableWork(true);
  interputPINtime = millis();
  TimeCountBeforeSleep = millis();
}

void printReg() {
  Serial.print(F("wakeUp PCIFR - "));
  Serial.print(PCIFR, BIN);
  Serial.print(F("; PCICR - "));
  Serial.print(PCICR, BIN);
  Serial.print(F("; PCMSK0 - "));
  Serial.print(PCMSK0, BIN);
  Serial.print(F("; PCMSK1 - "));
  Serial.print(PCMSK1, BIN);
  Serial.print(F("; PCMSK2- "));
  Serial.print(PCMSK2, BIN);
  Serial.println(F("; "));
}

void wakeUpM() { //пришло прерывание отключаем прерываня от модема, назбудить надо дальше
  detachInterrupt(digitalPinToInterrupt(RINGPIN)); //Отключаем прерывания от модема
  // проверяем что сработало и ставим флаг
  if (digitalRead(RINGPIN) == HIGH) intFlagRing = true;
  if (digitalRead(DETECTPIN) == DETECTLEVEL) intFlagDetect = true ;
}

void EnableDisableWork(bool in)
{ //включение выключение прерывание, для включения и выключения радочего режима
  Serial.print(F("EnableDisableWork "));
  if (in == true) {//wakeUpM
    attachInterrupt(digitalPinToInterrupt(DETECTPIN), wakeUpM, DETECTLEVELDP); //Если на 1-вом прерываниии - DETECTLEVELDP, то событие.
    //attachInterrupt(digitalPinToInterrupt(DETECTPIN), interputPin, DETECTLEVELDP); //Если на 1-вом прерываниии - DETECTLEVELDP, то событие.
    interputPINtime = millis(); // сохранили время для исключения дребезга
    Serial.println(F(" true. "));
  } else {
    detachInterrupt(digitalPinToInterrupt(DETECTPIN)); //Отключаем прерывания
    PCICR  |= (0 << PCIE2) | (0 << PCIE1) | (0 << PCIE0); // отключение периваний Pin Change Interrupts, PCINT
    Serial.println(F(" false. "));
  }
}

void EnterSleep() {
  intFlagRing = false;

  Serial.println(F("\r\nEnterSleep"));
  digitalWrite(LED_BUILTIN, LOW);        // гасим светодиод
  attachInterrupt(digitalPinToInterrupt(RINGPIN), wakeUpM, LOW); //Если на 0-вом прерываниии - ноль, то просыпаемся.
  delay(100);

  //  sleep_enable();                         //Разрешаем спящий режим
  // sleep_mode();                           //Спим (Прерывания продолжают работать.) Программа останавливается.
  // sleep_disable();                        //Запрещаем спящий режим

  power.sleep(SLEEP_FOREVER);

  // сюды придет программа после рбработки прерывания wakeUp()
  printReg();
  delay(50);

  digitalWrite(LED_BUILTIN, HIGH);        // включаем светодиод
  if (intFlagRing == true) {
    Serial.print(F("RING PIN, "));
  }
  if (intFlagDetect == true) {
    Serial.print(F("DETECT PIN, "));
  }
}

void loop() {
  if (intFlagDetect == true) {
    intFlagDetect = false;
    Serial.print(F("*"));
  }

  if (millis() - TimeCountBeforeSleep > TIME_COUNT_BEFORE_SLEEP) {
    // проверяем сколько счетчик стоит, если долго то уходим в SEEP
    EnterSleep();
    TimeCountBeforeSleep = millis();// могли долго спать, нужно обновить счетчик
  }

  // считываем данные с компьютера и записываем их в GPRS Shield
  serialPCread();
  // считываем данные с GPRS Shield и выводим их в Serial-порт
  serialGPRSread();
}

void serialPCread()
{
  i = 0;
  if (Serial.available() > 0) {
    char c;
    // если приходят данные по USB
    while (Serial.available() > 0) {
      inSerial[i] = (Serial.read());
      delay(10);
      i++;
    }
    inSerial[i] = '\0';
    if (!strcmp(inSerial, "/ENABLE\r\n")) {
      Serial.println("_EN");
      EnableDisableWork(true);
      TimeCountBeforeSleep = millis();
      inSerial[0] = '\0';
    } else if (!strcmp(inSerial, "/DISABLE\r\n")) {
      Serial.println("_DI");
      EnableDisableWork(false);
      TimeCountBeforeSleep = millis();
      inSerial[0] = '\0';
    } else SerialModem.print(inSerial);
  }
}

void serialGPRSread()
{
  if (SerialModem.available() > 0) {
    // если приходят данные с GPRS Shield
    while (SerialModem.available() > 0) {
      // передаём их в терминал
      Serial.write(SerialModem.read());
    }
  }
}
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,266
1,303
Москва
На сколько я помню ардуина из сна может выходить по внешнему прерыванию, но по какому не важно. Т.е. любое внешнее прерывание будет ее пробуждать, что собственно и происходит. Значит надо обработать это прерывание и если его не надо сейчас использовать заново отправлять в сон.
Но это не точно, это на основании моего склероза.
 

M@@}{

✩✩✩✩✩✩✩
5 Май 2021
7
0
Избыточное цитирование
На сколько я помню ардуина из сна может выходить по внешнему прерыванию, но по какому не важно. Т.е. любое внешнее прерывание будет ее пробуждать, что собственно и происходит. Значит надо обработать это прерывание и если его не надо сейчас использовать заново отправлять в сон.
Но это не точно, это на основании моего склероза.
Да именно так все и работает. Но зачем просыпаться если можно прерывание отключить. В теории если одно прерывание отключить то и просыпаться от изменения состояния на этом входе ардуина не должна, а она просыпается, вопрос почему?
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,415
978
58
Марий-Эл
Пару месяцев назад интересовался этим.
Если ничего не путаю, даже при отключении прерываний, по импульсу на одном из входов, или нескольким, он просыпается всё равно. Что бы этого не было, нужно использовать другой режим.
 

M@@}{

✩✩✩✩✩✩✩
5 Май 2021
7
0
Избыточное цитирование
Пару месяцев назад интересовался этим.
Если ничего не путаю, даже при отключении прерываний, по импульсу на одном из входов, или нескольким, он просыпается всё равно. Что бы этого не было, нужно использовать другой режим.
какой режим? пробовал все которые описаны к функции SLEEP.
есть ещё один способ выхода из прерывания
"
  • POWERDOWN_SLEEP
    – Наиболее глубокий сон, отключается всё кроме WDT и внешних прерываний, просыпается от аппаратных (обычных + PCINT) или WDT, пробуждение за 1000 тактов (62 мкс)
"
так написано в документации.
меня интересует "(обычных + PCINT)" вот что заставляет проснутся мой контроллер (Я так думаю)
Я пытался отключить но у меня ничего не получается.
Если запустить скетчь то он выдает состояние регистров которые управляют разрешением прерывания.
 

M@@}{

✩✩✩✩✩✩✩
5 Май 2021
7
0
Здесь всё описано.
Хороший файлик и как надо на русском, но не полный.
Там есть что пробуждение из сна в разных режимах идет от разных источников. Источник пробуждения от смены состояния пин есть во всех режимах. а вот как отключить или настроить данный режим там ничего не сказано.

А можно полный ПДФ для данного контроллера на русском? (У меня с английским туго, а переводчик переводит коряво, нужен профессиональный перевод )