;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Author: MLH ; Date: 9 May 2007 ; Purpose: ; This example demonstrates the use of the Timer/Counter subsystem. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .NOLIST .include "m32def.inc" .LIST ; data segment, reserve data memory in SRAM .DSEG overflow_counter: .byte 1 ; this byte stores the number of Counter0 overflows ; code segment for program instructions .CSEG .ORG 0 rjmp start .ORG 0x14 ; Output Comparator vector rjmp comparator_matchISR .ORG 0x16 ; Counter0 Overflow vector rjmp counter0_overflowISR .DEF temp=r18 ; use arbitrary register for temporary operations .org 0x2a start: ; Initialize the Stack Pointer (SP) CPU register for subsequent use ldi temp, LOW(RAMEND) ; get low byte of the address of the highest byte in Data Memory we can use out SPL, temp ; load it into the low byte of SP ldi temp, HIGH(RAMEND) ; high byte of address of highest Data Memory byte out SPH, temp ; load it into the high byte of SP ldi temp, 0xFF ; setup PortB for digital output out DDRB, temp andi temp, 0x00 out PORTB, temp ; turn LEDs off clr temp sts overflow_counter, temp ; initialize overflow_counter to 0 ; rcall initNormalMode rcall initCTCMode ; rcall initFastPWMMode ; rcall initPhaseCorrectMode sei ; this enables interrupts globally loop: rjmp loop ; loop forever, waiting for Timer/Counter interrupts ; subroutine initNormalMode ; puts T/C 0 in normal mode initNormalMode: push temp out TCNT0, temp ; clear Counter0 counter register; this is what Counter0 increments in temp, TCCR0 ; get current state of Timer/Counter0 Control Register andi temp, 0b11111000 ; clear CS02:CS00 that control frequency ori temp, 0b00000100 ; set CS02:CS00 to increment Counter0 every 256 CPU clock cycles (16us @ 16MHz) ; ori temp, 0b01001000 ; leave WGM00:WGM01 bits clear to indicate normal mode (count from 0 to 255 and reset) out TCCR0, temp ; counter is now running, TCNT0 is incrementing automatically every 16us ; next, enable Counter0 overflow interrupts in temp, TIMSK ; get state of Timer/Counter Interrupt Mask andi temp, 0b11111100 ; clear TOIE0 and OCIE0; keep other bits ori temp, 0b00000001 ; set bit TOIE0 to enable Counter0 overflow interrupt out TIMSK, temp pop temp ret ; end initNormalMode ; subroutine initCTCMode ; puts T/C 0 in CTC mode initCTCMode: push temp out TCNT0, temp ; clear Counter0 counter register; this is what Counter0 increments in temp, TCCR0 ; get current state of Timer/Counter0 Control Register andi temp, 0b11111000 ; clear CS02:CS00 that control frequency ori temp, 0b00000100 ; set CS02:CS00 to increment Counter0 every 256 CPU clock cycles (16us @ 16MHz) ori temp, 0b00001000 ; set WGM01 bit to indicate CTC mode (count from 0 to OCR0 value and reset) ori temp, 0b00010000 ; set COM01:COM00 to 0:1 to indicate *toggle* OC0 (PB3) on OCR0 compare match out TCCR0, temp ; counter is now running, TCNT0 is incrementing automatically every 16us ; next, enable Counter0 compare-match interrupts in temp, TIMSK ; get state of Timer/Counter Interrupt Mask andi temp, 0b11111100 ; clear TOIE0 and OCIE0; keep other bits ori temp, 0b00000010 ; set bit OCIE0 to enable OCR0 Output Comparator interrupt out TIMSK, temp ldi temp, 10 ; set comparator match value (only used if in CTC or PWM modes) out OCR0, temp ; OCIE0 interrupt will occur with TCNT0 reaches the OCR0 value pop temp ret ; end initCTCMode ; subroutine initFastPWMMode ; puts T/C 0 in Fast PWM mode initFastPWMMode: push temp out TCNT0, temp ; clear Counter0 counter register; this is what Counter0 increments in temp, TCCR0 ; get current state of Timer/Counter0 Control Register andi temp, 0b11111000 ; clear CS02:CS00 that control frequency ori temp, 0b00000101 ; set CS02:CS00 to increment Counter0 every 1024 CPU clock cycles ori temp, 0b01001000 ; set WGM00 and WGM01 bits to indicate Fast PWM mode (count from 0 to 255 and reset) ori temp, 0b00110000 ; set COM00/COM01 bits to *set* OC0 on compare match out TCCR0, temp ; counter is now running, TCNT0 is cycling at 61.035Hz ldi temp, 200 ; set comparator match value (only used if in CTC or PWM modes) out OCR0, temp ; OC0 will be SET when TCNT0 reaches OCR0, and will be CLEARED when TCNT0 resets pop temp ret ; end initFastPWMMode ; subroutine initPhaseCorrectMode ; puts T/C 0 in Phase-Correct PWM mode initPhaseCorrectMode: push temp out TCNT0, temp ; clear Counter0 counter register; this is what Counter0 increments in temp, TCCR0 ; get current state of Timer/Counter0 Control Register andi temp, 0b11111000 ; clear CS02:CS00 that control frequency ori temp, 0b00000101 ; set CS02:CS00 to increment Counter0 every 1024 CPU clock cycles ori temp, 0b01000000 ; set WGM00 and clear WGM01 bits to indicate Phase-correct PWM mode (count from 0 to 255 and then back to 0 ori temp, 0b00110000 ; set COM00/COM01 bits to *aet* OC0 on compare match out TCCR0, temp ; counter is now running, TCNT0 is cycling at 30.52Hz ldi temp, 253 ; set comparator match value (only used if in CTC mode) out OCR0, temp ; OC0 will be SET when TCNT0 reaches OCR0, and will be CLEARED when TCNT0 decreases below OCR0 pop temp ret ; end initPhaseCorrectMode ; interrupt handler counter0_overflowISR ; Purpose: implements the handling of the Timer/Counter0 overflow interrupt ; Every time the Counter0 overflow interrupt occurs, the overflow_counter (a byte in data memory) ; is incremented. The Counter0 is incremented every 256 clock cycles (16us), which ; corresponds to an overflow every 4096us, or 4.096ms. This means 244 overflows takes ; 999.424ms, or 0.999424s. After counting this many overflows, the LEDs are blinked. counter0_overflowISR: push temp lds temp, overflow_counter ; load last-stored value of overflow_counter from data memory inc temp ; increment value of overflow_counter in temp register cpi temp, 244 ; check if overflow_counter has reached 244 breq reset ; if so, reset the overflow_counter to 0 sts overflow_counter, temp ; store incremented value of overflow_counter clr temp ; all bits 0 out PORTB, temp rjmp end_ISR reset: ; reset the overflow_counter to 0 clr temp com temp ; all bits 1 out PORTB, temp ; toggle LEDs clr temp sts overflow_counter, temp ; here's where we actually clear the overflow_counter end_ISR: pop temp ; restore temporary registers reti ; end interrupt handler counter0_overflowISR ; interrupt handler comparator_matchISR ; Purpose: implements the handling of the Output Comparator match comparator_matchISR: reti push temp lds temp, overflow_counter ; load last-stored value of overflow_counter from data memory inc temp ; increment value of overflow_counter in temp register cpi temp, 80 ; check if overflow_counter has reached some predetermined value breq reset2 ; if so, reset the overflow_counter to 0 sts overflow_counter, temp ; store incremented value of overflow_counter clr temp ; all bits 0 out PORTB, temp rjmp end_matchISR reset2: ; reset the overflow_counter to 0 ldi temp, 0xf out PORTB, temp ; toggle LEDs clr temp sts overflow_counter, temp ; here's where we actually clear the overflow_counter end_matchISR: pop temp reti ; end interrupt handler comparator_matchISR