/* timer_pwm_demo.c Use of timer0 to produce a pulse-width modulated signal. We will use this signal to control the brightness of an LED. The interrupt routine will handle the PWM generation. Our "something else" will slowly alter the pulse width. With a 16MHz clock (and no prescaler), timer0 increments every 1/16000000 seconds, so the SIG_OVERFLOW0 interrupt occurs every (256)/16000000 = 16 usec. On each interrupt, the routine increments an internal counter ("counter"). While the counter has a value between 0 and the variable "duration", the LED will be on. Between "duration" and 255, the LED will be off. So - the period of the pulse is (256*256)/16000000 = 4.096 msec. */ #include #include #include #include #include "oulib.h" // Global so that it can be used in the interrupt handler, but // initialized by the main routine. volatile unsigned char counter = 0; volatile unsigned char duration = 0; // Interrupt handler for TIMER0 overflow SIGNAL(SIG_OVERFLOW0) { // Increment counter ++counter; if(counter == 0) { // Start of the pulse PORTB |= 0x1; } if(counter >= duration) { // End of the pulse // With the >=, we cleanly handle the case that "duration" // is changed in the middle of the pulse PORTB &= ~0x1; }; }; int main(void) { // Initialize I/O DDRB = 0xFF; PORTB = 0; unsigned int i; // Initialize counter counter = 0; duration = 0; // Interrupt occurs every (1024*256)/16000000 = .0164 seconds timer0_config(TIMER0_NOPRE); // Enable the timer interrupt timer0_enable(); // Enable global interrupts sei(); while(1) { // Do something else // Slowly increase the duration for(i = 0; i < 256; ++i) { duration = (unsigned char) i; delay_ms(10); }; // Slowly decrease the duration for(i = 255; i > 0; --i) { duration = (unsigned char) i; delay_ms(10); }; }; return(0); }