#include "header.h" // 14.3.1 : alternate functions for led2 PB1 // - OC1A (Timer/Counter1 Output Compare Match A Output) // - 16.11.1 controlled by COM1A1:0 in TCCR1A // - Table 16-2 : Compare Output Mode, Fast PWM // (1 << COM1A1) | (0 << COM1A0) -> non-inverting mode // - Table 16-4 : set timer 1 in fast PWM mode, with top as ICR1 or OCR1A // - ICR1 : Input Capture Register ((1 << WGM13) | (1 << WGM12) | (1 << WGM11) | (0 << WGM10)) // - OCR1A : Output Compare Register ((1 << WGM13) | (1 << WGM12) | (1 << WGM11) | (1 << WGM10)) // -> if OCR1A is top, it's also duty cycle, so changing duty cycle will also change frequency // -> if ICR1 is top, OCR1A is duty cycle, so it can be changed independantly // - PCINT1 (Pin Change Interrupt 1) : to interrupt when pin change, in input mode only // calulations // - frequency is 16Mhz -> it means that the clock runs 16 000 000 times per seconds // - and the timer1 can store 16 bits value of cycle -> which is 2^16 = 65536 // - so it will only last 65536/16000000 = 0,004096 second // - if i want my cycle to be 0.001 second, prescaler 1 is enough // - if i want my cycle to be 0.01 second, which prescaler ? // - 8 * 0,004096 = 0.032768 -> it is enough // - 64 * 0,004096 = 0.262144 -> it is largely enough // - if i choose prescaler 1 for a duration of 0.001 seconds, i need to restart the clock after how many cycles : // - (16000000 / 1) * 0.001 = 16000 ticks -> set ICR1 = 16000 // - if i choose prescaler 8 for a duration of 0.01 seconds, i need to restart the clock after how many cycles : // - (16000000 / 8) * 0.01 = 20000 ticks -> set ICR1 = 20000 // - if i choose prescaler 64 for a duration of 0.01 seconds, i need to restart the clock after how many cycles : // - (16000000 / 64) * 0.01 = 2500 ticks -> set ICR1 = 2500 // alternatively, can use the default values : // - Fast PWM, 8-bit, TOP 0x00FF (255) // - Fast PWM, 9-bit, TOP 0x01FF (511) // - Fast PWM, 10-bit, TOP 0x03FF (1023) // no need to set a second for the "blinking" with PWM and duty cycle : // only need to use a top value convenient, like a multiple of 100 // if choose top value of 100 : // - at prescaler 1 : 100 / 16000000 = 0.00000625s (it takes this time to do a cycle) // - at prescaler 8 : (100 * 8) / 16000000 = 0.00005s // - at prescaler 64 : (100 * 64) / 16000000 = 0.0004s // - at prescaler 256 : (100 * 256) / 16000000 = 0.0016s // - at prescaler 1024 : (100 * 1024) / 16000000 = 0.0064s // if choose top value of 1000 : // - at prescaler 1 : 1000 / 16000000 = 0.0000625s (it takes this time to do a cycle) // - at prescaler 8 : (1000 * 8) / 16000000 = 0.0005s // - at prescaler 64 : (1000 * 64) / 16000000 = 0.004s // - at prescaler 256 : (1000 * 256) / 16000000 = 0.016s // - at prescaler 1024 : (1000 * 1024) / 16000000 = 0.064s // 16.9.3 : timer1 fast PWM #define LED1_PWM_PRESCALER 256 // can be 1, 8, 64, 256, 1024 #define DUTY_CYCLE_PERCENT 9 #define FREQUENCY_MS 1 #define TOP_VALUE 1000 volatile uint8_t duty_cycle = DUTY_CYCLE_PERCENT; void blink_led_1() { TCCR1A = (1 << WGM11); // Table 16-4 : set timer1 in fast PWM mode 14, with TOP ICR1, so we can use OCR1A for duty cycle and keep ICR1 for frequency TCCR1B = (1 << WGM13) | (1 << WGM12); // mode 15 with OCR1A TOP prevent using duty cycle trigger on OC1A (OCR1B is free but triggers OC1B -> PB2) // other fast PWM modes 5, 6, and 7 uses predefined TOP, preventing to define a multiple of 100 for percent accuracy TCCR1A |= (1 << COM1A1); // Table 16-2 : set non-inverting mode to trigger OC1A on fast PWM (14.3.1 : OC1A is alternate function of PB1) TCCR1B |= PRESCALE_SET(LED1_PWM_PRESCALER); // Table 16-5 : set the appropriate prescale values // ICR1 = TIME_MS(FREQUENCY_MS, LED1_PWM_PRESCALER); // top value for Xms ICR1 = TOP_VALUE; OCR1A = PERCENT(duty_cycle, ICR1); // 16.9.3 : duty cycle } vary_duty() { // TCCR0A = (1 << WGM11); // Table 15-8 : set timer0 in CTC mode, with TOP OCRA // TCCR1B = (1 << WGM13) | (1 << WGM12); // TCCR1A |= (1 << COM1A1); // Table 16-2 : set non-inverting mode to trigger OC1A on fast PWM (14.3.1 : OC1A is alternate function of PB1) // TCCR1B |= PRESCALE_SET(LED1_PWM_PRESCALER); // Table 16-5 : set the appropriate prescale values // // ICR1 = TIME_MS(FREQUENCY_MS, LED1_PWM_PRESCALER); // top value for Xms // ICR1 = TOP_VALUE; // OCR1A = PERCENT(duty_cycle, ICR1); // 16.9.3 : duty cycle } // use timers interruptions to varie led1 intensity using duty cycle, from 0% to 100% to 0% in 1 second // timer1 sets the led duty cycle, timer0 change the duty cycle percentage int main() { MODE_OUTPUT(LED1); CLEAR_ELEM(LED1); MODE_OUTPUT(LED2); CLEAR_ELEM(LED2); MODE_OUTPUT(LED3); CLEAR_ELEM(LED3); MODE_OUTPUT(LED4); CLEAR_ELEM(LED4); SREG |= ENABLE_GLOBAL_INTERRUPT; blink_led_1(); vary_duty(); while (1); }