Контроллер просыпается по таймеру но код исполняется странно

10mills
Offline
Зарегистрирован: 17.02.2018

Доброго дня!

Делаю простой проектик, но захотелось чтоб с перламутровыми пуговицами, на солнечных батареях и фотонным двигателем :)

Это типа ночника, сувенир, стоит на полке и в момент когда в комнате гаснет свет, включается не надолго подсветка (во первых красиво, во вторых можно дойти, например, до кровати).

Для экономии решил его спать. Основная часть кода- пример из интернета, кое что дописал.

Теперь о проблеммах, пока это был "блинк" все работало, но с моим функционалом работает не очень и через раз. Более того, вставляя Serial.print() для отладки, печатает какой то мусор. В тои месте гда идет сравнение текущего и предидущего значений освещенности ( если поставить Serial.print() и оградить его delay() ) можно видеть, что последнее "предидущее" значение не соотвествует "текущему" на шаг назад... Немного путанно, короче, то что он показывает, это не то, что он измерял и напечатал в прошый раз.

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


#include <avr/sleep.h>     //AVR MCU power management
#include <avr/power.h>     //disable/anable AVR MCU peripheries (Analog Comparator, ADC, USI, Timers/Counters)
#include <avr/wdt.h>       //AVR MCU watchdog timer
#include <avr/io.h>        //includes the apropriate AVR MCU IO definitions
#include <avr/interrupt.h> //manipulation of the interrupt flags
#include "OneButton.h"

#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
#endif

#define LIGHT  3
#define SENSOR A0
#define SWITCH 0

volatile int bri, preBri, temp, test, ledBri;
volatile boolean flag;
volatile boolean dark;
volatile boolean autoLight = true;

OneButton button(SWITCH, true);
/*
    setup()
    Main setup
    NOTE:
    - valid sleep intervals: WDTO_15MS,  WDTO_30MS,  WDTO_60MS, WDTO_120MS
                             WDTO_250MS, WDTO_500MS, WDTO_1S,   WDTO_2S
                             WDTO_4S,    WDTO_8S
*/

void setup() {
  Serial.begin(9600);

  ledBri = 32;
  pinMode (SENSOR, INPUT);
  pinMode (LIGHT, OUTPUT);
  preBri = analogRead (SENSOR);
  button.attachClick(click1);
  button.attachLongPressStart(longPressStart);
  setup_watchdog(WDTO_500MS); //time to sleep
}

void loop() {

  if (autoLight) {

    while (!flag) {                                     // МК спит, пока сторожевой таймер не снимет флаг
      arduino_sleep();
    }
                                                        // МК если таймер сработал, должен выполниться код ниже
    wdt_disable();                                      // отключить таймер

    flag = false;                                       // вернуть флаг, чтоб МК снова уснул
    power_all_enable();                                 // включить переферию
    delay(10);
    if (!digitalRead(SWITCH)) {                         // ручное включение света
      autoLight = false;
      ledBri = 1;
    }
    bri = analogRead (SENSOR);                          // чтение сенсора освещенности

    if (bri < 200 && preBri >= 250 && bri < preBri) {   // сравнение с предидущим значением
      light();                                          // если ДА плавно включить и потушить свет
    }
    preBri = bri;                                       // запись текущего значения для последующего сравнения

    if (bri < 250) {                                    // запуск сторожевого таймера, если темно то на большее время
      wdt_enable(WDTO_2S);
    }
    else {
      wdt_enable(WDTO_500MS);
    }
  }
  else {                                                // ручное управление
    button.tick();
    if (!autoLight) {
      wdt_disable();
      analogWrite(LIGHT, ledBri);
    }
  }
}

/**************************************************************************/

void light() {
  wdt_disable();
  analogWrite(LIGHT, 92);
  for (int i = 92; i < 255; i++) {
    delay(15);
    analogWrite(LIGHT, i);
    if (analogRead (SENSOR) > 250) {
      analogWrite(LIGHT, 0);
      return;
    }
  }
  delay(5000);
  for (int i = 255; i > 0; i--) {
    delay(25);
    analogWrite(LIGHT, i);
    if (analogRead (SENSOR) > 250) {
      analogWrite(LIGHT, 0);
      return;
    }
  }
  analogWrite(LIGHT, 0);
}
/*****************************************************************************/

void arduino_sleep()
{
  cli();                               //disable interrupts for time critical operations below

  power_all_disable();                 //disable all peripheries (ADC, Timer0, Timer1, Universal Serial Interface)

  //    power_adc_disable();                 //disable ADC
  //    power_timer0_disable();              //disable Timer0
  //    power_timer1_disable();              //disable Timer2
  //    power_usi_disable();                 //disable the Universal Serial Interface module

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); //set sleep type

#if defined(BODS) && defined(BODSE)  //if MCU has bulit-in BOD it will be disabled, ATmega328P, ATtiny85, AVR_ATtiny45, ATtiny25  
  sleep_bod_disable();                 //disable Brown Out Detector (BOD) before going to sleep, saves more power
#endif

  sei();                               //re-enable interrupts

  sleep_mode();                        /*
                                             system stops & sleeps here, it automatically sets Sleep Enable (SE) bit,
                                             so sleep is possible, goes to sleep, wakes-up from sleep after interrupt,
                                             if interrupt is enabled or WDT enabled & timed out, than clears the SE bit.
*/

  /*** NOTE: sketch will continue from this point after sleep ***/
}

void setup_watchdog(byte sleep_time)
{
  cli();                           //disable interrupts for time critical operations below

  wdt_enable(sleep_time);          //set WDCE, WDE change prescaler bits

  MCUSR &= ~_BV(WDRF);             //must be cleared first, to clear WDE

#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
  WDTCR  |= _BV(WDCE) & ~_BV(WDE); //set WDCE first, clear WDE second, changes have to be done within 4-cycles
  WDTCR  |= _BV(WDIE);             //set WDIE to Watchdog Interrupt
#else
  WDTCSR |= _BV(WDCE) & ~_BV(WDE); //set WDCE first, clear WDE second, changes have to be done within 4-cycles
  WDTCSR |= _BV(WDIE);             //set WDIE to Watchdog Interrupt
#endif

  sei();                           //re-enable interrupts
}

/**************************************************************************/
/*
    ISR(WDT_vect)

    Watchdog Interrupt Service Routine, executed when watchdog is timed out

    NOTE:
    - if WDT ISR is not defined, MCU will reset after WDT
*/
/**************************************************************************/
ISR(WDT_vect)
{
  flag = true;
}

void click1() {
  if (!autoLight) {
    ledBri = ledBri + 32;
    if (ledBri > 255) ledBri = 32;
  }
}

void longPressStart() {
  autoLight = true;
  analogWrite(LIGHT, 0);
  wdt_enable(WDTO_500MS);
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

10mills пишет:
захотелось чтоб с перламутровыми пуговицами, на солнечных батареях и фотонным двигателем :)

Отсюда и все беды. Делали б как все нормальные люди с блэкджеком и шлюхами, так всё бы работало, и даже корованы грабились бы. А так ...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

10mills пишет:

В тои месте гда идет сравнение текущего и предидущего значений освещенности ( если поставить Serial.print() и оградить его delay() ) можно видеть, что последнее "предидущее" значение не соотвествует "текущему" на шаг назад... 

Давайте, Вы это сделаете и выложите а) именно тот скетч и б) лог печати. Хочется посмотреть.

И, да, кстати, посмотрите на условия в строке №61. Вам не кажется, что последнее условие - лишнее?

10mills
Offline
Зарегистрирован: 17.02.2018

Какой "тот"? Он у меня один, вот он же с принтами


#include <avr/sleep.h>     //AVR MCU power management
#include <avr/power.h>     //disable/anable AVR MCU peripheries (Analog Comparator, ADC, USI, Timers/Counters)
#include <avr/wdt.h>       //AVR MCU watchdog timer
#include <avr/io.h>        //includes the apropriate AVR MCU IO definitions
#include <avr/interrupt.h> //manipulation of the interrupt flags
#include "OneButton.h"

#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
#endif

#define LIGHT  3
#define SENSOR A0
#define SWITCH 0

volatile int bri, preBri, temp, test, ledBri;
volatile boolean flag;
volatile boolean dark;
volatile boolean autoLight = true;

OneButton button(SWITCH, true);
/*
    setup()
    Main setup
    NOTE:
    - valid sleep intervals: WDTO_15MS,  WDTO_30MS,  WDTO_60MS, WDTO_120MS
                             WDTO_250MS, WDTO_500MS, WDTO_1S,   WDTO_2S
                             WDTO_4S,    WDTO_8S
*/

void setup() {
  Serial.begin(19200);

  ledBri = 32;
  pinMode (SENSOR, INPUT);
  pinMode (LIGHT, OUTPUT);
  preBri = analogRead (SENSOR);
  button.attachClick(click1);
  button.attachLongPressStart(longPressStart);
  setup_watchdog(WDTO_500MS); //time to sleep
}

void loop() {

  if (autoLight) {

    while (!flag) {                                     // МК спит, пока сторожевой таймер не снимет флаг
      arduino_sleep();
    }
    // МК если таймер сработал, должен выполниться код ниже
    wdt_disable();                                      // отключить таймер

    flag = false;                                       // вернуть флаг, чтоб МК снова уснул
    power_all_enable();                                 // включить переферию
    delay(10);
    if (!digitalRead(SWITCH)) {                         // ручное включение света
      autoLight = false;
      ledBri = 1;
    }
    bri = analogRead (SENSOR);                          // чтение сенсора освещенности

    Serial.print("Light current: ");
    Serial.print(bri);
    Serial.print("   ");
    Serial.print("Light previous: ");
    Serial.print(preBri);
    Serial.println();
    delay(30);

    if (bri < 200 && preBri >= 250 && bri < preBri) {   // сравнение с предидущим значением
      light();                                          // если ДА плавно включить и потушить свет
    }
    preBri = bri;                                       // запись текущего значения для последующего сравнения

    if (bri < 250) {                                    // запуск сторожевого таймера, если темно то на большее время
      wdt_enable(WDTO_2S);
    }
    else {
      wdt_enable(WDTO_500MS);
    }
  }
  else {                                                // ручное управление
    button.tick();
    if (!autoLight) {
      wdt_disable();
      analogWrite(LIGHT, ledBri);
    }
  }
}

/**************************************************************************/

void light() {
  wdt_disable();
  analogWrite(LIGHT, 92);
  for (int i = 92; i < 255; i++) {
    delay(15);
    analogWrite(LIGHT, i);
    if (analogRead (SENSOR) > 250) {
      analogWrite(LIGHT, 0);
      return;
    }
  }
  delay(5000);
  for (int i = 255; i > 0; i--) {
    delay(25);
    analogWrite(LIGHT, i);
    if (analogRead (SENSOR) > 250) {
      analogWrite(LIGHT, 0);
      return;
    }
  }
  analogWrite(LIGHT, 0);
}
/*****************************************************************************/

void arduino_sleep()
{
  cli();                               //disable interrupts for time critical operations below

  power_all_disable();                 //disable all peripheries (ADC, Timer0, Timer1, Universal Serial Interface)

  //    power_adc_disable();                 //disable ADC
  //    power_timer0_disable();              //disable Timer0
  //    power_timer1_disable();              //disable Timer2
  //    power_usi_disable();                 //disable the Universal Serial Interface module

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); //set sleep type

#if defined(BODS) && defined(BODSE)  //if MCU has bulit-in BOD it will be disabled, ATmega328P, ATtiny85, AVR_ATtiny45, ATtiny25  
  sleep_bod_disable();                 //disable Brown Out Detector (BOD) before going to sleep, saves more power
#endif

  sei();                               //re-enable interrupts

  sleep_mode();                        /*
                                             system stops & sleeps here, it automatically sets Sleep Enable (SE) bit,
                                             so sleep is possible, goes to sleep, wakes-up from sleep after interrupt,
                                             if interrupt is enabled or WDT enabled & timed out, than clears the SE bit.
*/

  /*** NOTE: sketch will continue from this point after sleep ***/
}

void setup_watchdog(byte sleep_time)
{
  cli();                           //disable interrupts for time critical operations below

  wdt_enable(sleep_time);          //set WDCE, WDE change prescaler bits

  MCUSR &= ~_BV(WDRF);             //must be cleared first, to clear WDE

#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
  WDTCR  |= _BV(WDCE) & ~_BV(WDE); //set WDCE first, clear WDE second, changes have to be done within 4-cycles
  WDTCR  |= _BV(WDIE);             //set WDIE to Watchdog Interrupt
#else
  WDTCSR |= _BV(WDCE) & ~_BV(WDE); //set WDCE first, clear WDE second, changes have to be done within 4-cycles
  WDTCSR |= _BV(WDIE);             //set WDIE to Watchdog Interrupt
#endif

  sei();                           //re-enable interrupts
}

/**************************************************************************/
/*
    ISR(WDT_vect)

    Watchdog Interrupt Service Routine, executed when watchdog is timed out

    NOTE:
    - if WDT ISR is not defined, MCU will reset after WDT
*/
/**************************************************************************/
ISR(WDT_vect)
{
  flag = true;
}

void click1() {
  if (!autoLight) {
    ledBri = ledBri + 32;
    if (ledBri > 255) ledBri = 32;
  }
}

void longPressStart() {
  autoLight = true;
  analogWrite(LIGHT, 0);
  wdt_enable(WDTO_500MS);
}

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

https://github.com/enjoyneering/Arduino_Deep_Sleep/blob/master/arduino_d...

лог, то что отмеченно, должно быть одинаковым, по моему разумению.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

10mills пишет:

Какой "тот"? Он у меня один, вот он же с принтами

Вот, правильно. "Тот" - это тот, который печатает. Хочется смотреть на то как печатает и на результат, а не догадываться. Щас посмотрим неспеша.