Arduino freezes after using PWM on LED

I am currently building an iteration of a word clock from http://www.highonsolder.com/blog/2011/1/8/arduino-word-clock.html?currentPage=8

The clock appears to run smoothly, but the problem begins when I try to use a photoresistor to dim the LED lights. For some reason, whenever I activate the code, the clock will become unstable. The microprocessor will hang up and freeze randomly. Sometimes it will happen few seconds after it starts running or sometimes it will freeze up minutes later. The only way to restart it is to unplug the device. I don’t know if there is some memory leak that is going on. I built several protypes, thinking maybe one of them has been wired incorrectly. But every built still reacts the same way.

I suspect it has something to do with the PWM. I tried deactivating the dimming code and manually adjusted the the brightness from the following line: " //analogWrite(PWMPin, 255); //manually set brightness level" and it started acting up again. For some reason if I leave it by default at 255, it will run smoothly. But once I change the setting to a lower value, it’ll become unstable again.

I tried using numerous power sources. I used an FTDI cable to the computer and an external 5v power source and it’s still giving me trouble. I tried using both schematics. The second schematic uses a NPN 2N3904 transistor. I have to split the code into two posts because of the character limit. Any help is greatly appreciated.

// Display output pin assignments
#define MTEN 	Display1=Display1 | (1<<0)  
#define HALF	Display1=Display1 | (1<<1)
#define QUARTER	Display1=Display1 | (1<<2)
#define TWENTY	Display1=Display1 | (1<<3)
#define MFIVE	Display1=Display1 | (1<<4)
#define MINUTES	Display1=Display1 | (1<<5)
#define PAST	Display1=Display1 | (1<<6)
#define UNUSED1	Display1=Display1 | (1<<7)

#define TO	Display2=Display2 | (1<<0)
#define ONE	Display2=Display2 | (1<<1)
#define TWO	Display2=Display2 | (1<<2)
#define THREE	Display2=Display2 | (1<<3)
#define FOUR	Display2=Display2 | (1<<4)
#define HFIVE	Display2=Display2 | (1<<5)
#define SIX	Display2=Display2 | (1<<6)
#define UNUSED2	Display2=Display2 | (1<<7)

#define SEVEN	Display3=Display3 | (1<<0)
#define EIGHT	Display3=Display3 | (1<<1)
#define NINE	Display3=Display3 | (1<<2)
#define HTEN	Display3=Display3 | (1<<3)
#define ELEVEN	Display3=Display3 | (1<<4)
#define TWELVE	Display3=Display3 | (1<<5)
#define OCLOCK  Display3=Display3 | (1<<6)
#define UNUSED3	Display3=Display3 | (1<<7)

int  hour=9, minute=30, second=00;
static unsigned long msTick =0;  // the number of Millisecond Ticks since we last 
                                 // incremented the second counter
int  count;
char Display1=0, Display2=0, Display3=0;

// hardware constants
int LEDClockPin=6;
int LEDDataPin=7;
int LEDStrobePin=8;

int MinuteButtonPin=2;
int HourButtonPin=3;
int PWMPin = 9;

int PhotoCellReading;
int LedBrightness=255;



void setup()
{
  // initialise the hardware	
  // initialize the appropriate pins as outputs:
  pinMode(LEDClockPin, OUTPUT); 
  pinMode(LEDDataPin, OUTPUT); 
  pinMode(LEDStrobePin, OUTPUT); 
  
  //pinMode(BrightnessPin, INPUT);
  pinMode(MinuteButtonPin, INPUT); 
  pinMode(HourButtonPin, INPUT);
  
  pinMode(PWMPin, OUTPUT); 
  
  Serial.begin(19200);

  msTick=millis();      // Initialise the msTick counter
  displaytime();        // display the current time
}


void ledsoff(void) {
 Display1=0;
 Display2=0;
 Display3=0;
 }


void WriteLEDs(void) {
 // Now we write the actual values to the hardware
 shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display3);
 shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display2);
 shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display1);
 digitalWrite(LEDStrobePin,HIGH);
 delay(2);
 digitalWrite(LEDStrobePin,LOW); 
 }


void displaytime(void){

  // start by clearing the display to a known state
  ledsoff();
  
  Serial.print("It is ");

  // now we display the appropriate minute counter
  if ((minute>4) && (minute<10)) { 
    MFIVE; 
    MINUTES; 
    Serial.print("Five Minutes ");
  } 
  if ((minute>9) && (minute<15)) { 
    MTEN; 
    MINUTES; 
    Serial.print("Ten Minutes ");
  }
  if ((minute>14) && (minute<20)) {
    QUARTER; 
      Serial.print("Quarter ");
  }
  if ((minute>19) && (minute<25)) { 
    TWENTY; 
    MINUTES; 
    Serial.print("Twenty Minutes ");
  }
  if ((minute>24) && (minute<30)) { 
    TWENTY; 
    MFIVE; 
    MINUTES;
    Serial.print("Twenty Five Minutes ");
  }  
  if ((minute>29) && (minute<35)) {
    HALF;
    Serial.print("Half ");
  }
  if ((minute>34) && (minute<40)) { 
    TWENTY; 
    MFIVE; 
    MINUTES;
    Serial.print("Twenty Five Minutes ");
  }  
  if ((minute>39) && (minute<45)) { 
    TWENTY; 
    MINUTES; 
    Serial.print("Twenty Minutes ");
  }
  if ((minute>44) && (minute<50)) {
    QUARTER; 
    Serial.print("Quarter ");
  }
  if ((minute>49) && (minute<55)) { 
    MTEN; 
    MINUTES; 
    Serial.print("Ten Minutes ");
  } 
  if (minute>54) { 
    MFIVE; 
    MINUTES; 
    Serial.print("Five Minutes ");
  }

  if ((minute <5))
  {
    switch (hour) {
    case 1: 
      ONE; 
      Serial.print("One ");
      break;
    case 2: 
      TWO; 
      Serial.print("Two ");
      break;
    case 3: 
      THREE; 
      Serial.print("Three ");
      break;
    case 4: 
      FOUR; 
      Serial.print("Four ");
      break;
    case 5: 
      HFIVE; 
      Serial.print("Five ");
      break;
    case 6: 
      SIX; 
      Serial.print("Six ");
      break;
    case 7: 
      SEVEN; 
      Serial.print("Seven ");
      break;
    case 8: 
      EIGHT; 
      Serial.print("Eight ");
      break;
    case 9: 
      NINE; 
      Serial.print("Nine ");
      break;
    case 10: 
      HTEN; 
      Serial.print("Ten ");
      break;
    case 11: 
      ELEVEN; 
      Serial.print("Eleven ");
      break;
    case 12: 
      TWELVE; 
      Serial.print("Twelve ");
      break;
    }
  OCLOCK;
  Serial.println("O'Clock");
  }
  else
    if ((minute < 35) && (minute >4))
    {
      PAST;
      Serial.print("Past ");
      switch (hour) {
    case 1: 
      ONE; 
      Serial.println("One ");
      break;
    case 2: 
      TWO; 
      Serial.println("Two ");
      break;
    case 3: 
      THREE; 
      Serial.println("Three ");
      break;
    case 4: 
      FOUR; 
      Serial.println("Four ");
      break;
    case 5: 
      HFIVE; 
      Serial.println("Five ");
      break;
    case 6: 
      SIX; 
      Serial.println("Six ");
      break;
    case 7: 
      SEVEN; 
      Serial.println("Seven ");
      break;
    case 8: 
      EIGHT; 
      Serial.println("Eight ");
      break;
    case 9: 
      NINE; 
      Serial.println("Nine ");
      break;
    case 10: 
      HTEN; 
      Serial.println("Ten ");
      break;
    case 11: 
      ELEVEN; 
      Serial.println("Eleven ");
      break;
    case 12: 
      TWELVE; 
      Serial.println("Twelve ");
      break;
      }
    }
    else
    {
      // if we are greater than 34 minutes past the hour then display
      // the next hour, as we will be displaying a 'to' sign
      TO;
      Serial.print("To ");
      switch (hour) {
      case 1: 
        TWO; 
       Serial.println("Two ");
       break;
      case 2: 
        THREE; 
      Serial.println("Three ");
        break;
      case 3: 
        FOUR; 
      Serial.println("Four ");
        break;
      case 4: 
        HFIVE; 
      Serial.println("Five ");
        break;
      case 5: 
        SIX; 
      Serial.println("Six ");
        break;
      case 6: 
        SEVEN; 
      Serial.println("Seven ");
        break;
      case 7: 
        EIGHT; 
      Serial.println("Eight ");
        break;
      case 8: 
        NINE; 
      Serial.println("Nine ");
        break;
      case 9: 
        HTEN; 
      Serial.println("Ten ");
        break;
      case 10: 
        ELEVEN; 
      Serial.println("Eleven ");
        break;
      case 11: 
        TWELVE; 
      Serial.println("Twelve ");
        break;
      case 12: 
        ONE; 
      Serial.println("One ");
        break;
      }
    }
   WriteLEDs();
}


void incrementtime(void){
  // increment the time counters keeping care to rollover as required
  second=0;
  if (++minute >= 60) {
    minute=0;
    if (++hour == 13) {
      hour=1;  
    }
  }  
  // debug outputs
  Serial.println();
  Serial.print(hour);
  Serial.print(",");
  Serial.print(minute);
  Serial.print(",");
  Serial.println(second);
}
[code]void loop(void)
{ 
  
  

PhotoCellReading = analogRead(0);
//Serial.print("Analog reading = "); // Good for diagnosing your LDR readings
//Serial.println(PhotoCellReading); // the raw analog reading

LedBrightness = map(PhotoCellReading, 0, 1023, 0, 80); //The Max range of "80" stops my clock being too bright. You can go up to 250
if(LedBrightness<20) LedBrightness =0; // Stops the LED flickering on and off when moderately dark
// - Tweak this value depending on your environment (TV etc)

analogWrite(PWMPin, LedBrightness); //enable dimming via photoresistor

//analogWrite(PWMPin, 255); //manually set brightness level

  
    // heart of the timer - keep looking at the millisecond timer on the Arduino
    // and increment the seconds counter every 1000 ms
    if ( millis() - msTick >999) {
        msTick=millis();
        second++;
        // Flash the onboard Pin13 Led so we know something is hapening!
        digitalWrite(13,HIGH);
        delay(100);
        digitalWrite(13,LOW);    
    }
    
    //test to see if we need to increment the time counters
    if (second==60) 
    {
      incrementtime();
      displaytime();
    }

    // test to see if the Minute Button is being held down
    // for time setting
    if ( (digitalRead(MinuteButtonPin) ==1 ) && second!=1) 
      // the Minute Button is down and it has been more 
      // than one second since we last looked
    {
      minute=(((minute/5)*5) +5); 
      second=0;
      incrementtime();
      second++;  // Increment the second counter to ensure that the name
      // flash doesnt happen when setting time
      displaytime();
    }

    // test to see if the Hour Button is being held down
    // for time setting
    if ((digitalRead(HourButtonPin)==1 ) && second!=1) 
    {
      minute = (minute/5)*5;  //round minute down to previous 5 min interval
      if (++hour == 13) {
        hour=1;  
      }
      incrementtime();
      second++;  // Increment the second counter to ensure that the name
      // flash doesnt happen when setting time  
      displaytime();
    }

}

[/code]

You only have a single, .1uF decoupling capacitor for the entire circuit. Most likely you’re causing power fluctuations when the LEDs are switching on and off and that will be enough to trip the ATMega into reset or otherwise confuse your shift registers.

http://www.thebox.myzen.co.uk/Tutorial/De-coupling.html

  • Standard practice is to include a .1uF capacitor next to every chip in the circuit. Because you’re using ULN2003’s and pulling a lot of power through them you assuredly need additional capacitance; a 47uF electrolytic would be a good start but don’t be afraid to try other values.
  • The LM7805 should have a .1uF capacitor between its output and GND, again in close proximity to the chip, and the recommended cap between input and GND is .33uF. Sometimes these two caps are not required and other times you’ve spent hours debugging a circuit only to find out that they are.

From reading what you mentioned about resetting, I believe that's exactly why I'm having issues. From my understanding, I have to connect a capacitor from Vcc to GND to the ATMega. Should I also wire one to each ULN2003 as well? Where would I connect the GND pin with?

Between GND and COM (8 and 9) on each ULN2003. Between 8 and 16 on your 4094s, and 7 and 8 on the ATmega328. Don't forget the caps on the regulator as well.

In your code, in your setup() routine, it might be a good idea to flash your pin 13 led for a second or two just so you know when the sketch is starting -- to verify if the ATMega is resetting or not.

It works like a charm! Thank you so much!