Es ist ziemlich peinlich, aber ich verzweifle gerade an einem der
einfachsten Programme für das MSP430 Launchpad.
Das Ziel ist einfach:
Eine der LEDs mittels des eingabauten Buttons leuchten lassen. Ich habe
schon alle möglichen Beispielcodes aus dem Internet kopiert, aber die
Funktionieren nicht (andere Boardversion? Andere CCS-Version?).
Ich habe die Boardversion 1.5, verwende den M430G2553 und CCS
5.2.1.00018.
Die LEDs bekomme ich zum blinken, nur an der Steuerung per Button
haperts.
Wäre sehr nett, wenn mir jemand ein entsprechendes Progrämmchen
schreiben könnte, was auf dem einenen Launchpad 1.5 läuft.
Im Anhang noch ein Foto, was die derzeitige Konfiguration der Boards
zeigt.
Edit: Der Button funktioniert bei der Demo, liegt also an der
Software/Compiler oder am User.
Die erste Wahl wäre wohl die slac485, dort stehen Beispielcodes, die nur
geringfügig geändert werden müssen:
http://www.ti.com/lit/zip/slac485
Also z.B. msp430x2xx3_P1_01.asm bzw. msp430x2xx3_P1_01.c.
Der Taster muss auf P1.3 (Launchpad) und die LED auf P1.0/6 im code
geändert werden.
@Qwerty: funktioniert nicht.
Ich habe folgendes Programm verwendet (msp430x2xx3_P1_01.c):
#include <msp430g2553.h>
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= 0x01; // Set P1.0 to output
direction
while (1) // Test P1.4
{
if ((0x08 & P1IN)) P1OUT |= 0x01; // if P1.4 set, set P1.0
else P1OUT &= ~0x01; // else reset
}
}
Im Orginal steht statt 0x08 ein 0x10, aber der Button ist auf P1.3 und
nicht P1.4. Läuft aber halt trotzdem nicht.
Dabei zu beachten gab es, dass die Taster beim Launchpad gegen GND
geschaltet werden, während im ursprünglichen code gegen Vcc geschaltet
wurde. Die Aktivierung der pull-ups habe ich mal drin gelassen, falls
man den code in Schaltungen ohne externe pull-ups verwenden will. Das
Launchpad besitzt aber, wie schon erwähnt, pull-ups an den Tastern.
ASM:
Ok, aus anderen Quelle konnte ich dieses Programm ableiten:
#include <msp430g2553.h>
unsigned int i = 0;
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; /* Stop watchdog timer */
P1DIR = 0x41; /* Set LEDs to output direction */
P1OUT |= 0x08;
P1IE |= 0x08; /* P1.3 interrupt enabled */
P1IFG &= ~0x08; /* P1.3 IFG cleared */
P1REN |= 0x08; /* Enable the Pull Up */
__enable_interrupt(); /* enable all interrupts */
}
// Port 1 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
P1OUT ^= 0x41; /* LED toggle */
for(i=0; i< 5000; i++); /* Entprellen*/
P1IFG &= ~0x08; /* P1.3 IFG cleared */
}
Querty, dein Programm funktioniert auch. Ich habe dazu 2 Fragen:
Was macht "(1<<3)"?
Wie funktioniert die Whileschleife? Die Bedingung ist mir unklar.
Henning D. schrieb:> Was macht "(1<<3)"?
Eine 1 3 Stellen nach links schieben. Bitmanipulation> Wie funktioniert die Whileschleife?
Welche? while(1)? Das ist eine Endlosschleife, 1 ist !=0 und somit immer
wahr.
Henning D. schrieb:> Warum sollte man Bits verschieben und nicht einfach setzen?>
1
P1REN |= (1<<3);
Weil in dieser Schreibweise jeder Blinder aus 3 Meter Entfernung greifen
kann, dass hier vom Bit Nummer 3 die Rede ist.
(Wenn du den Compiler dazu einsetzen kannst, dass er dir lästige
Standardrechnerein abnimmt, dann tu das! Denn der Compiler macht dabei
keine Fehler. Du aber schon)
> Ich verstehe diese spezielle Bedingung nicht:> if ((0x08 & P1IN))
Mit dem Wissen, dass (1<<irgendwas) meistens das 'Bit irgendwas'
bedeutet, würdest du dann
if( P1IN & (1<<3) )
besser verstehen.
(Wenn Pin NUmmer 3 in P1IN auf 1 gesetzt ist, dann ...)
Im übrigen kommt das (zumindest sollte es das) in realem Code nicht vor.
In realem Code sollte das dann so stehen
1
#define TASTER_PORT P1IN // Port, an dem der Taster hängt
2
#define TASTER 3 // Taster hängt am Pin 3 vom Port 1
3
4
#define LED_POPRT P1OUT // POrt, an dem die LED hängt
5
#define LED 7 // Diese LED hängt am Pin 7
6
7
....
8
9
10
if(TASTER_PORT&(1<<TASTER))
11
LED_PORT|=(1<<LED);
12
else
13
LED_PORT&=~(1<<LED);
und wenn dann irgendwann mal die LED vom Pin 7 auf den Pin 5 umziehen
muss (wegen zb Hardware Änderung), dann ändert man einfach
1
#define LED 5 // Diese LED hängt am Pin 5
und den Rest des Programm passt der Compiler entsprechend an, ohne dass
du lange und fehlerträchtig irgendwelche Hex-Zahlen neu bestimmen musst.
Lass den Compiler für dich arbeiten!
Danke, jetzt hab ichs verstanden. (1<<3) war mich sprachmäßig nicht
bekannt.
Mir war bekannt, dass man später mit #define arbeiten sollte. Ich wollte
Code und Hardware lieber erst einmal "pur" verstehen.
An der If-Bedingung ist mir noch eine Kleinigkeit unklar:
"Übersetzt" steht da doch: P1IN UND (Bit3=1)
P1IN sind ja 8 Bit, welche dann nur mit einem Bit verglichen werden. Der
Compiler weiß aufgrund des "&" schon, dass er sich aus dem P1IN das
richtige Bit raussuchen muss?
Meine Fragen mögen recht merkwürdig klingen. Meine "Muttersprache" ist
Python. Hier würde ich einfach "If P1IN[4]==1" schreiben.
Henning D. schrieb:> An der If-Bedingung ist mir noch eine Kleinigkeit unklar:> "Übersetzt" steht da doch: P1IN UND (Bit3=1)> P1IN sind ja 8 Bit, welche dann nur mit einem Bit verglichen werden. Der> Compiler weiß aufgrund des "&" schon, dass er sich aus dem P1IN das> richtige Bit raussuchen muss?
???
"Übersetzt" steht da:
Nimm eine 1: 1
Schiebe sie 3 Stellen nach links: 1000
Verunde diesen Wert mit dem des Registers P1IN.
Teste ob der Wert ungleich Null ist und führe ggf. den Code im {}-Block
aus.
Oder anders gesagt (Zitat KHB):
>Wenn Pin NUmmer 3 in P1IN auf 1 gesetzt ist, dann ...
Henning D. schrieb:> P1IN sind ja 8 Bit, welche dann nur mit einem Bit verglichen werden. Der> Compiler weiß aufgrund des "&" schon, dass er sich aus dem P1IN das> richtige Bit raussuchen muss?
Dieses & ist das 'binäre UND'.
Ein binäres UND verknüpft Einzelbits.
Bit A Bit B Ergebnis
----------------------------
0 0 0
1 0 0
0 1 0
1 1 1
Das Ergebnis ist nur dann 1, wenn A UND B 1 waren.
Hier an dieser Stelle hast du die 8 Bits vom P1Iin und einer 'Maske'
P1IN 01101001
Maske 01000000
-------------------------- UND
01000000
(Jeweils untereinander stehende Bits werden einzeln miteinander
UND-verknüpft). Im Ergebnis bleibt nur an der Bitposition 6 eine 1
übrig, weil hier in beiden 8-Bit Werten an dieser Position ein 1 Bit
ist. Für alle anderen untereinanderstehenden Bits es nicht so ist, dass
in beiden Werten eine 1 dort steht und deshalb kommt da überall 0
heraus.
Aber: Da es in der Maske nur an Bitposition 6 eine 1 gibt, KÖNNEN die
restlichen Bits (also alle ausser der 6) gar nie nicht 1 ergeben. Das 0
Bit in der Maske sorgt dafür, dass an diesen Stellen im Ergebnis auf
jeden Fall eine 0 auftauchen wird.
Hier könnte man daher das UND wie ein Sieb auffassen durch welches P1IN
'gequetscht' wird und bei dem alle Löcher ausser einem (nämlich dem, wo
das 1 Bit sitzt) verstopft sind. Das Endergebnis wird nur von dieser
einen Bitposition bestimmt. Enteweder da kommt eine 1 aus P1IN durch
(wenn in P1IN eine 1 an dieser Bitposition war) oder da kommt im
Endergebnis eine 0 hin (weil in P1IN ebenfalls an dieser Stelle eine 0
war.)
P1IN & Maske
ist also nichts anderes als die Operation:
Nimm P1IN und setzte alle Bits im Ergebnis auf 0, deren Maskenbit
ebenfalls 0 ist.
Und anstelle die Maske so anzuschreiben: 0x40 schreibt man sie eben dann
so hin ( 1 << 6 ), denn dann sieht man sofort dass es hier darum geht
eine Maske zu bauen, die an der Bitposition 6 ein 1 Bit hat und alle
anderen Bits sollen 0 sein.
Das Ergebnis von
P1IN & ( 1 << 6 )
ist also entweder (gesehen über alle Bits) eine glatte 0, weil
das Ergebnis so aussieht 00000000
-> dann war auch das Bit 6 in P1IN ein 0-Bit
oder es ergibt sich ein Ergebnis, welches nicht gleich 0 ist, weil
das Ergebnis so aussieht 01000000
-> dann war auch das Bit 6 in P1IN ein 1-Bit
(Beachte: Uns interessiert gar nicht, welche Zahl genau da
dahinter steckt, wenn im Endergebnis an der Bitposition 6
ein 1 Bit ensteht. Dieses gesetzte 1 Bit sorgt auf jeden Fall
dafür, das das Ergebnis nicht 0 sein kann. Und das reicht schon.
Mit "da entsteht etwas, das auf jeden Fall erst mal nicht 0 ist"
kann man in C wunderbar leben.