Skip to content

Instantly share code, notes, and snippets.

@Wollw
Last active July 2, 2023 08:35
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save Wollw/2425784 to your computer and use it in GitHub Desktop.
Save Wollw/2425784 to your computer and use it in GitHub Desktop.
ATmega328P PWM Example
/**
* A PWM example for the ATmega328P using the 8-Bit Fast PWM mode.
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <util/delay.h>
int main (void) {
/**
* We will be using OCR1A as our PWM output register which is the
* same pin as PB1.
*/
DDRB |= _BV(PB1);
/**
* There are quite a number of PWM modes available but for the
* sake of simplicity we'll just use the 8-bit Fast PWM mode.
* This is done by setting the WGM10 and WGM12 bits. We
* Setting COM1A1 tells the microcontroller to set the
* output of the OCR1A pin low when the timer's counter reaches
* a compare value (which will be explained below). CS10 being
* set simply turns the timer on without a prescaler (so at full
* speed). The timer is used to determine when the PWM pin should be
* on and when it should be off.
*/
TCCR1A |= _BV(COM1A1) | _BV(WGM10);
TCCR1B |= _BV(CS10) | _BV(WGM12);
/**
* This loop is used to change the value in the OCR1A register.
* What that means is we're telling the timer waveform generator
* the point when it should change the state of the PWM pin.
* The way we configured it (with _BV(COM1A1) above) tells the
* generator to have the pin be on when the timer is at zero and then
* to turn it off once it reaches the value in the OCR1A register.
*
* Given that we are using an 8-bit mode the timer will reset to zero
* after it reaches 0xff, so we have 255 ticks of the timer until it
* resets. The value stored in OCR1A is the point within those 255
* ticks of the timer when the output pin should be turned off
* (remember, it starts on).
*
* Effectively this means that the ratio of pwm / 255 is the percentage
* of time that the pin will be high. Given this it isn't too hard
* to see what when the pwm value is at 0x00 the LED will be off
* and when it is 0xff the LED will be at its brightest.
*/
uint8_t pwm = 0x00;
bool up = true;
for(;;) {
OCR1A = pwm;
pwm += up ? 1 : -1;
if (pwm == 0xff)
up = false;
else if (pwm == 0x00)
up = true;
_delay_ms(10);
}
}
/**
* A PWM example for the ATmega328P using the 8-Bit Fast PWM mode.
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <util/delay.h>
int main (void) {
/**
* We will be using OCR0A as our PWM output register which is the
* same pin as PD6.
*/
DDRD |= _BV(PD6);
/**
* There are quite a number of PWM modes available but for the
* sake of simplicity we'll just use the 8-bit Fast PWM mode.
* This is done by setting the WGM00 and WGM01 bits. The
* Setting COM0A1 tells the microcontroller to set the
* output of the OCR0A pin low when the timer's counter reaches
* a compare value (which will be explained below). CS00 being
* set simply turns the timer on without a prescaler (so at full
* speed). The timer is used to determine when the PWM pin should be
* on and when it should be off.
*/
TCCR0A |= _BV(COM0A1) | _BV(WGM00) | _BV(WGM01);
TCCR0B |= _BV(CS00);
/**
* This loop is used to change the value in the OCR0A register.
* What that means is we're telling the timer waveform generator
* the point when it should change the state of the PWM pin.
* The way we configured it (with _BV(COM0A1) above) tells the
* generator to have the pin be on when the timer is at zero and then
* to turn it off once it reaches the value in the OCR0A register.
*
* Given that we are using an 8-bit mode the timer will reset to zero
* after it reaches 0xff, so we have 255 ticks of the timer until it
* resets. The value stored in OCR0A is the point within those 255
* ticks of the timer when the output pin should be turned off
* (remember, it starts on).
*
* Effectively this means that the ratio of pwm / 255 is the percentage
* of time that the pin will be high. Given this it isn't too hard
* to see what when the pwm value is at 0x00 the LED will be off
* and when it is 0xff the LED will be at its brightest.
*/
uint8_t pwm = 0x00;
bool up = true;
for(;;) {
OCR0A = pwm;
pwm += up ? 1 : -1;
if (pwm == 0xff)
up = false;
else if (pwm == 0x00)
up = true;
_delay_ms(10);
}
}
@ee-diary
Copy link

ee-diary commented Jun 9, 2022

is the header files #include <avr/interrupt.h> and #include <stdbool.h> required? I read several examples on ATmega328P Fast PWM mode Programming Examples but should i include these files?

@Wollw
Copy link
Author

Wollw commented Jun 9, 2022

stdbool.h is just a convenience so I can use the bool type, but not strictly needed if you change the type of the "up" variable. I don't think avr/interrupt.h is required either as I don't see anywhere I'm using interrupts in this example and it is probably just a remnant from something else I was doing. I'd test it out myself, but don't have the tool chain set up right now on this computer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment