Forum: Mikrocontroller und Digitale Elektronik Interner Button Launchpad


von H. D. (lactobacillus)


Angehängte Dateien:

Lesenswert?

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.

von Qwerty (Gast)


Lesenswert?

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.

von troll (Gast)


Lesenswert?

Bildformate wieder mal.

von H. D. (lactobacillus)


Lesenswert?

@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.

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

Hm... ich hätte ja gesagt dir fehlt der Pullup, aber der scheint auf dem 
Launchpad drauf zu sein...

kannst es ja trotzdem probieren
1
P1OUT |= (1<<3);
2
P1REN |= (1<<3);

von Qwerty (Gast)


Lesenswert?

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:
1
;*******************************************************************************
2
 .cdecls C,LIST,  "msp430G2553.h"
3
;------------------------------------------------------------------------------
4
            .text                           ; Program Start
5
;------------------------------------------------------------------------------
6
RESET       mov.w   #03FFh,SP               ; Initialize stackpointer
7
StopWDT     mov.w   #WDTPW+WDTHOLD,&WDTCTL  ; Stop WDT
8
SetupP1     bis.b   #00000001b,&P1DIR       ; P1.0 output
9
10
; Pull-up aktivieren, falls kein Pull-up widerstand vorhanden!
11
            bis.b   #00001000b,&P1REN       ; Pull-up aktivieren
12
            bis.b   #00001000b,&P1OUT       ; Pin Pull-up  
13
                                            ;                        
14
Mainloop    bit.b   #00001000b,&P1IN        ; P1.3 hi/low?
15
            jnc     ON                      ; jmp--> P1.3 is set
16
                                            ;
17
OFF         bic.b   #00000001b,&P1OUT       ; P1.0 = 0 / LED OFF
18
            jmp     Mainloop                ;
19
ON          bis.b   #00000001b,&P1OUT       ; P1.0 = 1 / LED ON
20
            jmp     Mainloop                ;
21
                                            ;
22
;------------------------------------------------------------------------------
23
;           Interrupt Vectors
24
;------------------------------------------------------------------------------
25
            .sect   ".reset"                ; MSP430 RESET Vector
26
            .short  RESET                   ;
27
            .end

C:
1
#include  <msp430G2553.h>
2
3
void main(void)
4
{
5
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
6
  P1DIR |= 0x01;                            // Set P1.0 to output direction
7
  P1REN |= (1<<3);
8
  P1OUT |= (1<<3);
9
10
  while (1)                                 // Test P1.3
11
  {
12
    if ((0x08 & P1IN)) P1OUT &= ~0x01;      // if P1.3 set, set P1.0
13
    else P1OUT |= 0x01;                     // else reset
14
  }
15
}

von H. D. (lactobacillus)


Lesenswert?

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.

von troll (Gast)


Lesenswert?

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.

von H. D. (lactobacillus)


Lesenswert?

Ach, ich meinte die if-Geschichte, nicht while. Ich verstehe diese 
spezielle Bedingung nicht:
1
if ((0x08 & P1IN))


Warum sollte man Bits verschieben und nicht einfach setzen?
1
P1REN |= (1<<3);
statt
1
P1REN |= 0x08;

von Karl H. (kbuchegg)


Lesenswert?

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)

von Karl H. (kbuchegg)


Lesenswert?

> 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 ...)

von Karl H. (kbuchegg)


Lesenswert?

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!

von H. D. (lactobacillus)


Lesenswert?

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.

von troll (Gast)


Lesenswert?

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 ...

von Karl H. (kbuchegg)


Lesenswert?

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.

von H. D. (lactobacillus)


Lesenswert?

Vielen Dank für die ausführliche Erklärung.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.