спящий режим

viktor2301
Offline
Зарегистрирован: 21.02.2015

Люди добрые, помогите!

Пишу программу на мегу 2560, для авто. Очень нужен спящий режим, с выходом из него по прерыванию.

Скетч из поста #5 заливал и модифицировал безчисленное количество раз. Результат всегда один - мега легко входит в спячку по прерыванию, но никогда из неё не выходит. В борьбе с даташитом победил даташит, я лиш понял что вроде бы нужно использовать прирывание INT7, коего ненашел.

Help, как вывести из спячки мегу?

Artemvip7
Offline
Зарегистрирован: 02.08.2014

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() для засыпания
  }
}

Почему при нажатии кнопки (wakePin = 2;) во время бодорствования Arduino UNO зависает?

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

Чуть переделанный мною код для пробуждения не только по кнопке, но и по WDT.

Вроде работает (в рабочем режиме кушает 8,6 мА, в спящем - 2,28 мА), но гляньте, вдруг есть что оптимизировать.
В частности, по нажатию кнопки "Welcome" иногда выводится два раза подряд.

// Просыпаемся по таймеру раз в 8 сек, либо по кнопке, делаем 10 вспышем и снова спим.

#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

#define BUTTON 3                 // Пин используемый для пробуждения (использует прерывание 1)
int count;                       // Счетчик  

// watchdog interrupt
ISR (WDT_vect) 
{
  wdt_disable();  // disable watchdog
}  // end of WDT_vect


void setup()
{
  config();           // настраиваем входы/выходы
  attachInterrupt(1, wakeUpNow, FALLING);    // Используем прерывание 1 (pin 3) для выполнения функции wakeUpNow (FALLING - прерывание вызывается только при смене значения на порту с HIGH на LOW)
  Serial.begin(9600);
  delay(5000);       // на всякий случай, если войдет в бесконечный цикл, можно будет перепрошить
  Serial.println("Start!");
}


void loop()
{
  // Отображаем информацию о счетчике
  Serial.print(count);
  Serial.print(", ");
  count++;
  //delay(1000);                           // Ждем секунду
  digitalWrite(LED_BUILTIN, HIGH); 
  delay(50);
  digitalWrite(LED_BUILTIN, LOW); 
  delay(50);

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


void sleepNow()         // Функция увода ардуины в спячку
{
  digitalWrite(LED_BUILTIN, LOW);             // Выключаем светодиод
  /*
  for (byte i = 0; i <= A5; i++)         // переводим пины в режим выхода (закомментировано, т.к. виснет после засыпания)
   {
   pinMode (i, OUTPUT);    // changed as per below
   digitalWrite (i, LOW);  //     ditto
   }
   */
  ACSR |= (1 << ACD);       // отключаем Аналоговый компаратор
  ADCSRA = 0;               // отключаем Аналоговый компаратор (такой код в других скетчах)
  power_all_disable();      // отключаем все внутренние блоки ЦП. (требуется <avr/power.h> + эта строчка должн быть после ADCSRA=0)
  // power_adc_disable();   // ADC converter
  // power_spi_disable();   // SPI
  // power_usart0_disable();// Serial (USART) 
  // power_timer0_disable();// Timer 0
  // power_timer1_disable();// Timer 1
  // power_timer2_disable();// Timer 2
  // power_twi_disable();   // TWI (I2C)

  // отключаем BOD 
  noInterrupts (); // cli(); // отключение прерываний
  uint8_t x = (MCUCR & ~(1 << BODSE)) | (1 << BODS); // подготовка бит
  MCUCR = x | (1 << BODSE); // процедура отключения BOD
  MCUCR = x;
  interrupts (); //sei(); // включение прерываний
  // конец отключения BOD 

  // подготовка WatchDog  
  MCUSR = 0;  // clear various "reset" flags
  WDTCSR = bit (WDCE) | bit (WDE); // allow changes, disable reset
  // set interrupt mode and an interval   
  WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
  //WDTCSR = bit (WDIE) | bit (WDP2) | bit (WDP1);  // set WDIE, and 1 second delay
  wdt_reset();  // pat the dog
  // конец подготовки WatchDog

  attachInterrupt(1,wakeUpNow, FALLING); // назначаем прерывание 1 (pin 3) для выполнения функции wakeUpNow при нажатии кнопки

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // устанавливается режим сна (это не вход в сон! Только установка режима!)
  sleep_enable();                        // включаем sleep-бит в регистре mcucr. Теперь возможен сон 
  sleep_mode();    //sleep_cpu();        // Здесь устройство перейдет в режим сна. Внешние прерывания и WDT продолжают работать.

  // -----------------------------------------------ПОСЛЕ ПРОСЫПАНИЯ ВЫПОЛНЕНИЕ КОДА ПРОДОЛЖИТСЯ ОТСЮДА!!! 
  wakeUpNow();
}


void wakeUpNow()        // Пробуждение по внешнему прерыванию
{
  // Код, который здесь, выполнится перед возвращением в цикл loop()
  // Таймеы и код, использующий таймеры (serial.print и др...) здесь не будут работать
  // Также мы не должны выполнять какие-то спец. функции, здесь мы просто просыпаемся 
  sleep_disable();                       // отключаем спящий режим
  power_all_enable();                    // включаем все внутренние блоки ЦП
  // power_adc_enable();    // ADC converter
  // power_spi_enable();    // SPI
  // power_usart0_enable(); // Serial (USART)
  // power_timer0_enable(); // Timer 0
  // power_timer1_enable(); // Timer 1
  // power_timer2_enable(); // Timer 2
  // power_twi_enable();    // TWI (I2C)
  wdt_disable();                         // нужно ли здесь это?
  config();                              // настраиваем входы/выходы
  detachInterrupt(1);                    // Выключаем прерывание - при нормальном режиме wakeUpNow() не будет вызываться
}

void config()   // Настраиваем входы/выходы
{
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(BUTTON, INPUT_PULLUP);
  Serial.println("Welcome!");  
}

/*
у ардуино есть 5 спящих режимов:
 * SLEEP_MODE_IDLE         -the least power savings
 * SLEEP_MODE_ADC
 * SLEEP_MODE_PWR_SAVE
 * SLEEP_MODE_STANDBY
 * SLEEP_MODE_PWR_DOWN     -the most power savings
 при последнем режиме вывести из сна ардуину можно только одним из прерываний на пинах 2 или 3 или срабатыванием таймера по watchdog.
 
 на момент ухода в сон все ноги мк включая не использованные должны быть в одном из состояний:
 - настроены на выход
 - настроены на вход и включена внешняя подтяжка
 - настроены на вход и присоеденена внешняя подтяжка
 - настроены на вход и закорочены на GND - это вариант длянеиспользованных пинов, но можно и с внутренней подтяжкой
 еще важно определиться с тем нужно ли просыпаться от таймеров. Таймеры много жрут
 ждет ацп
 жрет watch dog (0,1 мА)
 жрет детектор напряжения, который фьюзами включается
 */

 

s1981
Offline
Зарегистрирован: 22.12.2013

Можно корректный пример перевода, просыпания ардуины в спящий режим. Все что сдесь есть работает некорректно. Либо намертво засыпает, либо работает через раз и засыпает намертво(((

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

вот 100% работающий код (вчера был загружен в две платки для тестов):

https://bigdanzblog.wordpress.com/2014/08/10/attiny85-wake-from-sleep-on...

P.S. watchdog используется? В этом случае возможны такие проблемы со стандартным загрузчиком: https://geektimes.ru/post/255800/

HUSTON
Offline
Зарегистрирован: 04.04.2016

Может кто из вас поделится библиотекой <avr/sleep.h> ???

Облазил пол интернета и фиг

 
toc
Offline
Зарегистрирован: 09.02.2013

HUSTON пишет:

Может кто из вас поделится библиотекой <avr/sleep.h> ???

Облазил пол интернета и фиг

 

если у вас есть программа Arduino, то у вас уже есть эта библиотека.

HUSTON
Offline
Зарегистрирован: 04.04.2016

      Доброго времени суток. Подскажите, как на Ардуино нано(Atmega328p) сделать следующее: уходить в сон по нажатию кнопки и просыпаться по нажатию той же кнопки(подключенной к D2) и по таймеру, если в ходе обработки прерывания от таймера выполнилось условие равенства между моими константами и данными прочитанными по SPI, то необходимо выйти из сна и запретив прервания перейти к выполнению основной программы.

Ardfun
Offline
Зарегистрирован: 22.05.2016

А какое потребление енергии в спящем режиме ардуины? можно ли приравнять к отключеному питанию?

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013
Из моих проектов:
 /*
Потребление Arduino Uno (LED питания светится всегда) при Vcc = 3,3 В:
19,8 мА - при активности и изображении на OLED 0,96" (50% заполнения)
12,9 мА - при активности и OLED 0,96" под напряжением, но без вывода изображения (пустой экран)
11,3 мА - при активности и физически отключенном OLED 0,96"
6,2 мА - в режиме sleep и OLED 0,96" под напряжением, но без вывода изображения (пустой экран)
4,8 мА - в режиме sleep и физически отключенном OLED
Если сковырнуть LED питания, то еще экономим 2,5 мА
*/
 
/* Attiny85 Digispark
 * Замеры потребления проводились при напряжении 3,3 В:   с LED      без LED (индикатор питания)
 * Потребление на частоте 16,5 МГц (USB HID support):         12,88 мА  11,56 мА
 * Потребление на частоте 16 МГц:                                        12,65 мА  11,38 мА
 * Потребление на частоте  8 МГц:                                         9,59 мА    8,19 мА
 * Потребление на частоте  1 МГц:                                         6,44 мА    4,93 мА
 * Потребление на частоте  1 МГц + sleep:                             4,70 мА    3,13 мА
 * Потребление на частоте  1 МГц + sleep + выходы в LOW:   4,59 мА    3,03 мА
*/
 
Почему так много? А потому что используется Arduino IDE. Оказывается, при использовании конструкции setup и loop подгружается масса ардуиновских библиотек. Они включают таймеры, ацп, и прочее, и никто не считал сколько всего меняется. Если использовать чистый Си, то можно снизить до микроампер.
 
Спящий режим
http://www.polesite.ru/?p=1273

Использование режима сна для экономии энергии
http://www.gammon.com.au/power

3 years on one set of batteries
http://jeelabs.org/2013/09/08/3-years-on-one-set-of-batteries/
https://www.drive2.ru/b/1282902/

Понижение тактовой частоты, режимы энергосбережения:
http://student-proger.ru/2013/10/energopotreblenie-arduino/
http://inet-deal.mpa.ru/articles/arduino-003.html
https://www.reddit.com/r/arduino/comments/o5443/so_you_want_an_easy_way_to_save_power/
http://arduino.ru/forum/apparatnye-voprosy/rezhim-energosberezheniya

Пробуждение Arduino из спящего режима по нажатию кнопки
https://bigdanzblog.wordpress.com/2014/08/10/attiny85-wake-from-sleep-on-pin-state-change-code-example/
https://sites.google.com/site/vanyambauseslinux/arduino/ispolzovanie-preryvanij-arduino#p5
http://arduino.ru/forum/obshchii/spyashchii-rezhim

Ardfun
Offline
Зарегистрирован: 22.05.2016

А каким образом можно реализовать не спящий режим а отключение питания (почти полностю), принцип как в электронных устройствах, плеерах, мобилках, чтоб при нажатии допустим 5с включался аппарат и при таком же нажатии вырубался???

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

а с чего ты взял, что они полностью выключаются? Там скорее всего такой же сон, с микроамперным потреблением.

Но если очень надо, то можно и полное отрубание. 
Вот схема на реле:

Можно и средствами Arduino - кнопкой напрямую подаем питание на Vcc, Arduino включается, в setup прописываем - сразу же после включения: подать на пин X сигнал, который через транзистор скоммутирует питание (параллельно кнопке), после этого кнопку можно отпускать. Недостаток тут есть - надо чуть подержать кнопку (0,5-2 сек), чтобы Arduino успел загрузиться.

 

Viktor1306
Viktor1306 аватар
Offline
Зарегистрирован: 19.05.2016

Посоветуйте пожалуйста как лучше сделать. Нужно сделать чтоб ардуина просыпалась по внешнему сигналу, и по времени. С внешним сигналом я разобрался, а вот с таймером возникли вопросы. Во всех примерах пробуждения во Watсhdog-у используются корткие интервалы (от миллисекунд до десятков секунд), мне же нужны интервалы поболее (1ч. 2ч. 4ч. 8ч. и 16ч.). Всвязи с этим встаёт резонный вопрос, можно ли настроить сторожевой таймер на такие интервалы, и если да, то будет ли это правильно. Или рациональней будет использовать часы реального времени? 

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

сторожевой таймер имеет максимальный интервал 8 сек.

Но никто тебе не мешает завести переменную, куда каждые 8 сек записывать приращение на единичку.
Как только значение переменной превысит 450/900/1800/3600,значит пора просыпаться ;)

Viktor1306
Viktor1306 аватар
Offline
Зарегистрирован: 19.05.2016

О! Спасибо за подсказку. Отличная идея, а то у меня на ардуинке всего 3 ноги свободных осталось, и с часами реального времени будет проблемка...

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

Tomasina пишет:

сторожевой таймер имеет максимальный интервал 8 сек.

важно понимать, что 8сек относятся именно к atmega328, у других МК надо даташит смотреть, может быть меньше

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

watchdog изначально придуман для другого поэтому не расчитан на длительное время между прерываниями, но его фишка как раз в том что для его работы требуется меньше энергии

НО. если RTC уже есть и они уже жрут свои микроватты энергии, то просыпание по RTC позволит сэкономить еще чуточку, ибо хоть watchdog есть мало, но все равно ест. Если его отключить то можно довести потребление во сне до почти абсолютного минимума, особенно если еще все остальное отключить (в частности детектор низкого напряжения)

Viktor1306
Viktor1306 аватар
Offline
Зарегистрирован: 19.05.2016

RTC нету, но скорее всего придётся ставить. Так как нужно определять время сработки датчика. Я на каком то форуме, недели 2 назад читал что у часов можно запрограммировать какой то выход, чтоб на нём раз в час менялся лог. уровень. Буду весьма признателен если кто нибудь подскажет как, и где можно посмотреть пример использования RTC для этих целей. Облазил пол инета и ни где ни чего вразумительного не нашёл... 

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

Ds3231 имеет два будильника, можно на конкретное время настроить

dhog1
Offline
Зарегистрирован: 01.03.2016

Victor1306

PCF8563, это RTC с таймером. Таймер весьма гибок (256 отсчетов от ~2мкс до 1 мин на отсчёт), выход таймера настраивается (изм. лог. уровня / импульс), низкое потребление (~500 nA). Подробности в техдоке.

Использую весьма давно.

AlexAxel
Offline
Зарегистрирован: 26.01.2017

Вопрос такой: вот кнопками или по таймеру - это понятно более-менее. А вот такая задача: имеем устройство на ардуине которое транслирует с использованием модуля RX 433 последовательности символов - в течение часа - "а",  второго часа - "b", третьего - "с" и т.п. Второе устройство, с ресивером, находится в зоне приема в спящем режиме. Можно ли сделать так, чтобы оно просыпалось во время трансляции определенного символа и засыпало по окончании трансляции или выходе устройства-приемника из зоны сигнала (либо отключении передатчика)

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

какой минимальный ток потребления удавалось достичь?

а если остальные ноги нагружены чемто, то тогда как  с величиной потребления кристала по питанию?

ASK-list
Offline
Зарегистрирован: 17.01.2017

Насчёт минимального потребляемого тока.

Экспериментировал с Digispark.

На этой плате три пассивных потребителя энергии:

- светодиод питания: выпаял его резистор;

- стабилизатор напряжения 78M05 - отпаял его выходную ногу;

- подтягивающий резистор, обеспечивающий работу с USB: переставил его и подпаял пару проводков, чтобы их замыкать при заливке скетчей.

Получилось вот так:

За основу кода взял пример отсюда.

Код подкорректировал по своему разумению, получилось так:


#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>

#define WDTO_INFINITE 255
#define SLEEP_PERIOD WDTO_8S
#define SKIP_WDT_WAKEUPS 14 // x SLEEP_PERIOD + SLEEP_PERIOD (14 ~= 120 sec)

#define LIGHT_PIN 3 


volatile bool light_pcint = false;
volatile byte wakeup_counter = 0;

// Вектор (функция) прерывания PCINT, у ATtiny85 один порт (B), следовательно только один вектор PCINT
ISR(PCINT0_vect)
{
  light_pcint = true;
}

// Вектор прерывания таймера WDT
ISR(WDT_vect)
{
  wakeup_counter++;
}

void sleep()
{
  GIMSK = _BV(PCIE); // Включить Pin Change прерывания
//  if (SLEEP_PERIOD == WDTO_INFINITE || payload.light != LIGHT_FUZZY)
    PCMSK |= _BV(LIGHT_PIN); // PCINT3; включить если нет проблем с освещением или иначе нет шансов проснуться
  ADCSRA &= ~_BV(ADEN); // отключить ADC; уменьшает энергопотребление

  if (SLEEP_PERIOD != WDTO_INFINITE) {
    wdt_enable(SLEEP_PERIOD); // установить таймер
    WDTCR |= _BV(WDIE); // включить прерывания от таймера; фикс для ATtiny85
  }

  // Установить режим сна Power-down; MCUSR &= ~_BV(SM0); MCUSR |= _BV(SM1);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable(); // разрешить режим сна; MCUSR |= _BV(SE);
  sei(); // включить прерывания

  sleep_cpu(); // заснуть

  cli(); // отключить прерывания; для безопасного отключения PCINT3
  PCMSK &= ~_BV(LIGHT_PIN); // PCINT3; отключить
  sleep_disable(); // запретить режим сна; MCUSR &= ~_BV(SE);
  ADCSRA |= _BV(ADEN); // включить ADC
  sei(); // включить прерывания; иначе таймеры не будут работать
}

void setup() {
  // put your setup code here, to run once:
     pinMode(1, OUTPUT); //LED on Model B

     pinMode(0, INPUT); 
     pinMode(1, INPUT); 
     pinMode(2, INPUT); 
     pinMode(3, INPUT); 
     pinMode(4, INPUT); 
     pinMode(5, INPUT); 

}

void loop() {
  // put your main code here, to run repeatedly:

  digitalWrite(1, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(5000);               // wait for a 5 second

  digitalWrite(1, LOW);    // turn the LED off by making the voltage LOW
  sleep();

}

С этим скетчем Digispark выходит из спящего режима по Watchdog или по высокому уровню на третьем пине.

Ток, потребляемый платой в режиме SLEEP_MODE_PWR_DOWN - 7 мкА (семь микроампер).

То есть тысячу миллиампер-часов энергии плата съест в этом режиме за 16 лет.

ASK-list
Offline
Зарегистрирован: 17.01.2017

Продолжил эксперименты со спящим режимом в Digispark. У меня в нём навернулся загрузчик (сам не понял, почему). Я восстановил его, подробнее здесь. Теперь с загрузчиком micronucleus-1.06.hex минимальный ток составляет 28 мкА (что тоже неплохо).

Кстати, как я понял, для экономного спящего режима нужно отправить (digitalWrite) перед засыпанием на использовавшиеся пины уровень LOW.

ASK-list
Offline
Зарегистрирован: 17.01.2017

Вернул энергопотребление Digispark на уровень 7 мкА. Для этого прошил загрузчик micronucleus-1.06.hex (см. ссылку на моё описание этого процесса в предыдущем посте), но с другими значениями fuses. Фрагмент моего файла boards.txt:

digispark-tiny.name=Digispark (Tiny Core)
digispark-tiny.upload.maximum_size=6012
digispark-tiny.build.mcu=attiny85
digispark-tiny.build.f_cpu=16500000L
digispark-tiny.build.core=tiny
digispark-tiny.upload.using=digispark
digispark-tiny.bootloader.low_fuses=0xe1
digispark-tiny.bootloader.high_fuses=0xdf
digispark-tiny.bootloader.extended_fuses=0xfe
digispark-tiny.bootloader.path=micronucleus
digispark-tiny.bootloader.file=micronucleus-1.06.hex

Здесь отключены детекторы низкого напряжения питания.

Как оказалось, включение "Brown-out Detector trigger level" на уровень 2.7 В (BODLEVEL1) увеличивало энергопотребление в SLEEP_MODE_PWR_DOWN режиме с 7 до 28 мкА.

a5021
Offline
Зарегистрирован: 07.07.2013

7мка для голой атмеги многовато. У меня беспроводной сенсор, состоящий из МК, трех I2C датчиков, передатчика NRF24L01 и DC-DC преобразователя, в периоды, когда все это хозяйство включено, но "спит", потребляет 4.5мка.

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

a5021 пишет:

7мка для голой атмеги многовато. У меня беспроводной сенсор, состоящий из МК, трех I2C датчиков, передатчика NRF24L01 и DC-DC преобразователя, в периоды, когда все это хозяйство включено, но "спит", потребляет 4.5мка.

 

можете пример привести что и как использовали?

У меня менее пары милиампер чтото не получалось на 328, хотя  паял только проц на  отдельной плате.

a5021
Offline
Зарегистрирован: 07.07.2013

Так с мегой вообще ничего не нужно делать. Все, что требуется, она сама с рождения умеет:

Остается только внимательно все поотключать перед отправкой в сон, снизить тактовую и пусть она дремлет на наноамперах.

Viktor1306
Viktor1306 аватар
Offline
Зарегистрирован: 19.05.2016

Моя Ардуина, с которой я так долго воевал, сейчас потребляет в спящем режиме 0,7 мкА. Добился такого так:

Вместо WatchDog-а использую часы реального времени, пробуждение происходит по прерыванию которое генерится часами (будильником).

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

На плате Ардуино про мини, отпаял практически всю обвязку контроллера (светодиоды, стабилизатор на 3,3v, оставил только саму Атмегу, кварц с двумя кондёрами на 22пФ, подтягивающий резитор на ноге Reset (увеличил с 10к до 220к) и кондёр для формирования импульса сброса при программировани.

При уходе в сон, тактовая частота понижается до 1мГц, а напряжение питания Ардуины, падает практически до предела 1,9v (предел по даташиту 1,8v, хотя мне попадались образцы, прекрасно работающие и на 0,7v.

Отключаются все элементы схемы кроме МК и одного датчика (приёмник-пришлось купить японский с потреблнием 1,2мкА, и доработать его под собственные нужды, нужен он чтоб постоянно слушать эфир. Когда кто нибудь подходит с передатчиком он будит МК и последний ждёт кодовой посылки).

Все датчики, кроме дымового я использовал типа "сухой контакт" без всяких микросхем, диодов и т.д. Дымовой датчик установил изотопный, ток потребления у него в рабочем состоянии 0,4мкА в состоянии "Пожар" 5мА.

Вот и все хитрости...

З.Ы. вся схема в итоге потребляет около 2,5мкА в спящем режиме, а у моей схемы это основной режим. 

a5021
Offline
Зарегистрирован: 07.07.2013

Viktor1306 пишет:
При уходе в сон, тактовая частота понижается до 1мГц, а напряжение питания Ардуины, падает практически до предела 1,9v (предел по даташиту 1,8v, хотя мне попадались образцы, прекрасно работающие и на 0,7v.

Вы либо что-то путаете, либо неправильно измерения производили. От 0.7в атмега не будет работать в принципе. Скорее всего паразитное питание откуда-то заходило. Например, от программатора.

Цитата:
приёмник-пришлось купить японский с потреблнием 1,2мкА, и доработать его под собственные нужды, нужен он чтоб постоянно слушать эфир.

Тоже что-то совсем необычное. Какие-то данные по модели этого приемника вы можете озвучить?

ASK-list
Offline
Зарегистрирован: 17.01.2017

Пришёл к выводу, что для моей поделки потребуется Pro Mini, а Digispark не подойдёт (у него всего одно прерывание, его не хватит). В связи с этим просьба к знающим людям: не могли бы вы привести образец скетча, который бы переводил Pro Mini с Atmega328p в режим SLEEP_MODE_PWR_DOWN с минимальным энергопотреблением (понятно, что лишнюю обвязку я с платы уберу) и обеспечивал бы всего две вещи:

- выход из сна через, например, 2*8=16 секунд;

- выход из сна подачей высокого уровня на INT0 или INT1.

Заранее спасибо.

a5021
Offline
Зарегистрирован: 07.07.2013
dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Viktor1306, а можно полюбопытствовать чем и как вы измеряете микроамперы? Задача то нетривиальная :)

ASK-list
Offline
Зарегистрирован: 17.01.2017

Как раз  то, что надо, спасибо! Буду пробовать.

Ещё вопрос, если позволите. Имею сейчас в наличии пару NANO китайских (c CH340G, естественно). Есть ли у кого опыт по отключению на ней лишнего - намного ли больше резать-паять, чем у Pro Mini?

Viktor1306
Viktor1306 аватар
Offline
Зарегистрирован: 19.05.2016

Для a5021

По первому вопросу, да, возможно заходило с программатора, возможно в схеме вместо конденсатора был ионистор запаян. Давно это было, достался нам пакет Атмег, штук 2000 или больше, вот мы над ними и издевались.

По второму вопросу: У меня знакомый живёт в Японии, я попросил его посмотреть приёмопередатчик, типа как от автомобильных брелоков. Там то приёмник потребляет 1-3 мкА. Он присылает мне игрушку, кошачьи ушки, такой обруч с двумя ушами и маленький пультик к ним, говорит отдельно можно купить только партию а поштучно не продают, но в игрушке стоит. В итоге я стал счастливым обладателем 2х трансиверов, работают они на нестандартной частоте 3,65гГц, дальность около 50м (что мне и нужно). 6 дипазонов в каждом диапазоне 65536 каналов. Настройки производятся по интерфейсу I2С, по нему также передаются данные принятые и на отправку. Есть вывод на котором появляется лог. 1 если к приёмнику было обращение, я его использовал для того чтобы будить контроллер. С настройками я не разобрался, работает на 1 дипазоне 1 канале по дефолту. Питание 2 - 5 вольт. Я дал питание 2,2 вольта, потому что чем больше напряжение тем соответсвенно и ток. Имеет вид железной коробочки 1,5х1 см. Похож на SIM800 название прочесть не могу, так как не силён в японском.  

Для dimax

Мультиметром конечно, а чем их ещё меряют? Не линейкой же :) Мультиметр дорогой, не китайский за 250р. Я думаю, ему можно верить.

А как, ставлю мультиметр на 2000 мА, подключаю его последовательно с тем где хочу померить ток, и источником питания. Жду минуту, чтоб закончились все переходные процессы. И начинаю на мультиметре плавно уменьшать значение, так дохожу до микроамперов.

 

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Viktor1306, а что за мультиметр у вас?

Viktor1306
Viktor1306 аватар
Offline
Зарегистрирован: 19.05.2016

Первый Mastech MS8240D на столе стоит а второй Mastech MAS830 для того, чтоб с собой носить

ASK-list
Offline
Зарегистрирован: 17.01.2017

Разобрался с отключением лишних элементов обвеса у NANO с CH340G на борту. Оказалось, на этой плате отключить лишнее ещё проще, чем на Digispark.

1. Перерезать одну дорожку возле резистора RX светодиода:

Этим самым мы отключаем сразу стабилизатор питания AMS1117, светодиод питания, светодиоды RX и TX. Два последних светодиода, как я понимаю, тоже нужно отключать: они сидят на +5В, а для экономии энергии нужно переводить выводы в LOW. То есть в таком случае они окажутся под напряжением.

2. Перерезать дорожку питания у CH340G. Конечно, понадобится провод для подключения этой микросхемы при заливке скетчей:

Вот и всё! Со включенным WatchDog этот скетч

// пробуждение по WatchDog

#include <avr/sleep.h>
#include <avr/wdt.h>

const byte LED = LED_BUILTIN;

void flash ()
  {
  pinMode (LED, OUTPUT);
  for (byte i = 0; i < 10; i++)
    {
    digitalWrite (LED, HIGH);
    delay (50);
    digitalWrite (LED, LOW);
    delay (50);
    }
    
  pinMode (LED, INPUT);
    
  }  // end of flash
  
// watchdog interrupt
ISR (WDT_vect) 
{
   wdt_disable();  // disable watchdog
}  // end of WDT_vect
 
void setup () { }

void loop () 
{
 
  flash ();
 
  digitalWrite (0, LOW);
    
  // disable ADC
  ADCSRA = 0;  

  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval 
  WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
  wdt_reset();  // pat the dog
  
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  noInterrupts ();           // timed sequence follows
  sleep_enable();
 
  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS); 
  interrupts ();             // guarantees next instruction executed
  sleep_cpu ();  
  
  // cancel sleep as a precaution
  sleep_disable();
  
  } // end of loop

даёт энергопотребление 7 мкА (обратите внимание, что здесь пин 0 переводится в LOW - если этого не сделать, ток будет около 80 мкА).

На скетче с пробуждением от прерывания на втором пине (WatchDog не используется)

// пробуждение по прерыванию

#include <avr/sleep.h>

const byte LED = LED_BUILTIN;

void blink(int cnt)
{
  for (int i = 0; i < cnt; i++) {
    digitalWrite (LED, HIGH);
    delay (50);
    digitalWrite (LED, LOW);
    delay (50);
  }
}
  
void wake ()
{
  // cancel sleep as a precaution
  sleep_disable();
  // precautionary while we do other stuff
  detachInterrupt (0);
}  // end of wake

void setup () 
  {
  digitalWrite (2, HIGH);  // enable pull-up
  }  // end of setup

void loop () 
{
 
  pinMode (LED, OUTPUT);
  blink (10);
  digitalWrite (0, LOW);  // отправка на pin D0 значения LOW, иначе там остаётся около 2.5 В
  delay (50);
  pinMode (LED, INPUT);
  
  // disable ADC
  ADCSRA = 0;  
  
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_enable();

  // Do not interrupt before we go to sleep, or the
  // ISR will detach interrupts and we won't wake.
  noInterrupts ();
  
  // will be called when pin D2 goes low  
  attachInterrupt (0, wake, FALLING);
  EIFR = bit (INTF0);  // clear flag for interrupt 0
 
  // turn off brown-out enable in software
  // BODS must be set to one and BODSE must be set to zero within four clock cycles
  MCUCR = bit (BODS) | bit (BODSE);
  // The BODS bit is automatically cleared after three clock cycles
  MCUCR = bit (BODS); 
  
  // We are guaranteed that the sleep_cpu call will be done
  // as the processor executes the next instruction after
  // interrupts are turned on.
  interrupts ();  // one cycle
  sleep_cpu ();   // one cycle

  } // end of loop

мой китайский тестер за 250 рублей :) на диапазоне с разрешением 1 мкА показывает ноль.

Кстати, чтобы не паять чёрный провод, пытался сделать так:

но диод Шоттки на входе USB питания имеет утечку в обратном направлении больше 1 мА, так что этот вариант не прошёл. Конечно, можно было паять вместо этого диода обычный, но по Datasheet на CH340G напряжение питания 4.5 - 5.5 В, и чего он мне напрошивает при четырёхвольтовом питании - неизвестно.

a5021
Offline
Зарегистрирован: 07.07.2013

Viktor1306 пишет:
Там то приёмник потребляет 1-3 мкА.

Я было засомневался, что подобное вообще существует в природе, слишком уж необычные характеристики, но потом погуглил слегка и был вынужден умерить скепсис. Оказалось, что существует класс устройств под названием "Wake Up Receiver", где в режиме постоянного прослушивания эфира находится не полноценный  трансивер, а некая схема по принципу детекторного радиоприемника, часто настренная на иную частоту, нежели та, что используется для передачи данных. Детектор на СВЧ-диоде Шоттки вылавливает из эфира "пробуждающий" импульс, который потом усиливается  сверхэкономичным ОУ, выход которого является линией внешнего прерывания для МК. Микроконтроллер пробуждается и запускает вполне себе традиционный передачик типа CC2540 или даже NRF24L01. Вобщем, "Wake Up Receiver" выглядеть может примерно так:

Собственное потребление TLV2401 -- 0.8мка, еще какие-то микротоки утекают через прочие элементы схемы и совокупное потребление чуть больше микроампера для данного "радио-пробудителя" представляется вполне достижимым.

velvol
Offline
Зарегистрирован: 04.03.2017

Спасибо CityCat за рабочий код.

d00m
Offline
Зарегистрирован: 21.02.2013

Viktor1306 пишет:

Мультиметром конечно, а чем их ещё меряют? Не линейкой же :) Мультиметр дорогой, не китайский за 250р. Я думаю, ему можно верить.

А как, ставлю мультиметр на 2000 мА, подключаю его последовательно с тем где хочу померить ток, и источником питания. Жду минуту, чтоб закончились все переходные процессы. И начинаю на мультиметре плавно уменьшать значение, так дохожу до микроамперов.

позвольте вопрос - вот в этом случае, при измерении потребления - ваше устройство как запитано?

от батарейки? 

у меня похожий мультиметр - MASTECH MS8268, но если я его включаю в цепь питания, чтобы измерить потребляемый ток - то моя ардуина постоянно перезагружается.

вот тут тема моя с деталями:

http://arduino.ru/forum/apparatnye-voprosy/mk-na-baze-atmega328-izmereni...

может подскажете чтото? 

LeXXkiev
Offline
Зарегистрирован: 20.03.2016

ASK-list

При каком напряжении питания Вам удалось завести вашу Nano? Как я смотрю по даташиту на 328Р, о питании от CR2030 (3V) или Li-Ion (3.7V) можно забыть со штатным кварцем на 16 МГц....

 

b707
Offline
Зарегистрирован: 26.05.2017

LeXXkiev пишет:

ASK-list

При каком напряжении питания Вам удалось завести вашу Nano? Как я смотрю по даташиту на 328Р, о питании от CR2030 (3V) или Li-Ion (3.7V) можно забыть со штатным кварцем на 16 МГц....

 

Нелогично покупать готовую плату (Нано), а потом удалять с нее элементы и резать дорожки и тд. Если нужно низкое потребление - купите микроконтроллер отдельно и запустите его на той частоте, на какой хотите.

ASK-list
Offline
Зарегистрирован: 17.01.2017
LeXXkiev пишет:
ASK-list 
При каком напряжении питания Вам удалось завести вашу Nano? Как я смотрю по даташиту на 328Р, о питании от CR2030 (3V) или Li-Ion (3.7V) можно забыть со штатным кварцем на 16 МГц....
 
Со спящими режимами на пониженном питании не экспериментировал, но вот нарушения обычной работы Nano при питании от Li-Ion у меня не происходило (в том числе при разряде аккумулятора до 3.6V).
 
b707 пишет:
Нелогично покупать готовую плату (Нано), а потом удалять с нее элементы и резать дорожки и тд. Если нужно низкое потребление - купите микроконтроллер отдельно и запустите его на той частоте, на какой хотите.
 
Подумывал о покупке микроконтроллера отдельно. Для домашней поделки проще перерезать две дорожки и получить энергопотребление в спящем режиме меньше 1 мкА, чем распаять на самодельной плате микроконтроллер и шить его программатором. К тому же цена платы теперь совсем небольшая.
 
Если купить Pro Mini - не факт, что резать ничего не придётся, а отдельный программатор также нужно будет подключать.

 

b707
Offline
Зарегистрирован: 26.05.2017

ASK-list пишет:

Подумывал о покупке микроконтроллера отдельно. Для домашней поделки проще перерезать две дорожки и получить энергопотребление в спящем режиме меньше 1 мкА, чем распаять на самодельной плате микроконтроллер и шить его программатором.

Самодельную плату так и так делать - что под готовую Нано, что под микроконтроллер. Вы же не станете собирать готовое изделие на бредборде с проводками, правильно? А "отдельный программатор" не нужен, достаточно другой Нано/Уно.

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


Привет ребята., помогите разобраться ... Сетуация такая Заганяю в спящий режим,  но после выхода из него  одна из функций (определения питания на входе в Ардуину).. Хочу следить за акамулятором  допустим раз в 15 мин..
Короче пока в сон не отправил всё работает, как в сон загнал.То после просыпания по Watchdog, функция readVcc() выводит последние показания перед сном, и больше не меняеться, только перезагрузка спасает.
Хоть по прерыванию бужу Ардуино или по количеству спящих режимов..

Вот код функций (определения напрежения на в ходе в Ардуину).

const long InternalReferenceVoltage = 1062;  // Adjust this value to your board's specific internal BG voltage

											 // Code courtesy of "Coding Badly" and "Retrolefty" from the Arduino forum
											 // results are Vcc * 100
											 // So for example, 5V would be 500.
int readVcc()
{
	// REFS0 : Selects AVcc external reference
	// MUX3 MUX2 MUX1 : Selects 1.1V (VBG)  
	ADMUX = bit(REFS0) | bit(MUX3) | bit(MUX2) | bit(MUX1);
	ADCSRA |= bit(ADSC);  // start conversion
	while (ADCSRA & bit(ADSC))
	{
	}  // wait for conversion to complete
	int results = (((InternalReferenceVoltage * 1024) / ADC) + 5) / 10;
	return results;
	
} // end of getBandgap

А вот кот  sleepNow(), после которого функция  readVcc() не работает..

Я думаю что это связано с этой  проблемай

ACSR |= (1 << ACD);       // отключаем Аналоговый компаратор

 ADCSRA = 0;               // отключаем Аналоговый компаратор (такой код в других скетчах)

 

 
void sleepNow()         // Функция увода ардуины в спячку

{

	pr_Li_ion_Bat++;// переменая для проверки батареи через определённый периуд времени (считаем сколько раз уснули)
	digitalWrite(LED_BUILTIN, LOW);             // Выключаем светодиод

											//	
											//	for (byte i = 0; i <= A5; i++)         // переводим пины в режим выхода (закомментировано, т.к. виснет после засыпания)
											//	
											//	pinMode (i, OUTPUT);    // changed as per below
											//	digitalWrite (i, LOW);  //     ditto
											//	}
											//	

	ACSR |= (1 << ACD);       // отключаем Аналоговый компаратор

	ADCSRA = 0;               // отключаем Аналоговый компаратор (такой код в других скетчах)

	power_all_disable();      // отключаем все внутренние блоки ЦП. (требуется <avr/power.h> + эта строчка должн быть после ADCSRA=0)

							  // power_adc_disable();   // ADC converter

							 //  power_spi_disable();   // SPI

							 //power_usart0_disable();// Serial (USART)
							 
							  // power_timer0_disable();// Timer 0

							  // power_timer1_disable();// Timer 1

							  // power_timer2_disable();// Timer 2

							//   power_twi_disable();   // TWI (I2C)

							  // отключаем BOD

	noInterrupts(); // cli(); // отключение прерываний

	uint8_t x = (MCUCR & ~(1 << BODSE)) | (1 << BODS); // подготовка бит

	MCUCR = x | (1 << BODSE); // процедура отключения BOD

	MCUCR = x;

	interrupts(); //sei(); // включение прерываний

				  // конец отключения BOD

				  // подготовка WatchDog 

	MCUSR = 0;  // clear various "reset" flags

	WDTCSR = bit(WDCE) | bit(WDE); // allow changes, disable reset

								   // set interrupt mode and an interval  

	WDTCSR = bit(WDIE) | bit(WDP3) | bit(WDP0);    // set WDIE, and 8 seconds delay

												   //WDTCSR = bit (WDIE) | bit (WDP2) | bit (WDP1);  // set WDIE, and 1 second delay

	wdt_reset();  // pat the dog

				  // конец подготовки WatchDog

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


	
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // устанавливается режим сна (это не вход в сон! Только установка режима!)

	sleep_enable();                        // включаем sleep-бит в регистре mcucr. Теперь возможен сон

	sleep_mode();    //sleep_cpu();        // Здесь устройство перейдет в режим сна. Внешние прерывания и WDT продолжают работать.



					 // -----------------------------------------------ПОСЛЕ ПРОСЫПАНИЯ ВЫПОЛНЕНИЕ КОДА ПРОДОЛЖИТСЯ ОТСЮДА!!!


	wakeUpNow();

}


void wakeUpNow()        // Пробуждение по внешнему прерыванию

{

	//}
	// Таймеы и код, использующий таймеры (serial.print и др...) здесь не будут работать

	// Также мы не должны выполнять какие-то спец. функции, здесь мы просто просыпаемся

	sleep_disable();                       // отключаем спящий режим

	power_all_enable();                    // включаем все внутренние блоки ЦП

	wdt_disable();                         // нужно ли здесь это?

	config();                              // настраиваем входы/выходы

	detachInterrupt(0);                    // Выключаем прерывание - при нормальном режиме wakeUpNow() не будет вызываться


}


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

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ruslan_rachinsk, а что тут разбираться? Копипастить с умом нужно. Засыпая вы отрубаете АЦП (18 строка) , а кто его включать будет обратно?

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

Понял почему не работает readVcc() ,после спящего режима..

Короче после спящего пежима константа (переменная) ADCSRA = 0;остаётся пустой 

А перед спящим режимом константа работает и она не пустая..

Так вот вопрос, как вернуть константt (переменная) ADCSRA нужное значение..

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

dimax пишет:

ruslan_rachinsk, а что тут разбираться? Копипастить с умом нужно. Засыпая вы отрубаете АЦП (18 строка) , а кто его включать будет обратно?

Я начинающий, слабо сдесь понемаю, а разве вот это строка не включает всё сразу..

power_all_enable();                    // включаем все внутренние блоки ЦП

Токда подскажи как включить..

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

Тема закрыта, разобрался..

Всем пока спасибо...

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

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