Code gets stuck

Hi all!

I have a problem with one of my codes and after trying to solve it on many evenings, I’ve finally gave up. :confused:
Hopefully someone here can help me! :slight_smile:

The provided code is used for a night-/mobile light and in my point of view nothing special. It’s running on an attiny85 with a lithium battery. And that is the reason, why I used the “power down” sleep mode in my code.

So what’s my problem: With an attached pullup button, I can toggle within three modes. Off / On / PIR-Mode combined with an LDR. All these modes let the LEDs fade in and out.

The problem happens, when I toggle from the starting mode 0 (off), to mode 1 (on), mode 2 (PIR) and then back to mode 0. If I wait for a completely fade out, it stucks.
But when I enable the “Testcode” in my code, everything works smooth.

Thank you very much for your support!

// ATMEL ATTINY 25/45/85 / ARDUINO
//
//                  +-/-+
// Ain0 (D 5) PB5  1|    |8  Vcc
// Ain3 (D 3) PB3  2|    |7  PB2 (D 2) Ain1
// Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
//            GND  4|    |5  PB0 (D 0) pwm0
//                  +----+

//#define DEBUG

#define USEPIR
#define USELDR
#define AUTOADJUST

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

#ifndef DEBUG
const byte LED = 0;
#else
#include <SendOnlySoftwareSerial.h>
SendOnlySoftwareSerial Serial(0);
#endif

#ifdef USEPIR
const byte PIR = 2;

unsigned int pirTimeout = 30; // wait x times for watchdog to wake up (once a second per default)
unsigned int pirTrigger = pirTimeout;
#endif

#ifdef USELDR
const byte LUM = A2;
const byte LUMPOWER = 3;

unsigned int lumLimit = 768; // as darker as higher ;-) (take care of automatic adjustment function)
const int lumThreshold = 50;
#endif

const byte BUTTON = 1;

byte ledPWM = 0;
byte currentMode = 0;
unsigned long lastButtonPress = 0;

ISR (PCINT0_vect) {
  wdt_disable();
}

#if defined USELDR || defined USEPIR
ISR (WDT_vect) {
  wdt_disable();
}
#endif

void setup() {
#if defined USELDR || defined USEPIR
  resetWatchdog();
#endif

#ifndef DEBUG
  pinMode (LED, OUTPUT);
#else
  Serial.begin(9600);
  Serial.println("Startup...");
#endif

#ifdef USEPIR
  pinMode (PIR, INPUT);
#endif
#ifdef USELDR
  pinMode (LUM, INPUT);
  pinMode (LUMPOWER, OUTPUT);
#endif
  pinMode (BUTTON, INPUT_PULLUP);

  for ( int flashCount = 0; flashCount < 3; flashCount++ ) {
    while (ledPWM<255) {
#ifdef DEBUG
      Serial.print("r");
#endif
      rampUpDown(1,5);
    }
    while (ledPWM>0) {
#ifdef DEBUG
      Serial.print("r");
#endif
      rampUpDown(0,5);
    }
#ifndef DEBUG
    digitalWrite(LED, LOW);
#endif
    delay(250);
  }
#ifdef DEBUG
  Serial.println();
#endif

  PCMSK = 0b00000110;
  GIFR   |= bit (PCIF);
  GIMSK  |= bit (PCIE);

}  // end of setup

void loop() {

  if ( digitalRead(BUTTON) == LOW ) {
    if ( millis() - lastButtonPress > 500 ) {
#if defined USELDR || defined USEPIR
      if ( currentMode < 2 )
#else
      if ( currentMode < 1 )
#endif
        currentMode++;
      else {
        currentMode = 0;
#if defined USELDR || defined USEPIR
        digitalWrite(LUMPOWER, LOW);
#endif
      }
      lastButtonPress = millis();
#ifdef DEBUG
      Serial.print("nrMode: ");
      Serial.println(currentMode);
#endif
    }
/* Testcode
    if ( currentMode == 0 ) {
      while ( ledPWM > 0 ) {
        rampUpDown(0,1);
      }
      while (ledPWM<255) {
        rampUpDown(1,1);
      }
      while (ledPWM>0) {
        rampUpDown(0,1);
      }
    }
    else */ if ( currentMode == 2 ) {
      digitalWrite(LUMPOWER, HIGH);
      for ( byte counter = 0; counter < 3; counter++ ) {
        while (ledPWM<255) {
#ifdef DEBUG
          Serial.print("r");
#endif
          rampUpDown(1,1);
        }
        while (ledPWM>0) {
#ifdef DEBUG
          Serial.print("r");
#endif
          rampUpDown(0,1);
        }
      }
#ifdef DEBUG
      Serial.println();
#endif
    }
  }
  
  if ( currentMode == 0 ) {
#ifdef DEBUG
    Serial.print("rChecking PWM value... ");
#endif
    if ( ledPWM > 0 ) {
      rampUpDown(0,10);
    }
    else {
#ifdef DEBUG
      Serial.println();
#endif
      goToSleep(0);
    }
  }

  else if ( currentMode == 1 ) {
#ifdef DEBUG
    Serial.print("rChecking PWM value... ");
#endif
    if ( ledPWM < 255 ) {
      rampUpDown(1,10);
    }
    else {
#ifdef DEBUG
      Serial.println();
#endif
      goToSleep(0);
    }
  }

#if defined USEPIR || defined USELDR
  else if ( currentMode == 2 ) {
    int lumValue = analogRead(LUM);
#ifdef AUTOADJUST
    if ( lumLimit < 1020 && lumValue > lumLimit ) {
      lumLimit = lumValue < 1020 ? lumValue : 1020;
#endif
#ifdef DEBUG
      Serial.print("LUM: ");
      Serial.print(lumValue);
      Serial.println();
#endif
    }
    bool pirValue = LOW;
    if ( digitalRead(PIR) == HIGH && lumValue >= lumLimit ) {
      pirTrigger = 0;
#ifdef DEBUG
      Serial.print(" - Motion detected");
#endif
    }
    if ( pirTrigger < pirTimeout ) {
      pirValue = HIGH;
#ifdef DEBUG
      Serial.print(" - Checking PWM value... ");
      Serial.println(ledPWM);
#endif
      if ( ledPWM == 255 )
        pirTrigger++;
    }
  
#ifdef DEBUG
    Serial.print("r");
    Serial.print(millis());
    Serial.print(" pirValue: ");
    Serial.print(pirValue);
    Serial.print(" ");
#endif
  
    if ( pirValue == LOW && ledPWM == 0 ) {
      digitalWrite(LUMPOWER, LOW);
      pirTrigger = pirTimeout;
      goToSleep(0);
      digitalWrite(LUMPOWER, HIGH);
    }
    else if ( ( pirValue == LOW || lumValue < ( lumLimit - lumThreshold ) ) && ledPWM > 0 ) {
      rampUpDown(0,10);
    }
    else if ( pirValue == HIGH && ledPWM == 255 ) {
      goToSleep(1);
    }
    else if ( pirValue == HIGH && ( ( lumValue >= lumLimit && ledPWM < 255 ) || ( lumValue >= ( lumLimit - lumThreshold ) && ledPWM > 0 && ledPWM < 255 ) ) ) {
      rampUpDown(1,5);
    }
  }
#endif

void goToSleep(bool useWDT) {
#ifdef DEBUG
    Serial.print(millis());
    Serial.print(" - Goto sleep mode: ");
    Serial.println(useWDT);
#endif
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  byte keepADCSRA = ADCSRA;
  ADCSRA = 0;
  power_all_disable();
  noInterrupts();
#if defined USEPIR || defined USELDR
  if ( useWDT == 1 ) resetWatchdog();
#endif
  sleep_enable();
  interrupts();
  sleep_cpu();
  sleep_disable();
  power_all_enable();
  ADCSRA = keepADCSRA;
}

#if defined USEPIR || defined USELDR
void resetWatchdog() {
  MCUSR = 0;
  WDTCR = bit (WDCE) | bit (WDE) | bit (WDIF);
  WDTCR = bit (WDIE) | bit (WDP2) | bit (WDP1);
  wdt_reset();
}
#endif

void rampUpDown(bool upDown, byte speed) {
  if ( upDown == 1 ) ledPWM++;
  else ledPWM--;

#ifndef DEBUG
  analogWrite(LED,ledPWM);
#else
  Serial.print("Ramp... ");
  Serial.print(ledPWM);
  Serial.print("  ");
#endif
  delay(speed);
}

Hello there!

What is the micro controller doing when the code “freezes”?