MSP430 Blinklicht (mit Timer)

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: 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.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 */

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)
calibratednot_calibrated
P1.4, SMCLK (calibrated)P1.4, SMCLK (default)
calibrated_01uncalibrated_01

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

This site uses Akismet to reduce spam. Learn how your comment data is processed.