Increasing brightness of LED by varying duty cycle using Timers

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Atmega328PB @ 16 Mhz

 

My goal is to increase the brightness while the push button is pressed and to decrease the brightness until its off when the button is released. So far, I have this successfully implemented using a simply delay function, shown below. 

while(!(PINB & (1<<PINB7)))  //While the button is pressed
    {
		for(i = 0; i <= top; i++)
		{
			LED_ON;           //LED on for i time
			delay_func(i);
			LED_OFF;           // LED off for top - i time
			delay_func(top-i);
      			
      			while(i == top)    // While the button has been held down for i==top time, keep the LED on 100%
      			{
        			LED_ON;
				delay_func(top);
          
					if((PINB & (1<<PINB7)))     //If the button is released
					{
						for(j = top; j >= 0; j--)
						{
							LED_ON;          //LED on for j time 
							delay_func(j);
							LED_OFF;         //LED off for top-j time
							delay_func(top-j);
						}
            
						break;
					}
					
      			}
		}
    }

Essentially, the LED is giving the appearance of brightening by increasing the time that it is on versus the time that it is off when the button is pressed.  When the button is released, the LED will increase the time that it is off versus on until it is completely off. 

 

I want to replace the delay function and do the same thing but using Timers. So instead of delaying the LED on and off times a certain amount, I need to vary the duty cycle from 1% to 100%. Then the LED will go from 1% time spent on and 99% time spent off to 100% time spent on and 0 % time spent off. 

 

So far, I have timer0 initialized as follows:

TCCR0A |= (0 << WGM02) | (0 << WGM01) | (0 << WGM00); // Set the Timer Mode to Normal
TCCR0B |= (1 << CS02) | (0 << CS01) | (1 << CS00); // Prescale = Clk / 1024 

I am using 1024 prescale so I can have a 10ms period, which is roughly 156 ticks. 

 

Based on this picture, my goal is to vary Ton and Toff instead of calling the delay function, but I do not know how. 

 

If anyone can point me in the right direction, I would greatly appreciate it. Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try one of the PWM modes. That is EXACTLY what they are built for.

 

As an example, consider an 8-bit timer using COMPxA (where x is the timer number, 0, etc).There are 256 counts per timer period (0 to 255). Setting COMPxA to 25 will give about 10% duty cycle, while 50 will give close to 20%.

 

There is caution when using AVR timers this way. Setting COMPxA to 0 will NOT totally turn off the LED. There will be a very slight glow. 

 

You will also need to route the compare signal to a particular port pin, No interrupts are needed. To change the duty cycle, just write a new value to the COMPxA register. It will update at the correct time.

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Be aware that, because the human eye is non-linear, halving the duty cycle might not seem to correspond to halving the brightness.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was looking at the code trying to spot a clue to say which C compiler it is but can't spot anything obvious so I'll simply say if it happens to be avr-gcc the manual contains this example
.
https://www.nongnu.org/avr-libc/user-manual/group__demo__project.html