This article shows how to make an ATtiny13 to generate hardware PWM (Pulse Width Modulation) signal. The example code uses timer in Fast PWM mode (WGM02:0 = 3, see manual section 11.7.3). In this mode, by setting the COM0A1:0 bits to one, the compare unit allows generation of PWM waveforms on the AC0A pin (PB0) with duty resolution 0..255. The presented example can operate on few frequencies: 4.687kHz, 585Hz, 73Hz, 18Hz, 4Hz (@1.2MHz). If you need higher PWM frequencies then set fuse bits to run ATtiny13 with 9.6MHz clock source. The example code is on Github, click here.
Parts Required
- ATtiny13 – i.e. MBAVR-1 development board
Circuit Diagram
Software
This code is written in C and can be compiled using the avr-gcc. All information about how to compile this AVR project is here.
/** * Copyright (c) 2019, Łukasz Marcin Podkalicki <lpodkalicki@gmail.com> * ATtiny13/031 * Example of hardware Fast PWM. * Features: * - PWM duty resolution: 0..255 * - PWM frequencies (@1.2MHz): 4.687kHz, 585Hz, 73Hz, 18Hz, 4Hz */ #include <avr/io.h> #include <util/delay.h> #define N_1 (_BV(CS00)) #define N_8 (_BV(CS01)) #define N_64 (_BV(CS01)|_BV(CS00)) #define N_256 (_BV(CS02)) #define N_1024 (_BV(CS02)|_BV(CS00)) static void pwm_init(void) { DDRB |= _BV(PB0); // set PWM pin as OUTPUT TCCR0A |= _BV(WGM01)|_BV(WGM00); // set timer mode to FAST PWM TCCR0A |= _BV(COM0A1); // connect PWM signal to pin (AC0A => PB0) } /* When timer is set to Fast PWM Mode, the freqency can be calculated using equation: F = F_CPU / (N * 256) Posible frequencies (@1.2MHz): -> F(N_1) = 4.687kHz -> F(N_8) = 585Hz -> F(N_64) = 73Hz -> F(N_256) = 18Hz -> F(N_1024) = 4Hz */ static void pwm_set_frequency(uint32_t N) { TCCR0B = (TCCR0B & ~((1<<CS02)|(1<<CS01)|(1<<CS00))) | N; // set prescaler } static void pwm_set_duty(uint8_t duty) { OCR0A = duty; // set the OCRnx } static void pwm_stop(void) { TCCR0B &= ~((1<<CS02)|(1<<CS01)|(1<<CS00)); // stop the timer } int main(void) { uint8_t duty = 0; /* setup */ pwm_init(); pwm_set_frequency(N_1); /* loop */ while (1) { pwm_set_duty(duty++); _delay_ms(100); } }