спящий режим

ruslan_rachinski
Offline
Зарегистрирован: 14.01.2018

dimax пишет:

ruslan_rachinsk,  ADCSRA=(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2)|(1<<ADEN)|(1<<ADSC);

Я сделал так, вроде все зароботала, это куски кода.

byte old_ADCSRA; // для включения процесора (Глобальная переменная )

 

 old_ADCSRA = ADCSRA; // присвоем значения процесора перед сбросом
                          //
ACSR |= (1 << ACD);       // отключаем Аналоговый компаратор
  // disable ADC to save power
ADCSRA = 0;               // отключаем Аналоговый компаратор (такой код в других скетчах)
 
power_all_disable();      // отключаем все внутренние блоки ЦП. (требуется <avr/power.h> + эта строчка должн быть после ADCSRA=0)

Потом когда проснулся, 

sleep_disable();                       // отключаем спящий режим
 
power_all_enable();                    // включаем все внутренние блоки ЦП
                
ADCSRA = old_ADCSRA;   // re-enable ADC conversion
// включаем повторно процесор
 
Вроде работает, нормально(всё правильно)
Дима спасибо что ответил...
Теперь буду знать как активировать процесор вашим способом!!!! 
5N62V
Offline
Зарегистрирован: 25.02.2016

CityCat пишет:

По ее мотивам переписал код для вас. Проверить не на чем пока, должно работать:

#include <avr/sleep.h>

int wakePin = 2;                 // Пин используемый для просыпания (прерывания)
int sleepStatus = 0;             // Переменная для хранения статуса (спим, проснулись) - не используется в коде
int count = 0;                   // Счетчик
int LedPin=13;                   // Светодиод


void wakeUpNow()        // Прерывание сработает после пробуждения
{
  if (sleepStatus)               // Если мы спали,
  {
    sleep_disable();             // то первое, что нужно сделать после просыпания - выключить спящий режим
    digitalWrite(LedPin, HIGH);  // Включаем светодиод
    sleepStatus = 0;             // В переменную заносим статус бодрствования
  }
  else
    {
      Serial.println("Timer: Entering Sleep mode");
      delay(100);     // Этот делэй необходим, чтоб функция sleep не вызывала ошибку по Serial
      sleepNow();     // Вызов функции sleep() для засыпания
    }
    
  // Код, который здесь выполнится перед возвращением в цикл loop()
  // Таймеы и код, использующий таймеры (serial.print и др...) здесь не будет работать
  // Также мы не должны выполнять какие-то спец. функции здесь,
  // Т.к. здесь мы просто просыпаемся
}


void setup()
{
  pinMode(LedPin, OUTPUT);
  digitalWrite(LedPin, HIGH);                // Включаем светодиод
  pinMode(wakePin, INPUT);
  digitalWrite(wakePin, HIGH);               // Подтягивем ногу к 5.
  Serial.begin(9600);
  attachInterrupt(0, wakeUpNow, FALLING);    // Используем прерывание 0 (pin 2) для выполнения функции wakeUpNow (прерывание вызывается только при смене значения на порту с HIGH на LOW - подтянуть ногу 2 на 5в.)
}


void sleepNow()         // Функция увода ардуины в спячку.
{
  digitalWrite(LedPin, LOW);             // Выключаем светодиод
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // Здесь устанавливается режим сна
  sleep_enable();                        // Включаем sleep-бит в регистре mcucr. Теперь возможен слип 

  //attachInterrupt(0,wakeUpNow, LOW);     // Используем прерывание 0 (pin 2) для выполнения функции wakeUpNow при появлении низкого уровня на пине 2

  count = 0;                             // Обнуляем счетчик прошедших секунд
  sleepStatus = 1;                       // В переменную заносим статус сна

  sleep_mode();                          // Здесь устройство перейдет в режим сна!!!
  // -----------------------------------------------ПОСЛЕ ПРОСЫПАНИЯ ВЫПОЛНЕНИЕ КОДА ПРОДОЛЖИТСЯ ОТСЮДА!!!
                           
  //sleep_disable();                       // Первое, что нужно сделать после просыпания - выключить спящий режим
  //detachInterrupt(0);                    // Выключаем прерывание - при нормальном режиме wakeUpNow() не будет вызываться
}


void loop()
{
  // Отображаем информацию о счетчике
  Serial.print("Awake for ");
  Serial.print(count);
  Serial.println("sec");
  count++;
  delay(1000);                           // Ждем секунду


  // Проверяем - если прошло 10 секунд - засыпаем
  if (count >= 10)
  {
    Serial.println("Timer: Entering Sleep mode");
    delay(100);     // Этот делэй необходим, чтоб функция sleep не вызывала ошибку по Serial
    count = 0;
    sleepNow();     // Вызов функции sleep() для засыпания
  }
}

У меня этот код не заработал.  Засыпает как надо, просыпается и..... зависает. Может из-за более новой версии IDE. 

Для меня проще свой код написать, чем разбираться почему чужой не работает. Почитал статью, все понятно.

Проц Atmega328P, при подключении питания  - работает, не засыпает,  при нажатии и удержании кнопки 2 сек - засыпает. При очередном нажатии и удержании - просыпается. Может кому пригодится. Критика приветствуется. 

Кнопка, разумеется,  со второго пина на землю.

#include <avr/sleep.h>

#define THRESHOLD 2000//порог срабатывания в мсек

const byte LED = 13;
bool flagWokeUp = 1;//начальное состояние - не спим
bool data = 1;

void wakeUp (){ //функция просыпания
  sleep_disable();
  detachInterrupt (0);
}

void setup ()
{
  Serial.begin(9600);
  pinMode (2, INPUT_PULLUP);
  pinMode (LED, OUTPUT);
}

void loop () {
  unsigned long time = 0;
  if (!(PIND & (1 << 2)))  time = millis();//если кнопка нажата
  while (!(PIND & (1 << 2)));  //ждем пока кнопку отпустят
  if (time) {
    if ((millis() - time) > THRESHOLD) {
      flagWokeUp = !flagWokeUp;
      time = 0;
    }
  }
  if (flagWokeUp) {
    // В этом блоке выполняем то, что нужно выполнять
    // во включеном состоянии
    //например мигаем диодом
    delay (50);
    digitalWrite (LED, data);
    delay (50);
    data = !data;
    digitalWrite (LED, data);

  }

  if (!flagWokeUp)goSleep();

}

void goSleep() {//функция ухода в сон

  delay(100);
  ADCSRA = 0;
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  noInterrupts ();
  attachInterrupt (0, wakeUp, FALLING);
  EIFR = bit (INTF0);
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS);
  interrupts ();
  sleep_cpu ();
}

 

cevinel
Offline
Зарегистрирован: 08.03.2019

Прошу прощения, совсем запутался, пробовал разные варианты засыпает и не просыпается. Что надо, есть небольшой проект для автомобиля, наобходимо по наличию напряжения с замка зажигания пробуждать ардуинку и при отсутствии засыпать. Как выполнено в железе статус провод с замка зажигания подключен на аналоговый вход A(1), а также при появлении напряжения полевик(IFR 520N ноги G и S шунтированны резистором 10 к ) замыкает на землю контакт D2.

Пока реализовано только выключение дисплея. Сосбственно сам код.  Немогу сообразить как сюда прикрутить алгоритм засыпания чтоб работало корректно.

#include <LiquidCrystal_I2C.h>
#include <avr/sleep.h>
#define THRESHOLD 2000//порог срабатывания в мсек
#define PIN_RELAY 5 // Определяем пин, используемый для подключения реле(вкл компрессора)
#define PIN_RELAY2 6 // Определяем пин, используемый для подключения реле(вкл пер блок)
#define PIN_RELAY3 7 // Определяем пин, используемый для подключения реле(вкл зад блок)
#define PIN_RELAY4 8 // Определяем пин, используемый для подключения реле(вкл зад блок)
LiquidCrystal_I2C lcd(0x27, 16, 2); // Устанавливаем дисплей

bool flagWokeUp = 1;//начальное состояние - не спим
bool data = 1;

void wakeUp (){ //функция просыпания
  sleep_disable();
  detachInterrupt (0);
}
  
void setup()
{
  Serial.begin(9600);
  pinMode (2, INPUT);
  pinMode(PIN_RELAY, OUTPUT); // Объявляем пин реле как выход
  pinMode(PIN_RELAY2, OUTPUT);
  pinMode(PIN_RELAY3, OUTPUT);
  pinMode(PIN_RELAY4, OUTPUT);
  digitalWrite(PIN_RELAY, HIGH); // Выключаем реле - посылаем высокий сигнал
  digitalWrite(PIN_RELAY2, HIGH);
  digitalWrite(PIN_RELAY3, HIGH);
  digitalWrite(PIN_RELAY4, HIGH);
  lcd.init();
}
void loop()
{ 
  if (digitalRead(2)  == LOW) {
   flagWokeUp;
  }
 if (digitalRead(2)  != LOW){
    !flagWokeUp;
   }


  if (flagWokeUp) {
  // label :
  float z = analogRead(A1);       // Вход наличия включения зажигания.
           z = z * 5. / 1024. / 6.8 * (20 + 6.8);

    // if ( z > 10) {
     lcd.backlight();             // Включаем подсветку дисплея
     lcd.display();               //Включаем дисплей.
 
   // } else {
    // lcd.noDisplay();             // выключаем дисплей
    // lcd.noBacklight();
    
   // delay(1000);
   // goto label;
  // }
   float val = analogRead(A0);  // Вход датчика давления
            val = val * 5. / 1024.;
            val = 3 * val - 1.5;
   float v = analogRead(A2);   // вход измерения напряжения
            v = v * 5. / 1024. / 6.8 * (20 + 6.8);
   float kk = analogRead(A3);  // вход кнопки компрессора
         kk = kk * 5. / 1024. / 6.8 * (20 + 6.8);
   float kvpb = analogRead(A6); // вход кнопки включения передней блокировки
         kvpb = kvpb * 5. / 1024. / 6.8 * (20 + 6.8);
   float kvzb = analogRead(A7); // вход кнопки включения задней блокировки.
         kvzb = kvzb * 5. / 1024. / 6.8 * (20 + 6.8);      
          // delay(1000);  
    if (val < 0 ){
      val = 0.0; // Убираем значения лежащие ниже предела измерения
    }
    if (val > 12){
      val = 12; // Убираем значения лежащие выше предела измерения
    }
    
    if (kk > 10 and val <= 8 and z > 10){
    lcd.setCursor(8, 1);
    lcd.print("COMP ON ");
    digitalWrite(PIN_RELAY, LOW); // Включаем реле - посылаем низкий уровень сигнала
  } 
    if (kk < 10 || val >= 10 || z < 10){
    lcd.setCursor(8, 1);
    lcd.print("COMP OFF");
    digitalWrite(PIN_RELAY, HIGH); // Отключаем реле - посылаем высокий уровень сигнала
  }
 if (kvpb  > 10){
    digitalWrite(PIN_RELAY2, LOW); // Включаем реле - посылаем низкий уровень сигнала
  } else {
    digitalWrite(PIN_RELAY2, HIGH); // Отключаем реле - посылаем высокий уровень сигнала
  }
 if (kvzb  > 10){
    digitalWrite(PIN_RELAY3, LOW); // Включаем реле - посылаем низкий уровень сигнала
  } else {
    digitalWrite(PIN_RELAY3, HIGH); // Отключаем реле - посылаем высокий уровень сигнала
  }
  
  // digitalWrite(PIN_RELAY2, LOW);
  lcd.setCursor(0, 0);
  lcd.print("P");
  lcd.setCursor(2, 0);
  lcd.print(val,1);
  lcd.setCursor(9, 0);
  lcd.print("V");
  lcd.setCursor(11, 0);
  lcd.print(v,1);
  
  // Устанавливаем курсор на вторую строку и нулевой символ.
  lcd.setCursor(0, 1);
  // Выводим на экран количество секунд с момента запуска ардуины
  lcd.print(millis() / 1000);
 }
if (!flagWokeUp)goSleep();
}
void goSleep() {//функция ухода в сон
  delay(100);
    ADCSRA = 0;
    set_sleep_mode (SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    noInterrupts ();
    attachInterrupt (0, wakeUp, FALLING);
    EIFR = bit (INTF0);
    MCUCR = bit (BODS) | bit (BODSE);
    MCUCR = bit (BODS);
    interrupts ();
    sleep_cpu ();
  }