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

  1. /*************************************************
  2.  *     ___       _             _    
  3.  *    |   |_ _ _| |___ ___   _| |___
  4.  *    | | |_'_| . | -_|  _|_| . | -_|
  5.  *    |___|_,_|___|___|___|_|___|___|
  6.  *
  7.  * FILE:     main.c
  8.  * Author:   declis (xdec.de)
  9.  ************************************************/
  10.  
  11. #include <msp430g2231.h>
  12. #include "timer.h"
  13.  
  14. void main(void)
  15. {
  16.     WDTCTL=WDTPW+WDTHOLD;       /* stop watchdog timer */
  17.  
  18.     BCSCTL1=CALBC1_1MHZ;        /* set DCO to 1MHz, set range */
  19.     DCOCTL=CALDCO_1MHZ;         /* set DCO step+modulation */
  20.     P1DIR|=BIT6;                /* P1.6 -> output */
  21.     P1OUT&=~BIT6;               /* clear P1.6 (LED2 off) */
  22.  
  23.     init_TimerA();              /* initialize TimerA */
  24.     _EINT();                    /* enable interrupt */
  25.  
  26.     for(;;);
  27. }
/*************************************************
 *     ___       _             _     
 *    |   |_ _ _| |___ ___   _| |___
 *    | | |_'_| . | -_|  _|_| . | -_|
 *    |___|_,_|___|___|___|_|___|___|
 *
 * 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

  1. /*************************************************
  2.  *     ___       _             _    
  3.  *    |   |_ _ _| |___ ___   _| |___
  4.  *    | | |_'_| . | -_|  _|_| . | -_|
  5.  *    |___|_,_|___|___|___|_|___|___|
  6.  *
  7.  * FILE:     timer.c
  8.  * Author:   declis (xdec.de)
  9.  ************************************************/
  10.  
  11. #include <msp430g2231.h>
  12. #include "timer.h"
  13.  
  14. #define cycles 62500u           /* 500ms */
  15. volatile char count;            /* counter for 2*500ms=1s */
  16.  
  17. /* cycles=(seconds*10^6Hz)/8 */
  18. /* seconds=(8*cycles)/10^6Hz  */
  19. void init_TimerA(void)
  20. {
  21.     TACTL|=TASSEL_2+ID_3;   /* SMCLK, 8x divider */
  22.     TACCR0=cycles;
  23.     count=2;                /* set counter */
  24.     TACCTL0|=CCIE;          /* enable TimerA interrupt */
  25.     TACTL|=MC_1;            /* start timer in up-mode */
  26. }
  27.  
  28. /* Timer_A ISR */
  29. #pragma INTERRUPT (ISR_TimerA)
  30. #pragma vector=TIMERA0_VECTOR
  31. void ISR_TimerA(void)
  32. {
  33.     count--;
  34.     if(!count)
  35.     {
  36.         P1OUT^=BIT6;        /* toggle P1.6 */
  37.         count=2;            /* reset counter */
  38.     }
  39. }
/*************************************************
 *     ___       _             _     
 *    |   |_ _ _| |___ ___   _| |___
 *    | | |_'_| . | -_|  _|_| . | -_|
 *    |___|_,_|___|___|___|_|___|___|
 *
 * 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

  1. /*************************************************
  2.  *     ___       _             _    
  3.  *    |   |_ _ _| |___ ___   _| |___
  4.  *    | | |_'_| . | -_|  _|_| . | -_|
  5.  *    |___|_,_|___|___|___|_|___|___|
  6.  *
  7.  * FILE:     timer.h
  8.  * Author:   declis (xdec.de)
  9.  ************************************************/
  10.  
  11. #ifndef TIMER_H_
  12. #define TIMER_H_
  13.  
  14. void init_TimerA(void);
  15.  
  16. #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:

  1. BCSCTL1=CALBC1_1MHZ;        /* set DCO to 1MHz, set range */
  2. 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)
calibratednot_calibrated
P1.4, SMCLK (calibrated)P1.4, SMCLK (default)
calibrated_01uncalibrated_01

Leave a Reply

Your email address will not be published.

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.