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.
- 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
- 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
Aufgaben
- Was geschieht, wenn das Programm frei läuft?
- Untersuchen Sie die Pins P1.0 und P1.6 mit einem Oszilloskop. Wie groß ist die Frequenz des Rechtecksignals?
- Warum beträgt das Tastverhältnis nicht 50%?
- Entfernen Sie alle
__no_operation()
-Anweisungen und laden Sie das Programm erneut auf den MSP430. Welche Änderungen ergeben sich? - 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
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
unddouble
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 Variablecounter
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-Dateimsp430.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-Wert | Anweisung | Ergebnis |
---|---|---|
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.
- 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;
}
}