In diesem Beispiel-Programm (C und Assembler) wird der Timer initialisiert und es wird mit Interrupts gearbeitet. Wie im vorherigen Programm (Blinklicht ohne Timer) wird wieder eine LED zum blinken gebracht.
ASM-Programm
In dem Programm gehe ich von einer Frequenz SMCLK=1MHz (was auch einigermaßen genau passt) aus um die Zyklen zu berechnen. In dem ASM-Programm wird die LED jede Sekunde für eine Sekunde zum leuchten gebracht. Da die maximale Grenze der Zyklen (2^16)-1 enspricht, also etwa knapp über 500ms (500ms=62500 Zyklen), kommt hier noch ein Faktor ins Spiel um auf die eine Sekunde zu kommen (2*500ms, siehe Programm). Der Faktor wird in der Timer-ISR immer dekrementiert und geprüft.
FILE: main.asm
;*********************************************** ; ___ _ _ ; | |_ _ _| |___ ___ _| |___ ; | | |_'_| . | -_| _|_| . | -_| ; |___|_,_|___|___|___|_|___|___| ; ; FILE: main.asm ; Author: declis (xdec.de) ;*********************************************** .cdecls "msp430g2231.h" .ref init_TimerA,ISR_TimerA .global main .text main: mov.w #0x280,SP ;initialize stack pointer mov.w #WDTPW+WDTHOLD,&WDTCTL ;stop watchdog timer bis.b #BIT6,&P1DIR ;P1.6 -> output bic.b #BIT6,&P1OUT ;clear P1.6 (LED2 off) mov.w #2,R4 ;factor for TimerA-ISR (2*500ms) call #init_TimerA ;initialize TimerA EINT ;GIE=1, or bis.w #GIE,SR -> enable interrupt jmp $ .sect TIMERA0_VECTOR ;0xFFF2 Timer A CC0 (".int09") .word ISR_TimerA ;interrupt service routine for TimerA .end
FILE: timer.asm
;*********************************************** ; ___ _ _ ; | |_ _ _| |___ ___ _| |___ ; | | |_'_| . | -_| _|_| . | -_| ; |___|_,_|___|___|___|_|___|___| ; ; FILE: timer.asm ; Author: declis (xdec.de) ;*********************************************** .cdecls "msp430g2231.h" cycles .equ 62500 .def init_TimerA,ISR_TimerA .text ;------------------------------------------ ; Name: init_TimerA ; Description: initialize Timer A ; cycles=(seconds*10^6Hz)/8 ; seconds=(8*cycles)/10^6Hz ; 62500 cycles = 500ms ; SMCLK=~1MHz ; Input: nothing ; Returns: nothing ; Destroys: nothing ;------------------------------------------ init_TimerA: bis.w #TASSEL_2+ID_3,&TACTL ;SMCLK, 8x divider mov.w #cycles,&TACCR0 bis.w #CCIE,&TACCTL0 ;enable TimerA interrupt bis.w #MC_1,&TACTL ;start timer in up-mode ret ;------------------------------------------ ; Name: ISR_TimerA ; Description: Interrupt Service Routine TA ; toggle LED2 every second ; Input: nothing ; Returns: nothing ; Destroys: R4 ;------------------------------------------ ISR_TimerA: dec.w R4 ;decrement factor/counter jnz isrTAend ;R4!=0 xor.b #BIT6,&P1OUT ;toggle P1.6 (LED2) mov.w #2,R4 ;reset factor/counter isrTAend: reti .end
C-Programm
FILE: main.c
- /*************************************************
- * ___ _ _
- * | |_ _ _| |___ ___ _| |___
- * | | |_'_| . | -_| _|_| . | -_|
- * |___|_,_|___|___|___|_|___|___|
- *
- * FILE: main.c
- * Author: declis (xdec.de)
- ************************************************/
- #include <msp430g2231.h>
- #include "timer.h"
- void main(void)
- {
- WDTCTL=WDTPW+WDTHOLD; /* stop watchdog timer */
- BCSCTL1=CALBC1_1MHZ; /* set DCO to 1MHz, set range */
- DCOCTL=CALDCO_1MHZ; /* set DCO step+modulation */
- P1DIR|=BIT6; /* P1.6 -> output */
- P1OUT&=~BIT6; /* clear P1.6 (LED2 off) */
- init_TimerA(); /* initialize TimerA */
- _EINT(); /* enable interrupt */
- for(;;);
- }
/************************************************* * ___ _ _ * | |_ _ _| |___ ___ _| |___ * | | |_'_| . | -_| _|_| . | -_| * |___|_,_|___|___|___|_|___|___| * * FILE: main.c * Author: declis (xdec.de) ************************************************/ #include <msp430g2231.h> #include "timer.h" void main(void) { WDTCTL=WDTPW+WDTHOLD; /* stop watchdog timer */ BCSCTL1=CALBC1_1MHZ; /* set DCO to 1MHz, set range */ DCOCTL=CALDCO_1MHZ; /* set DCO step+modulation */ P1DIR|=BIT6; /* P1.6 -> output */ P1OUT&=~BIT6; /* clear P1.6 (LED2 off) */ init_TimerA(); /* initialize TimerA */ _EINT(); /* enable interrupt */ for(;;); }
FILE: timer.c
- /*************************************************
- * ___ _ _
- * | |_ _ _| |___ ___ _| |___
- * | | |_'_| . | -_| _|_| . | -_|
- * |___|_,_|___|___|___|_|___|___|
- *
- * FILE: timer.c
- * Author: declis (xdec.de)
- ************************************************/
- #include <msp430g2231.h>
- #include "timer.h"
- #define cycles 62500u /* 500ms */
- volatile char count; /* counter for 2*500ms=1s */
- /* cycles=(seconds*10^6Hz)/8 */
- /* seconds=(8*cycles)/10^6Hz */
- void init_TimerA(void)
- {
- TACTL|=TASSEL_2+ID_3; /* SMCLK, 8x divider */
- TACCR0=cycles;
- count=2; /* set counter */
- TACCTL0|=CCIE; /* enable TimerA interrupt */
- TACTL|=MC_1; /* start timer in up-mode */
- }
- /* Timer_A ISR */
- #pragma INTERRUPT (ISR_TimerA)
- #pragma vector=TIMERA0_VECTOR
- void ISR_TimerA(void)
- {
- count--;
- if(!count)
- {
- P1OUT^=BIT6; /* toggle P1.6 */
- count=2; /* reset counter */
- }
- }
/************************************************* * ___ _ _ * | |_ _ _| |___ ___ _| |___ * | | |_'_| . | -_| _|_| . | -_| * |___|_,_|___|___|___|_|___|___| * * FILE: timer.c * Author: declis (xdec.de) ************************************************/ #include <msp430g2231.h> #include "timer.h" #define cycles 62500u /* 500ms */ volatile char count; /* counter for 2*500ms=1s */ /* cycles=(seconds*10^6Hz)/8 */ /* seconds=(8*cycles)/10^6Hz */ void init_TimerA(void) { TACTL|=TASSEL_2+ID_3; /* SMCLK, 8x divider */ TACCR0=cycles; count=2; /* set counter */ TACCTL0|=CCIE; /* enable TimerA interrupt */ TACTL|=MC_1; /* start timer in up-mode */ } /* Timer_A ISR */ #pragma INTERRUPT (ISR_TimerA) #pragma vector=TIMERA0_VECTOR void ISR_TimerA(void) { count--; if(!count) { P1OUT^=BIT6; /* toggle P1.6 */ count=2; /* reset counter */ } }
FILE: timer.h
- /*************************************************
- * ___ _ _
- * | |_ _ _| |___ ___ _| |___
- * | | |_'_| . | -_| _|_| . | -_|
- * |___|_,_|___|___|___|_|___|___|
- *
- * FILE: timer.h
- * Author: declis (xdec.de)
- ************************************************/
- #ifndef TIMER_H_
- #define TIMER_H_
- void init_TimerA(void);
- #endif /*TIMER_H_*/
/************************************************* * ___ _ _ * | |_ _ _| |___ ___ _| |___ * | | |_'_| . | -_| _|_| . | -_| * |___|_,_|___|___|___|_|___|___| * * FILE: timer.h * Author: declis (xdec.de) ************************************************/ #ifndef TIMER_H_ #define TIMER_H_ void init_TimerA(void); #endif /*TIMER_H_*/
Update (11.01.13): Das Programm wurde um zwei Zeilen erweitert um einmal den Unterschied zwischen “DCO calibrated (@1MHz) und “DCO uncalibrated” zu sehen. Wie man aus dem User-Guide auf Seite 279 entnehmen kann (und auch im Header-FIle), gibt es kalibrierte Einstellungen für bestimmte Frequenzen (bei dem G2231 1MHz, bei z.B. G2452 1MHz, 8MHz und 16MHz). Diese Einstellung wird folgendermaßen vorgenommen:
- BCSCTL1=CALBC1_1MHZ; /* set DCO to 1MHz, set range */
- DCOCTL=CALDCO_1MHZ; /* set DCO step+modulation */
BCSCTL1=CALBC1_1MHZ; /* set DCO to 1MHz, set range */ DCOCTL=CALDCO_1MHZ; /* set DCO step+modulation */
Möchte man auf 8,12 oder 16MHz takten, so ersetzt man “…1MHz” logischerweise durch 8 oder 16. Man kann mit einem einfachen Messgerät einen deutlichen unterschied sehen:
P1.6, LED (calibrated) | P1.6, LED (default) |
![]() | ![]() |
P1.4, SMCLK (calibrated) | P1.4, SMCLK (default) |
![]() | ![]() |