Skip to content

MSP430 - Ausgänge der parallelen Schnittstelle

Erstes Programm

  • Mit Hilfe der Ausgänge der parallelen Schnittstelle können z. B. LEDs an- und ausgeschaltet werden.
  • Auf dem Launchpad sind 5 verschiedene LEDs verbaut.

alt: "LEDs auf dem Launchpad", src: "Launchpad MSP-EXP430G2ET, S. 25", w:50, label:"fig:launchpad_leds"

  • Im ersten Programm sollen die rote und grüne LED blinken.
  • Dafür müssen die Jumper J6 und J7 verbunden sein.
  • Die grüne LED ist mit Pin P1.0 und die rote LED mit P1.6 verbunden.

Erstes Programm - Blinken der roten und grünen LED

#include <msp430.h>

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

    P1DIR = 0xFF;
    __no_operation();

    while (1) {
        P1OUT = 0x41;
        __no_operation();
        P1OUT = 0x00;
        __no_operation();
    }
}

Debugging, Flashen und Kompilieren in Code Composer Studio

w:30

  • Debuggen des Programms:
    • Verwenden von Breakpoints, Einzelschritt-Betrieb, Beobachten von Registerwerten
    • Programmieren des MSP430 durch Klicken des grünen Käfer-Symbols. Bug?
  • Programmieren des MSP430 ohne Debuggen durch Klicken des Flash-Symbols.
  • Überprüfen und Kompilieren des Quelltextes (z. B. um Syntax-Fehler zu finden) durch Klicken des Compile-Symbols

alt: "Vereinfachter Schaltplan eines MSP430 ports", w:50

Aufgaben

  1. Was geschieht, wenn das Programm frei läuft?
  2. Untersuchen Sie die Pins P1.0 und P1.6 mit einem Oszilloskop. Wie groß ist die Frequenz des Rechtecksignals?
  3. Warum beträgt das Tastverhältnis nicht 50%?
  4. Entfernen Sie alle __no_operation()-Anweisungen und laden Sie das Programm erneut auf den MSP430. Welche Änderungen ergeben sich?
  5. Die Standard-Taktfrequenz des MSP430 beträgt circa 1 MHz. Wie viele Taktzyklen werden benötigt, um eine Schleifeniteration zu durchlaufen? Wie viele Taktzyklen werden pro NOP-Anweisung benötigt?
Lösung

w:50 w:50

\[ n = \frac{f\ped{clock}}{f\ped{signal}} \]
\[ n_1 \approx 12, \quad n_2 \approx 10 \]

Hinzufügen von Verzögerungs-Routinen

Verwenden einer Schleife

  • Um das Blinken der LEDs für das menschliche Auge sichtbar zu machen, kann das Programm mit Hilfe von Schleifen in der Software verzögert werden.
  • Es sollen folgenden verschiedenen Implementierungen gezeigt werden.

Verzögern des LED-Blinkens mit einer Schleife

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

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

    P1DIR = 0xFF;

    while (1) {
        P1OUT = 0x41;

        volatile uint16_t counter = 50000;
        while (counter > 0) {
            counter--;
        }

        P1OUT = 0x00;
        counter = 50000;
        while (counter > 0) {
            counter--;
        }
    }
}

Datentypen in C"

  • In C gibt es standardmäßig die folgenden Datentypen für Ganzzahlen:
    char, short, int, long
  • Durch den Prefix unsigned können die Ganzzahlen vorzeichenlos gemacht werden, sodass sich der nutzbare Wertebereich verdoppelt.
  • Für ASCII-Zeichen wird ebenfalls der Datentyp char verwendet.
  • Für Gleitkommazahlen stehen die Datentypen float und double zur Verfügung.
  • Native Datentypen für Boolean und Zeichenketten sind nicht vorgesehen.
  • Der Datentyp int ist grundsätzlich ein Wort breit. Das heißt im Fall des MSP430 werden 16bit, beim PC werden 32bit verwendet.
  • Aus diesem Grund sollten für Ganzzahlen die Datentypen der stdint-Headerdatei verwendet werden.
    #include <stdint.h>
stdint nativ Größe Minimum Maximum
int8_t char 8 Bit -128 127
uint8_t unsigned char oder byte 8 Bit 0 255
int16_t short (int) 16 Bit -32 768 32 767
uint16_t unsigned short (unsigned int) 16 Bit 0 65 535
int32_t long 32 Bit -2 147 483 648 2 147 483 647
uint32_t unsigned long 32 Bit 0 4 294 967 295

Schlüsselwort volatile und Compiler-Optimierung

  • Das Schlüsselwort volatile wurde bei der Variable counter hinzugefügt.
  • Diese Schlüsselwort stellt sicher, dass der Compiler keine Optimierungen mit dieser Variable durchführt.
  • Das Entfernen des Schlüsselwortes führt dazu, dass die Schleife optimiert und entfernt wird. Somit wird auch die Zeitverzögerung entfernt.
  • Alternativ kann die Optimierung in den Compiler-Einstellungen deaktiviert werden.

Aufgabe

Verdoppeln Sie die Verzögerungszeit auf 100 000 Iterationen. Stellen Sie sicher, dass die Verzögerung korrekt ausgeführt wird.

Hinweis: Beachte ggf. die Warnung des Compilers!

Kapseln der Schleife in einer Funktion

Verzögerungsschleife in einer Funktion

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

void delay(uint16_t duration);

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

    P1DIR = 0xFF;

    while (1) {
        P1OUT = 0x41;
        delay(50000);
        P1OUT = 0x00;
        delay(50000);
    }
}

void delay(uint16_t duration) {
    volatile uint16_t counter = duration;
    while (counter > 0) {
        counter--;
    }
}

Funktionen in C

  • Jede Funktion benötigt eine Prototypen, wenn diese aufgerufen werden soll.
  • Benutze Funktionen, um...
    • ... die Programmierung zu strukturieren.
    • ... wiederholenden Programmabschnitte zusammenzufassen.

Verwenden von __delay_cycles()

  • __delay_cycles() ist ein Macro, der durch die Header-Datei msp430.h definiert wird.
  • Diese Macro erzeugt eine Verzögerung von exakt n Taktzyklen.
  • n muss während des Kompilieren bekannt sein, ansonsten wird eine Kompilierfehler geworfen.

Verzögerung des LED-Blinken mit __delay_cycles()

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

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

    P1DIR = 0xFF;

    while (1) {
        P1OUT = 0x41;
        __delay_cycles(500000);
        P1OUT = 0x00;
        __delay_cycles(500000);
    }
}

Bitmanipulation

Bitmanipulation

  • Setzen mehrere Bits in einer Variablen: variable |= bits;
  • Zurücksetzen mehrere Bits in einer Variablen: variable &= ~bits;
  • Umschalten mehrere Bits in einer Variablen: variable ^= bits;

Bit-Konstanten

Die folgenden Bit-Konstanten sind in der msp430.h definiert.

Konstante Bin Hex Dec
BIT0 0000 0001 0x01 1
BIT1 0000 0010 0x02 2
BIT2 0000 0100 0x04 4
BIT3 0000 1000 0x08 8
BIT4 0001 0000 0x10 16
BIT5 0010 0000 0x20 32
BIT6 0100 0000 0x40 64
BIT7 1000 0000 0x80 127

Aufgabe

Welchen Wert nimmt das Register nach dem Ausführen der Anweisung an? Geben Sie den Wert mindestens in Hexadezimal und Binär an.

Register-WertAnweisungErgebnis
P1DIR=0;P1DIR|=0b01000001; 
P1DIR=0xF1;P1DIR|=0b01000001; 
P1OUT=0xA5;P1OUT&=~0b00000001; 
P1OUT=0xA5;P1OUT=0b00001111; 
x=0;x|=BIT0+BIT6; 
y=0x55;y&=~(BIT0+BIT2); 
P1OUT=0x40;P1OUT=BIT0+BIT6; 

Überprüfen der Ergebnisse mit der Python-Shell: https://www.python.org/shell/.
P1DIR = 0; P1DIR |= 0b01000001; print(hex(P1DIR) + " " + bin(P1DIR))

Blinken der roten und grünen LED mit Bitmanipulation

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

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

    P1DIR |= BIT0 + BIT6;
    P1OUT &= ~(BIT0 + BIT6);

    while (1) {
        P1OUT |= BIT0;
        P1OUT ^= BIT6;
        __delay_cycles(500000);
        P1OUT &= ~BIT0;
        P1OUT ^= BIT6;
        __delay_cycles(500000);
    }
}

Aufgabe

Die Pins P2.1, P2.3 und P2.5 sind mit der RGB-LED des Lauchpads verbunden (siehe Pinout). Schreiben Sie eine Programm, dass die folgenden Farben nacheinander anzeigt.

  • rot
  • gelb
  • grün
  • türkis
  • blau
  • violett
Lösung
#include <msp430.h>
#include <stdint.h>

#define P_RED (BIT1)
#define P_GREEN (BIT3)
#define P_BLUE (BIT5)
#define DELAY (1000000)

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

    P2DIR |= BIT1 + BIT3 + BIT5;
    P2OUT &= ~(P_RED + P_GREEN + P_BLUE);

    // red
    P2OUT |= P_RED;

    while (1) {
        // red
        P2OUT &= ~P_BLUE;
        __delay_cycles(DELAY);

        // yellow
        P2OUT |= P_GREEN;
        __delay_cycles(DELAY);

        // green
        P2OUT &= ~P_RED;
        __delay_cycles(DELAY);

        // cyan
        P2OUT |= P_BLUE;
        __delay_cycles(DELAY);

        // blue
        P2OUT &= ~ P_GREEN;
        __delay_cycles(DELAY);

        // magenta
        P2OUT |= P_RED;
        __delay_cycles(DELAY);
    }
}

Charlieplexing

  • Charlieplexing ist ein einfacher Weg Pins des Mikrocontrollers beim Ansteuern von LEDs einzusparen.
  • Mit der folgenden Schaltung kann jeweils eine der 6 LEDs mit nur 3 Pins angesteuert werden.

alt: "Charlieplexing mit 3 Pins", w: 50

  • Um eine beliebige LED anzusteuern, muss sich ein Pin auf H-Pegel, ein Pin auf L-Pegel und der dritte im High-Impedance-Mode befinden.
  • Der High-Impedance-Mode wird durch das Löschen des zugehörigen Bits des PxDIR-Registers aktiviert.

Aufgabe

Schreiben Sie ein Programm, dass alle LEDs der Charlieplexing-Schaltung nacheinander aktiviert. Schreiben Sie eine Funktion charlieplexing(n), die genau die n-te LED aktiviert.

Lösung
#include <msp430.h>
#include <stdint.h>

static void charlieplexing(uint8_t n);

int main(void) {
  WDTCTL = WDTPW | WDTHOLD;

  uint8_t i = 0;
  while (1) {
    charlieplexing(i);
    i++;
    if (i >= 6)
      i = 0;
    __delay_cycles(500000);
  }
}

static void charlieplexing(uint8_t n) {
  P2DIR &= ~(BIT0 + BIT1 + BIT2);
  P2OUT &= ~(BIT0 + BIT1 + BIT2);

  switch (n) {
  case 0:
    P2OUT |= BIT0;
    P2DIR |= BIT0 + BIT1;
    break;
  case 1:
    P2OUT |= BIT1;
    P2DIR |= BIT0 + BIT1;
    break;
  case 2:
    P2OUT |= BIT1;
    P2DIR |= BIT1 + BIT2;
    break;
  case 3:
    P2OUT |= BIT2;
    P2DIR |= BIT1 + BIT2;
    break;
  case 4:
    P2OUT |= BIT0;
    P2DIR |= BIT0 + BIT2;
    break;
  case 5:
    P2OUT |= BIT2;
    P2DIR |= BIT0 + BIT2;
    break;
  default:
    break;
  }
}