ATTINY / Watchdog - Unexpected behavior. Help w/ review and troubleshooting

Hey folks.

I’m working on an adaptation of some spooky eyes illustrated here:

My plan was to add a day/night indicator using an LDR. Since all of the IO pins of the ATTINY were in use driving the LEDS (and I didnt want to set the fuse for the reset pin) i chose to repurpose one of the pins for input and then reassign it to output.

The code for the LDR/LED functionality works without issue and as expected.

The issue comes when I add the WATCHDOG/SLEEP combo to this. My goal there was to add some power saving elements so that during the day it has a very low draw. I expected this to wake every 8 seconds, poll the LDR, and if its still light go back to sleep.

When implemented, I’m getting unexpected LED lighting during the light period. I’m not sure why I would unless there is some interaction in the timer/sleep thats causing issues for my code. Alternately, I thought perhaps there might be some errant readings from the LDR and I need to add some code to average out readings or hysteresis.

Any and all help would be greatly appreciated. I am absolutely a novice and am doing my best to work through this as an educational experience.

//--Spooky Eyes V3
//
#include <avr/sleep.h>;
#include <avr/wdt.h>;
// #define adc_disable() (ADCSRA &= ~(1<<ADEN))



int led[]={0,1,2,3,4};
int darkpin=A1;
int count=0;
int delayTime = 40;
int darkindicator = 1;
volatile boolean f_wdt = 1;


void setup()//--set all pins to output
{
for (int x=0;x<5;x++){
pinMode(led[x],OUTPUT);
}

  // adc_disable();  // NOT FUNCTIONING and removed.
}


// PWM LED 
void spwm(int freq,int spin,int sp){
//--on
digitalWrite(spin,HIGH);
delayMicroseconds(sp*freq);

//--off
digitalWrite(spin,LOW);
delayMicroseconds(sp*(255-freq));
} //spwm


void system_sleep() {
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode
  sleep_enable();
  sleep_mode();
  sleep_disable();
}

void setup_watchdog(int ii) {
  byte bb;
  int ww;
  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);
  ww=bb;
  MCUSR &= ~(1<<WDRF);
  // start timed sequence
  WDTCR |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCR = bb;
  WDTCR |= _BV(WDIE);
}
   
// Watchdog Interrupt Service / is executed when watchdog timed out
ISR(WDT_vect) {
  f_wdt=1;
}


void loop()
{

  
pinMode(darkpin,INPUT);
darkindicator = analogRead(darkpin); // This reads the value of the LDR to determine if its dark.
if (darkindicator > 200)  //  If value is greater than 200, assume its dark and continue to light LEDs
{
  //  This is the LED LIGHTING CODE
  
  pinMode(2,OUTPUT); //Reset PIN 2 to output.
  delayTime= random(3,80);// Set values between 2 and 80 -- How long LED stays on
  count= (random(0,5));

  // Fading On--
  for (int x=1;x<254;x++) 
  {
  spwm(x,led[count],delayTime);
  }

  //--Fading Off
  for(int x=254;x>1;x--)
  {
  spwm(x,led[count],4);
  //--the last argument can be "delayTime" variable if you want to fade out same way as you faded on. 
  //--Setting it to 1 or 2 turns off lights real fast like the eyelid is closing
  }
  count= random(0,2);

  delay(random(100,2000));//--- amount of time leds are OFF 

// END LED LIGHTING CODE

}
else
{
   //  WATCHDOG SLEEP MODE  

  if (f_wdt==1) {
    f_wdt=0;
    setup_watchdog(9);
    system_sleep();

    // END WATCHDOG SLEEP MODE
  }
  
}

}
pinMode(darkpin,INPUT);
darkindicator = analogRead(darkpin); // This reads the value of the LDR to determine if its dark.

Analog pins are input only. Setting the mode of the digital pin that shares the same physical location is pointless.

pinMode(darkpin,INPUT);
  pinMode(2,OUTPUT); //Reset PIN 2 to output.

Why do some pinMode() calls use pin numbers and others use variables that contain pin numbers (aka names)? Consistency is a good thing.

  delayTime= random(3,80);// Set values between 2 and 80 -- How long LED stays on
  count= (random(0,5));

Why is the random() function call wrapped in useless parentheses in one case but not the other? Did I mention that consistency is a good thing.

void setup_watchdog(int ii) {

With an argument name like that, it is certainly easy to understand what value to pass to the function to get the results desired. NOT!

I suspect that your real problem, though, is that you can't use a pin for analog input and digital output at the same time.

Thanks for the quick reply.

I certainly understand the inconsistencies in the code. These were pulled from various sources. The input/output change is mine and obviously can be cleaned up somewhat. I'm a novice at this-- and that clearly is illustrated in this code. I'll work to clean up some of that when I get functionality working.

Your comments on the use of input and output pins in use at the same time is curious. What doesnt make sense to me is that this functions as expected when I remove all of the sleep/watchdog functionality. The LEDs remain dark when there is enough light on the LDR. When its covered, the circuit starts its loop to light the lights. I don't seem to have any issues using the same pin as its being constantly redefined throughout the loop. The ATTINY85 pin 2 shares both analog and digital in the layout I saw. Does this break some cardinal rule of AVR coding to do that?

How do you pin 2 wired, presumably with both an LDR and LEDs?

Correct. Its wired simultaneously to the LDR/POT for measurement and to a resistor/LED for the lighting portion. In light, the calibrated analog readings are in the 50-100 range.. In dark, I'm getting 200-400. The signal is low and not enough to light the LED. Its why I went analog here.

Again, that piece seems to work -- albeit I came up with the idea since I had no other pins outside of the reset pin to use.

I can draw it up tonight and post a schematic if its helpful.

Please post a hand drawn schematic (not Fritzing), with component values.

I see you said no fritzing. It seems the easiest way to put this together so hopefully its ok.

Hopefully this is clear enough to get the idea. I’m thinking its pretty straight forward.

That "schematic" is acceptable, whereas most breadboard Fritzing diagrams are not.

I don't see an obvious problem, except for a possible problem of the LDR loading down the uP output pin (an LDR can have resistance ranging anywhere from a few ohms to megohms). Of course, the LEDs screw up the voltage divider with very nonlinear effects -- they are light sensitive and act as photodiodes.

  1. Try reading the analog input twice and ignore the first reading. Sometimes the first is nonsense.

  2. Try eliminating the LEDs associated with that pin, and dedicate it to input, to see if the problem goes away.

Otherwise debug using print statements to see what analogRead returns.