6

This is admittedly a cross-post from LED fade malfunction (random flash) but I can't get an answer on the Arduino forum.

I was mucking around with some very basic code and I noticed that when repeatedly holding an LED at 0 brightness for 1 second and then fading in to full brightness, a small flash would occasionally happen at the beginning of each fade (seemingly random).

int led = 11;
int brightness = 0;

void setup()  
{ 
  pinMode(led, OUTPUT);
} 


void loop()  
{ 
  if(brightness >= 256) //checks if brightness has passed 255, resets to 0
  {
    analogWrite(led, 255);
    brightness = 0; 
  }
  analogWrite(led, brightness);
  if(brightness == 0)
    {
      delay(1000); //LED off for 1 second
    }

  brightness+=1; //increment brightness
  delay(20);
}

So, the thing that has me completely perplexed is that I can use a different piece of code (below) and the flash goes away!

int i = 0;
int led = 11;

void setup()
{
  pinMode(led,OUTPUT);
}

void loop()
{
analogWrite(led, i);
delay(6);
if(i%256 == 0)
{
  i = 0 ;
  delay(1000);
}
i++;
}

Has anyone got any clue as to why this would happen? Both programs have basically the same code, except for that i is reset to 0 in the first program whereas in the second, i keeps incrementing past 255 so that analogWrite 'overflows.' I think it must be a firmware, (or maybe a software?) problem.

There is a video on youtube of it happening here, Arduino - fading LED problem.

Adrian
  • 108
  • 8

1 Answers1

4

According to the links you provide from the arduino.cc forum the question is more or less answered. If not that important, just avoid analogWrite(led,0) and make it analogWrite(led,1)

if you still want that analogWrite(led,0), I've tested your code with the advice and it seems to work OK when changing the register manually:

#include "wiring_private.h"

int led = 11;
int brightness = 0;

void setup()
{
  pinMode(led, OUTPUT);
}


void loop()
{
  if (brightness >= 256) //checks if brightness has passed 255, resets to 0
  {
    brightness = 0;
    sbi(TCCR2A, COM2A1);
    OCR2A = 0; // set pwm duty
  }

  analogWrite(led, brightness);
  if (brightness == 0)
  {
    delay(1000); //LED off for 1 second
  }

  brightness += 1; //increment brightness
  delay(20);
}

Edit: to explain what those "strange codes" are

I'm not very expert in this field to explain how exactly this works but basically sbi is function defined in a macro by Atmel (?), it stands for "set bit in" and is used to change registers of ATmega chips. So basically what I did was change register defined by the macro TCCR2A (why? because it is the register that controls PWM in pin 11) and pass the bitmask COM2A1 (this is a mode of compare defined in datasheet) and OCR2A is a register used to store the compare value that defines duty cycle. Imagine a counter that every time it receives a tick from a signal clock it compares the value of the counter with the value stored in OCR2A and it sets the pin high or low if that value as been passed or not (more or less like this, depending on the mode stored on TCCR2A).

But in fact I've not done some black magic. I just looked into the code of analogWrite() and that is the way they use to set a value of PWM in pin 11:

void analogWrite(uint8_t pin, int val)
{
    // We need to make sure the PWM output is enabled for those pins
    // that support it, as we turn it off when digitally reading or
    // writing with them.  Also, make sure the pin is in output mode
    // for consistenty with Wiring, which doesn't require a pinMode
    // call for the analog output pins.
    pinMode(pin, OUTPUT);
    if (val == 0)
    {
        digitalWrite(pin, LOW);
    }
    else if (val == 255)
    {
        digitalWrite(pin, HIGH);
    }
    else
    {
        switch(digitalPinToTimer(pin))
        {

...

          #if defined(TCCR2A) && defined(COM2A1)
            case TIMER2A:
                // connect pwm to pin on timer 2, channel A
                sbi(TCCR2A, COM2A1);
                OCR2A = val; // set pwm duty
                break;
          #endif
...

}

So basically I just used that info to set the register to zero, as suggested from the arduino.cc forum link that you have.

If you want to know more about PWM in Arduino, this site has a lot of info and explains a lot of the modes of registers also.

Greenonline
  • 3,152
  • 7
  • 36
  • 48
brtiberio
  • 926
  • 5
  • 15