Skip to content

MSP430 - Timer A

Übersicht

alt: "Aufbau von Timer A", src: "Family Guide, S. 357", w:70

  • Taktquellen: meist ACLK oder SMCLK
  • Zusätzliche Taktteiler: /1, /2, /4, /8
  • 16-bit Zähler: von 0 bis 0xFFFF / 65535
  • 3 sogenannte capture and compare register CCR0, CCR1 und CCR2
  • Capture mode:
    • Kopieren des Zählerwertes in das CCR im Falle eine Ereignisses (z. B. Flankenwechsel am Eingangsignal)
    • z. B. Messen der Periodendauer und Frequenz von Eingangssignalen
  • Compare mode:
    • Erzeugen eines Interruptes, wenn CCR-Wert gleich dem Zählerwert
    • Automatisches Setzen, Zurücksetzen oder Umschalten eines Pins des MSP430
  • Register des Timer A

alt: "Register TACTL", src: "Family Guide, S. 370", w:70, label:"fig:tactl"

alt: "Register TACCTLx", src: "Family Guide, S. 371", w:70, label:"fig:tacctlx"

Der MSP430G2553 hat zwei Timer A, die mit Timer A0 und Timer A1 bezeichnet werden.

Registernamen von Timer A0 und Timer A1__

Description Timer A0 Timer A1
Timer A Control Register TA0CTL TA1CTL
Timer A Capture&Compare Register 0 TA0CCR0 TA1CCR0
Timer A Capture&Compare Register 1 TA0CCR1 TA1CCR1
Timer A Capture&Compare Register 2 TA0CCR2 TA1CCR2
Timer A Capture&Compare Control Register 0 TA0CCTL0 TA1CCTL0
Timer A Capture&Compare Control Register 1 TA0CCTL1 TA1CCTL1
Timer A Capture&Compare Control Register 2 TA0CCTL2 TA1CCTL2
Timer A Interrupt Vector 0 TIMER0_A0_VECTOR TIMER1_A0_VECTOR
Timer A Interrupt Vector 1 TIMER0_A1_VECTOR TIMER1_A1_VECTOR

Erzeugen regelmäßiger Interruptsignale

Verwendung des CCR0

Erzeugen eines Interruptsignals mit CCR0

#include <msp430.h>
#include <stdint.h>

int main(void) {
    WDTCTL = WDTPW | WDTHOLD;  // stop watchdog timer

    P1DIR |= BIT0;

    TA0CCR0 = 0;
    TA0CCTL0 = CCIE;
    TA0CTL = TASSEL_1 + MC_2 + TACLR;

    __enable_interrupt();

    while (1) {
        __low_power_mode_3();
    }
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR() {
    P1OUT ^= BIT0;
}

Namenskonventionen von Bitfelder in der msp430.h

  • Konstanten, die einzelne Bits enthalten werden entsprechend des Datenblatts benannt.
    z. B. TACLR ist gleich BIT2 oder 0x04
  • Bei Konstanten die mehrere Bits enthalten muss zwischen mit Unterstrich und ohne Unterstrich unterschieden werden.
  • Dies zeigt die folgende Tabelle am Beispiel der Mode-Control-Bits
Wert Beschreinung Mit Unterstrich Ohne Unterstrich
00 Stop Mode MC_0 0
01 Up Mode MC_1 MC0
10 Continuous Mode MC_2 MC1
11 Up/Down Mode MC_3 MC1 + MC0

Berechnungen von Zeitverzögerungen des Timers"

Formel:

\[ \Delta t = \frac{\Delta n}{f} \]

mit \(\Delta t\) der Zeitdauer zwischen zwei Ereignissen, \(\Delta n\) der Differenz der Zählerwerte, oder dem CCR-Wert und \(f\) der Frequenz des Taktgebers des Timers.

Mit \(f = 32.768\si{kHz}\) ergeben sich die folgenden Werte

Δn (hex) Δn (dec) Δt [ms]
0x4000 16384 500
0x8000 32768 1000
0xC000 49152 1500
0xFFFF 65535 1999.97
0x10000 65536 2000

Blinken mit 1 Hz

  • Um eine LED mit einer Frequenz von 1 Hz blinken zu lassen, muss alle 500 ms der Pin umgeschaltet werden.
  • Alle 0x4000 Zählschritte muss eine Interrupt erfolgen.

Lösung 1: Up Mode

Blinken mit 1 Hz - Up Mode

TA0CCR0 = 0x4000;
TA0CCTL0 = CCIE;
TA0CTL = TASSEL_1 + MC_1 + TACLR;

Lösung 2: Continuous Mode

Blinken mit 1 Hz - Continuous Mode

TA0CCR0 = 0x4000;
TA0CCTL0 = CCIE;
TA0CTL = TASSEL_1 + MC_2 + TACLR;

...

#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR() {
    P1OUT ^= BIT0;
    TA0CCR0 += 0x4000;
}

Verwenden aller CCR und des Timer Overflow Interrupts

Verwenden aller CCR und des Timer Overflow Interrupts

int main(void) {
    WDTCTL = WDTPW | WDTHOLD;  // stop watchdog timer

    P1OUT &= ~BIT0;
    P2OUT &= ~(BIT1 + BIT3 + BIT5);
    P1DIR |= BIT0;
    P2DIR |= BIT1 + BIT3 + BIT5;

    TA0CCR0 = 0x2000;
    TA0CCTL0 = CCIE;
    TA0CCR1 = 0x4000;
    TA0CCTL1 = CCIE;
    TA0CCR2 = 0x8000;
    TA0CCTL2 = CCIE;
    TA0CTL = TASSEL_1 + MC_2 + TACLR + TAIE;

    __enable_interrupt();

    while (1) {
        __low_power_mode_3();
    }
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR() {
    P2OUT ^= BIT1;
    TA0CCR0 += 0x2000;
}

#pragma vector=TIMER0_A1_VECTOR
__interrupt void TimerA1_ISR() {
    switch (TAIV) {
    case 2:
        // CCR1 Interrupt
        P2OUT ^= BIT3;
        TA0CCR1 += 0x4000;
        break;
    case 4:
        // CCR2 Interrupt
        P2OUT ^= BIT5;
        TA0CCR2 += 0x8000;
        break;
    case 10:
        // Timer Overflow
        P1OUT ^= BIT0;
        break;
    }
}

Aufgabe

Veränderen Sie Ihre RGB-LED-Programm so, dass die Farben rot, gelb, grün, türkis, blau und violett automatisch durchrotieren. Durch einen Tastendruck soll zwischen mehreren Geschwindigkeiten gewechselt werden können.

Verwenden Sie Interrupt und den Low-Power-Mode. ISR sollen so kurz wie möglich gehalten werden.

Aufgabe

Verändern Sie das vorangengene Programm so, dass anstelle des Timers A0 der Timer A1 verwendet wird.

Erzeugen symmetrischer Rechtecksignale

  • Beispiel: Erzeugen eines 440 Hz Rechtecksignals auf Grundlage des 32,768 kHz Taktgebers
  • Schalten eines 440 kHz Signals benötigte eine hohe Anzahl von Taktzyklen.
  • Die CCR können automatisch spezielle Pins des MSP430 manipulieren. Nach der Initialisierung werden keine CPU-Takte benötigt.
  • Diese Pins müssen mit dem Timer A verbunden sein, siehe Pinbelegung des MSP430G2553:

alt: "Pinbelegung des MSP430G2553 mit 20 Pins", w: 75, src: "https://github.com/RobFro96/MSP430Pinouts"

Timer-Pins des MSP430G2553"

Pin Timer CCR
P1.1 Timer A0 CCR0
P1.2 Timer A0 CCR1
P1.5 Timer A0 CCR0
P1.6 Timer A0 CCR1
P2.0 Timer A1 CCR0
P2.1 Timer A1 CCR1
P2.2 Timer A1 CCR1
P2.3 Timer A1 CCR0
P2.4 Timer A1 CCR2
P2.5 Timer A1 CCR2

Verwenden des CCR zum Manipulieren der Pins

  • Um die Verbindung des Pins mit dem Timer herzustellen müssen die Bits der Register PxSEL und PxSEL2 entsprechend gesetzt werden (siehe Pinbelegung).
  • Um P2.0 mit den Timer zu verbinden müssen P2SEL = 1 und P2SEL2 = 0 gesetzt werden.
  • Die Datenrichten des Pins muss außerdem auf Ausgang gesetzt werden.
    P2SEL |= BIT0;
    P2SEL2 &= ~BIT0;
    P2DIR |= BIT0;
    
  • In welcher Art und Weise die Pins bei einen CCR-Ereignis verändert werden, wird durch die OUTMOD-Bits des TAxCCTLx-Registers bestimmt.

    alt: "CCR-Ausgang bei verschiedenen OUTMOD-Werten", src: "Family Guide, S. 364", w:50

  • Zum Erzeugen eines symmetrischen Rechtecksignals sollte OUTMOD = 4 verwendet werden.

Erzeugen eines 440 Hz-Signals an P2.0

int main(void) {
    WDTCTL = WDTPW | WDTHOLD;  // stop watchdog timer

    P2SEL |= BIT0;
    P2SEL2 &= ~BIT0;
    P2DIR |= BIT0;

    TA1CCR0 = 37;
    TA1CCTL0 = OUTMOD_4;
    TA1CTL = TASSEL_1 + MC_1 + TACLR;

    __enable_interrupt();

    while (1) {
        __low_power_mode_3();
    }
}

Aufgabe

Messen Sie das Signal an P2.0 mit einem Oszilloskop. Wie hoch ist die Signalfrequenz?

Verändern Sie den Wert des CCR0-Registers auf 36. Warum ist die Signalfrequenz nun exakter?

Lösung
\[f_{37} = 431.158\si{Hz}\]

→ The generated frequency is to slow.

\[f_{36} = 442.811\si{Hz} \]

→ The timer counts from 0 to 36. This results into 37 counter steps. The frequency is generated with an CCR value of 36.

Aufgabe

Verwenden Sie die SMCLK des um ein 1 kHz Rechtecksignal an P2.0 zu erzeugen. Messen Sie die Signalfrequenz.

Der DCO des MSP430 erzeugt den Takt für die MCLK und SMCLK. Dieser muss kalibriert werden, um exaktere Ausgangssignale zu liefern. Texas Instruments speichert Kalibrierwerte für 1, 8, 12 und 16 MHz im Flash-Speicher des MSP430.

Um diese Werte zu laden, müssen die folgeden beiden Befehle zu Beginn des Programms eingefügt werden.

BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;

Der DCO des MSP430 ist nicht so exakt, wie der Quarzoszillator der ACLK. Die Frequenz des DCO ist außerdem stark abhängig von Umgebungstemperatur und Betriebsspannung.

Lösung
WDTCTL = WDTPW | WDTHOLD;  // stop watchdog timer

P2SEL |= BIT0;
P2SEL2 &= ~BIT0;
P2DIR |= BIT0;

TA1CCR0 = 499;
TA1CCTL0 = OUTMOD_4;
TA1CTL = TASSEL_2 + MC_1 + TACLR;

__enable_interrupt();

while (1) {
  __low_power_mode_0();
}
\[ f\ped{uncal} = 1.065\si{kHz} \]
\[ f\ped{cal} = 1.002\si{kHz} \]

Erzeugen pulsdauer-modulierter Signale

alt: "Verschiedene Tastverhältnisse (Duty-Cycles) eines PWM-Signals", src: "Wikipedia-Commons", w:45

  • Verwenden von PWM-Signalen:
    • Einfachste Form eines Digital-Analog-Wandlers
    • Ausgabe von analogen Audiosignalen
    • Dimmen von LEDs
    • Geschwindigkeitssteuerung von Gleichstrommotoren
    • Steuern von Modellbau-Servomotoren

Dimmen von LEDs

Dimmen von LEDs an P2.1 und P2.5

volatile uint8_t pwm = 16;

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;  // stop watchdog timer

    P1DIR &= ~BIT3;
    P1OUT |= BIT3;
    P1REN |= BIT3;
    P1IES |= BIT3;
    P1IFG &= ~BIT3;
    P1IE |= BIT3;

    P2SEL |= BIT1 + BIT5;
    P2SEL2 &= ~(BIT1 + BIT5);
    P2DIR |= BIT1 + BIT5;

    TA1CCR0 = 255;
    TA1CCR1 = pwm;
    TA1CCTL1 = OUTMOD_7;
    TA1CCR2 = 255 - pwm;
    TA1CCTL2 = OUTMOD_7;
    TA1CTL = TASSEL_1 + MC_1 + TACLR;

    __enable_interrupt();

    while (1) {
        __low_power_mode_3();

        pwm += 32;
        TA1CCR1 = pwm;
        TA1CCR2 = 255 - pwm;
    }
}

#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR() {
    if (P1IFG & BIT3) {
        P1IFG &= ~BIT3;
        __low_power_mode_off_on_exit();
    }
}

Steuern von Modellbau-Servomotoren

Aufgabe

Verbinden Sie einen Modellbau-Servomotor mit dem Launchpad. Verwenden Sie die folgenden Pin-Belegung. Stellen Sie sicher, dass Sie die 5 V-Betriebsspannung verwenden.

alt: "Pinbelegung eines Modellbau-Servomotors", src: "components101.com", w:30

Im folgenden Bild ist der Signalverlauf zu sehen, der verwendet werden muss, um einen Servomotor zu steuern. Programmieren Sie den MSP430, sodass die Position des Servomotors mit Hilfe eines Tasters verändert werden kann.

alt: "PWM-Signal zum Ansteuern eines Modellbau-Servos", src: "Wikipedia-Commons", w:50