Firstly I highly recommend this tutorial on simply getting a LED to flash. It uses a different pin for the LED so is a slightly different circuit but not by much. I personally only used the electrical schematic and the code from the tutorial as I'm using a AVRISP MKII programmer and know basic electronics already.
So for my very small tutorial (not really a tutorial), I'm going to assume the reader can read an electrical schematic and knows how get the code from what you type to the chip. I'm also going to not really explain the code much as I tried to comment as much as I could. The reason for not explaining what I did so much is because there are heaps of tutorials out there for PWM on AVR chips. I only wanted to put this one out because I couldn't find simple code (rather than masses of subroutines) to control PWM using the 8bit timer0 on the ATMEGA88.
Without any further ado here's a video of how the LED should flash after the project.
R1 is a pull up resistor to make sure the reset pin (which is labelled as pin PC6) is kept at logic one when not being programmed. I tried adding a 10uF capacitor connected to ground on the reset pin but the programmer was unable to connect, so I haven't added one in. C1 is a smoothing capacitor just to help if there is any spikes in the supply voltage. R2 makes sure that there is enough current going through the LED to give enough brightness without pulling too much current from the microcontroller. The connector named ISP-CONNECT, is where the MKII attaches.
Finally the code is as follows.
/*
* Name: ATMEGA88A - Breathing LED using PWM on timer0
* Description: This sets a LED on portD.6 to glow in a
* pattern similar to breathing, like the Mac sleep LED does
*/
#include <avr/io.h>
#include <math.h> // Allows the use of pi and e in Equations
#include <avr/interrupt.h>
unsigned int count = 0; // our variable to determine where in wave we are
int main()
{
DDRD = (1 << DDD6); // Set PD6 as an output
OCR0A = 0; // clear OC0A (0% duty)
OCR0B = 0; // clear OC0B for good practice
TCNT0 = 0; // clear timer0 register
TIFR0 = 0; // clear timer0 all interrupts if any
TIMSK0 = (1 << OCIE0A); // enable interrupt for OC0A
TCCR0A = (0<<WGM01)|(1<<WGM00); // timer0 to phase corrected PWM
TCCR0B = (1<<CS00); // timer0 to use clock with no prescale
TCCR0A ^= (1 << COM0A1); // Clear 0C0A on compare match (turn timer on)
sei(); // Enables global interrupts
while(1); // Never ending loop
}
/**************************************/
/**** Interupt for timer0A compare ****/
/**************************************/
/* This is used to update the duty */
/* cycle to follow our equation. The */
/* equation is a modified version of */
/* exp(sin(x)). */
/**************************************/
ISR(TIMER0_COMPA_vect)
{
count++; // update where we are in the wave
OCR0A = (255+255/exp(2))*exp(sin(2*M_PI*count/8192)-1)-255/exp(2);
// set the new duty cycle
}
The only thing I really want to say about the code is about the equation on the third last line. The equation is based on exp(sin(x) ). This was then amplified and stretched to get the full voltage range and not flash too quickly. The number 8192 is 1/8th of the max value an unsigned integer, so to get a good time for each cycle without having any part of the wave skipped.
If anyone has any questions, write in the comments and I'll try and reply.