Search code examples
avrpwmattiny

Pulse width modulation (PWM) on Attiny 9


I am using an Attiny 9. enter image description here

I connected a LED to PB1. I wrote following code and upload it to the Attiny 9.

#define F_CPU 800000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/sleep.h>
#include <avr/power.h>

#define D0 PB1

int main(void)
{
  power_adc_disable();
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);

  TCCR0A |= (1<<WGM00)|(1<<WGM01)|(1<<COM0B1);
  TCCR0B |= (1<<WGM03)|(1<<WGM02)|(1<<CS00);

  DDRB |= 1<<D0;

  PORTB |= 1<<D0;
  _delay_ms(3000);
  PORTB &= ~(1<<D0);

  for (uint8_t i = 255; 247 < i; --i)
  {
    OCR0B = i;
    _delay_ms(70);
  }

  for (uint8_t i= 247; -1 < i; --i)
  {
    OCR0B = i;
    _delay_ms(4);
  }

  while(1){
    sleep_enable();
    sleep_cpu();
  }

  return 0;
}

I want the LED to be lighten and darken. But after I uploaded the code, the LED illuminates continuously. I also read a datasheet of Attiny 9. I followed how to use PWM. But it's not working.

What's wrong?


Solution

  • There are a number of issues with that code.

    1. You're putting the processor in to power down mode, which according to the datasheet, disables the clocks and only asynchronous events can take place.
    2. You're setting it to use fast PWM mode with OCR0A as your top, but you aren't setting OCR0A anywhere. You won't generate any compare matches if you your timer can't count high enough. It would appear from your loops that you are expecting the timer to count to 255.
    3. You only change the duty cycle of the PWM before your while loop, so even if your PWM gets set up correctly, you won't ever be able to see your LED pulse like you want.

    Here's a link giving an example of how to set up a PWM and change its duty cycles: http://allaboutavr.com/index.php/2017/05/13/chapter-5-timers-and-pwm-pulse-width-modulation/

    Ty something like this:

    #include <avr/io.h>
    #include <util/delay.h>
    
    #define D0 PB1
    
    int main(void)
    {
        DDRB |= 1<<D0;
    
        TCCR0A |= (1<<WGM00)|(1<<COM0B1);
        TCCR0B |= (1<<WGM02)|(1<<CS00);
    
        while (1) {
            for (uint8_t i = 0; i < 255; i++) {
                OCR0B = i;
                _delay_ms(4);
            }
    
            for (uint8_t i = 255; i >= 0; i--) {
                OCR0B = i;
                _delay_ms(4);
            }
        }
    }