Forum: Mikrocontroller und Digitale Elektronik Probelm beim Taster


von Sven B. (sven98)


Lesenswert?

Guten Abend,

ich hab es geschafft, dass meine LEDs die vier Zustände annimmt.

1) Taste einmal drücken, dann geht die ROTE LED AN
2) Taste zum zweiten mal gedrückt, dann geht die GELBE LED AN und die 
ROTE AUS
3) Taste zum dritten mal gedrückt, dann gehen die beiden AN
4) Taste zum vierten mal gedrückt, dann gehen die beiden LEDs AUS.


hier ist einmal mein Code:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <inttypes.h>
4
#include <avr/power.h>
5
6
#define F_CPU 2000000UL
7
#define TASTE_AUF  0
8
#define TASTE_ZU   1
9
10
int main(void)
11
{
12
  uint8_t alter_tastenzustand = TASTE_AUF;
13
      
14
  
15
  DDRB &=~ (1<<PB0);        
16
  DDRB |= (1<<PB1);        
17
  DDRA |= (1<<PA0) | (1<<PA1);   
18
  PORTB |= (1<<PB0);        
19
20
21
22
23
24
  while(1)
25
  {
26
27
    PORTB &=~ (1<<PB1);               
28
              
29
      
30
    if (!(PINB & (1<<PB0)))            
31
    
32
33
      alter_tastenzustand++;          
34
                          
35
    switch(alter_tastenzustand)          
36
    {
37
      case 0 : PORTA &=~ (1<<PA0);       
38
           PORTA &=~ (1<<PA1); break;
39
40
      case 1 : PORTA &=~ (1<<PA1);        
41
           PORTA |= (1<<PA0); break;    
42
            
43
      case 2 : PORTA &=~ (1<<PA0);      
44
           PORTA |= (1<<PA1); break;
45
46
      case 3 : PORTA |= (1<<PA1);        
47
           PORTA |= (1<<PA0); break;
48
49
      default :PORTA &=~ (1<<PA0);      
50
           PORTA &=~ (1<<PA1); 
51
      alter_tastenzustand = TASTE_AUF; 
52
    }
53
        _delay_ms(100);            
54
55
      
56
    
57
   }
58
}
jetzt meine Frage, wenn ich den Taste gedrückt halte, dann laufen die 
vier Zustände durch und das möchte ich nicht. Ich möchte, wenn ich den 
Taster einmal gedrückt halte, dass nur die ROTE LED AN ist bzw. den 
Zustand hat. Also ich will diesen zustand speichern,wie mach ich das?

Liebe Grüße
Sven98

: Bearbeitet durch User
von kopfkratzer (Gast)


Lesenswert?

kopfkratz
Es wurde doch schon geschrieben wie man das in einer Statemachine 
abbildet.
Statt einfach hochzuzählen mußt Du in jedem Deiner cases die Zustände 
ändern.
Ist Dir eigentlich klar was Dein "Zähler" in der Endlosschleife macht ?

von Karl H. (kbuchegg)


Lesenswert?

Sven Baum schrieb:


> jetzt meine Frage, wenn ich den Taste gedrückt halte,

Sven, das hatten wir doch alles schon mal.

Solange du dich von dieser Strategie hier
1
  while(1)
2
  {
3
    ...
4
      
5
    if (!(PINB & (1<<PB0)))            
6
      ....
7
8
    _delay_ms(100);
9
  }
nicht löst, solange wird das nichts. Und wenn du noch 100 mal fragst.

Die korrekte Strategie ist eine Flankenerkennung, die eine Veränderung 
des Tastenzustands feststellt
1
  uint8_t PinPrevious;
2
  uint8_t PinNow;
3
4
5
  ....
6
  PinPrevious = ( PINB & ( 1 << PB0 ) );
7
8
  while(1)
9
  {
10
11
    PinNow = ( PINB & ( 1 << PB0 ) );
12
13
    if( PinNow != PinPrevious )   // hat sich der Pin verändert?
14
    {
15
      if( !PinNow )               // Ja, hat er. Was ist er jetzt?
16
      {                           // Gedrückt oder Losgelassen?
17
        ....                      //   Er ist gedrückt: mach was, der
18
                                  //   Benutzer hat gerade den Taster gedrückt
19
        ....
20
      }
21
22
      PinPrevious = PinNow;
23
      _delay_ms( 10 );       // Pseudoentprellung, in dem die Prellzeit
24
                             // ausgesessen wird
25
    }
26
  }

Und wenn du noch 200 mal fragst, die Sache wird deswegen nicht 
einfacher. Das ist sowieso schon die abgespeckte Minimalversion mit 
integriertem Bauchweh.


Davon losgelöst ist dann die Sache mit dem Zähler, der angibt welche 
LED-Kombination leuchten soll. Der Teil kommt dann zum Bleistift dort 
rein (aber korrekt schreiben!), wo jetzt die .... Punkte sind. Im 
einfachsten Teil machst du bei einem Tastendruck nur das Erhöhen des 
Statuszählers. Das  Auswerten dieses Zählers und entsprechende 
Beschalten der LED kann auch nach der Tastenauswertung erfolgen.

: Bearbeitet durch User
von Sven B. (sven98)


Lesenswert?

Hallo Karl-Heinz,

ich hab deine Rat befolgt. Am anfang, wollte ich nur die eine LED AN und 
AUS bekommen mit einem Tasten druck. Da habe ich diesen Code verwendet.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <inttypes.h>
4
#include <avr/power.h>
5
6
7
#define F_CPU 2000000UL
8
#define TASTE_AUF   0
9
#define TASTE_ZU   1
10
#define TASTE_NEU   1
11
12
int main(void)
13
{
14
  uint8_t neuer_tastenzustand = TASTE_NEU;
15
  uint8_t alter_tastenzustand = TASTE_AUF;
16
  
17
18
  DDRB &=~ (1<<PB0);        
19
  PORTB |= (1<<PB0);        
20
  DDRB |= (1<<PB1);        
21
  DDRA |= (1<<PA0) | (1<<PA1);   
22
23
  while(1)
24
  {
25
  
26
27
28
    if (PINB & (1<<PB0))                  
29
30
    if (alter_tastenzustand == TASTE_ZU)         
31
32
      {
33
        
34
        PORTA ^= (1<<PA0);                
35
        alter_tastenzustand = TASTE_AUF;        
36
      }
37
      
38
    if (!(PINB & (1<<PB0)))                  
39
    alter_tastenzustand = TASTE_ZU;               
40
  }
41
}

Das gleiche Prinzip hab ich jetzt auch getan, aber es funktioniert 
nicht.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

[ ]   Ich bin in der Lage, Code den mir jemand vorgibt, sinngemäss und 
vollständig zu übernehmen
[ ]   Ich bin nicht dazu in der Lage


Wenn du das Kreuzerl zu oft in der 2-ten Zeile machst, dann solltest du 
dir ernsthaft überlegen, dir ein anderes Hobby zu suchen.

> Das gleiche Prinzip

Pustekuchen. Das ist noch nicht mal annähernd an dem, was ich dir 
vorgezeigt habe.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <inttypes.h>
4
#include <avr/power.h>
5
6
7
int main()
8
{
9
  uint8_t PinPrevious;
10
  uint8_t PinNow;
11
12
  uint8_t Status = 0;
13
14
  DDRB &=~ (1<<PB0);        
15
  PORTB |= (1<<PB0);        
16
  DDRB |= (1<<PB1);        
17
  DDRA |= (1<<PA0) | (1<<PA1);
18
19
  PinPrevious = ( PINB & ( 1 << PB0 ) );
20
21
  while(1)
22
  {
23
24
    PinNow = ( PINB & ( 1 << PB0 ) );
25
26
    if( PinNow != PinPrevious )   // hat sich der Pin verändert?
27
    {
28
      if( !PinNow )               // Ja, hat er. Was ist er jetzt?
29
      {                           // Gedrückt oder Losgelassen?
30
                                  //   Er ist gedrückt: mach was, der
31
                                  //   Benutzer hat gerade den Taster gedrückt
32
        Status++;
33
        if( Status == 2 )
34
          Status = 0;
35
      }
36
37
      PinPrevious = PinNow;
38
      _delay_ms( 10 );       // Pseudoentprellung, in dem die Prellzeit
39
                             // ausgesessen wird
40
    }
41
42
    if( Status == 0 )
43
      PORTA |= ( 1 << PA0 );
44
    else
45
      PORTA &= ~( 1 << PA0 );
46
  }
47
}

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

>> Das gleiche Prinzip
>
> Pustekuchen. Das ist noch nicht mal annähernd an dem, was ich dir
> vorgezeigt habe.


Ich werde das Gefühl nicht los, du würdest denken, das in meiner Vorlage 
eine einzige Zeile die gewünschte Funktionalität ergibt.

Dem ist nicht so!

In der Vorlage ist JEDE Zeile relevant! Erst durch das Zusammenspiel 
ALLER Zeilen ergibt sich die geforderte Funktion. Es gibt nicht "die 
eine Zeile", die alles verändert.

: Bearbeitet durch User
von kopfkratzer (Gast)


Lesenswert?

@Karl Heinz:
Es ist bewundernswert wie Du geduldigt die immer gleichen Fehler 
ansprichst und zu korregieren versuchst.
Doch ich denke mal das hier ein massives Verständnisproblem vorliegt.
Wenn der TO einen Zustandsautomaten bauen will sollte er sich erstmal 
mit dem Thema auseinander setzen statt sinnlos herumzuprobieren.
Wurde ja schon alles durchgekaut:
1. Zustände definieren und auf Papier z.B. als Kreis zeichnen
2. Übergänge der Zustände via Pfeil einzeichnen
3. Übergangsbedingung an Pfeil schreiben
Das dann in ein simples Ablaufdiagramm gießen und damit implementieren.
So schwierig ist das nicht und dann spielt die Programmiersprache auch 
keine Rolle mehr.
Das Problem liegt nicht im Code sondern dem Verständnis was herauskommen 
soll ...

von Karl H. (kbuchegg)


Lesenswert?

kopfkratzer schrieb:

> Wenn der TO einen Zustandsautomaten bauen will sollte er sich erstmal
> mit dem Thema auseinander setzen statt sinnlos herumzuprobieren.

Less es ihn erst mal ins Hirn bringen, dass nicht jede Funktion damit 
erreicht wird, dass man 1 Zeile Code hinschreibt.
Ich denke im Moment entdeckt er gerade, dass es sowas wie Algorithmen 
gibt. Also Vorschriften (an Sven gerichtet), die über viele Stufen 
laufen und an deren Ende dann eine bestimmte Funktionalität steht. Die 
Vorschrift als ganzes ergibt die Funktion. Lass einen teil weg und es 
funktioniert nicht mehr.
Wie beim Kuchenbacken. Das ganze Rezept ist die Vorschrift, wie man zu 
einer Scahertorte kommt. Lass einen Teil weg und du kriegst keine 
Sachertorte mehr.

von kopfkratzer (Gast)


Lesenswert?

Karl Heinz schrieb:
> Lass einen Teil weg und du kriegst keine
> Sachertorte mehr.

Nur das man das Endergebnis trotzdem essen kann :-P

Sven sollte einfach mal das Tutorial durcharbeiten und dazu noch ein 
gutes Buch über Algorithmen und allgemein Datenverarbeitung lesen.
Wenn er dann verstanden hat was die eigentliche Herausforderung ist (das 
ist NICHT das Programmieren) ist er wesentlich weiter ;-)
Aber soll ja "schnell" fertig werden und so :-P

von Sven B. (sven98)


Lesenswert?

Hallo Karl Heinz,

herzlichen Dank für deine Hilfe. Ich konnte die letzten Tage nicht 
antworten, weil ich krank war.

Ich hab es jetzt hinbekommen hab mir mal dein Beispiel durchgearbeitet 
und ich glaube, dass ich es jetzt verstanden habe.

Eine Frage hätte ich da noch.

In meinem Programm siehst Du meine case-Anweisung, weil ich die vier 
Zustände haben möchte und das funktioniert auch wunderbar.

Hier nochmal der geämnderte Code:
1
/*
2
 * Test.c
3
 *
4
 * Created: 28.11.2013 17:58:16
5
 *  Author: 
6
 */ 
7
8
#define F_CPU 2000000UL
9
#include <util/delay.h>
10
#include <avr/io.h>
11
#include <inttypes.h>
12
#include <avr/power.h>
13
14
#include <avr/io.h>
15
#include <util/delay.h>
16
#include <inttypes.h>
17
#include <avr/power.h>
18
19
20
int main()
21
{
22
  uint8_t PinPrevious;
23
  uint8_t PinNow;
24
25
  uint8_t Status = 0;
26
27
  DDRB &=~ (1<<PB0);
28
  PORTB |= (1<<PB0);
29
  DDRB |= (1<<PB1);
30
  DDRA |= (1<<PA0) | (1<<PA1);
31
32
  PinPrevious = ( PINB & ( 1 << PB0 ) );  // Zuweisung : Variable "PinPrevious" = PINB an Port B0 ist 1 (Taster ist nicht gedrückt) 
33
34
  while(1)
35
  {
36
37
    PinNow = ( PINB & ( 1 << PB0 ) );  // Zuweisung : Variable "PinNow" = PINB an Port B0 ist 1 (Taster ist nicht gedrückt)
38
39
    if( PinNow != PinPrevious )      //  Abfrage: Hat sich der Pin an Port B0 verändert?
40
    {
41
      if( !PinNow )          // Ja, hat er. Was ist er jetzt?; Gedrückt oder Losgelassen?; Er ist gedrückt: mach was, der Benutzer hat gerade den Taster gedrückt
42
      {                                      
43
44
        if( Status == 4 )
45
        Status = 0;
46
        
47
        Status++;
48
        switch(Status)
49
        {
50
                      
51
         case 0 : PORTA &= ~(1 << PA0 );
52
              PORTA &= ~(1 << PA1 );break;
53
                      
54
         case 1 : PORTA &= ~(1 << PA1 );
55
              PORTA |= (1 << PA0 );break;
56
                      
57
         case 2 : PORTA &= ~(1 << PA0 );
58
              PORTA |= (1 << PA1 );break;
59
                      
60
         case 3 : PORTA |= (1 << PA1 );
61
              PORTA |= (1 << PA0 );break;
62
                      
63
         default : PORTA &= ~(1 << PA0 );
64
               PORTA &= ~(1 << PA1 );
65
        }
66
67
      }
68
69
      PinPrevious = PinNow;
70
      _delay_ms( 10 );        // Pseudoentprellung, in dem die Prellzeit ; ausgesessen wird
71
    }
72
    
73
74
75
    //if( Status == 0 )
76
    //PORTA |= ( 1 << PA0 );
77
    //else
78
    //PORTA &= ~( 1 << PA0 );
79
    
80
    //if( Status == 1 )
81
    //PORTA |= ( 1 << PA1 );
82
    //else
83
    //PORTA &= ~( 1 << PA1 );
84
    
85
    //if( Status == 2 )
86
    //PORTA &= ~( 1 << PA0 );
87
88
    //if( Status == 3 )
89
    //PORTA &= ~( 1 << PA1);
90
  }
91
}
Ich hatte es do versucht wie Du es mir gezeigt hast (Aus kommentiert), 
diese haben auch funktioniert aber nur für die ersten zwei Zustände.

Also Blaue LED AN und Grüne AUS!
Und Grüne LED AN und Blaue AUS!

Ich bin nicht dahinter gekommen die anderen zwei Zustände zu 
programmieren, deswegen habe ich meine case-Anweisung verwendet.

Hättest Du da vielleicht noch eine Idee?

lg
Sven

: Bearbeitet durch Admin
von Karl H. (kbuchegg)


Lesenswert?

Erstens ist hier
1
        if( Status == 4 )
2
        Status = 0;
3
        
4
        Status++;
die Reihenfolge falsch.

Nimm mal an, Status hätte den Wert 0.
So weit so gut.
Jetzt drückst du eine Taste. Was passiert?
1
        if( Status == 4 )
Hat Status den Wert 4? Nein. Also wird der abhängige Teil nicht 
ausgeführt.
Wie gehts weiter?
1
        Status++;
aus 0 wird 1. So weit so gut.

wieder drückst du die Taste. Was passiert jetzt?
1
        if( Status == 4 )
Hat Status den Wert 4? Nein. Status ist jetzt ja 1, und 1 ist nicht 4. 
Also wird die abhängige ANweisung nicht ausgeführt und es geht weiter 
mit
1
        Status++;
Aus 1 wird 2

Nächster Tastendruck. Wieder landet der Code hier
1
        if( Status == 4 )
2 ist nicht 4, also wird das davon abhängige 0-setzen von Status nicht 
gemacht
1
        Status++;
aus 2 wird 3.

Nächster Tastendruck
1
        if( Status == 4 )
Status hat den Wert 3, daher passiert wieder weiter nichts und es geht 
weiter mit
1
        Status++;
aus 3 wird 4.

Moment, deine if weiter unten behandeln aber den Fall gar nicht, dass 
Status jemals 4 werden könnte!

Nächster Tastendruck. Der Code landet wieder hier
1
        if( Status == 4 )
Diesmal hat STatus den Wert 4. Also wird ausgeführt
1
          Status = 0;
aus 4 wird 0. Wie gehts weiter? Mit
1
        Status++;
Aus der soeben zugewiesenen 0 wird eine 1.

usw. use.

Deine Statusvariable nimmt also bei den Tastendrücken nacheinander diese 
Werte an
1
  0 1 2 3 4 1 2 3 4 1 2 3 4 ....
die erste 0 ist nur mehr oder weniger zufällig entstanden, weil Status 
vor dem ersten Tastendruck mit 0 initialisiert wurde.

Das passt also schon mal nicht.


Dann
1
    //if( Status == 0 )
2
    //PORTA |= ( 1 << PA0 );
3
    //else
4
    //PORTA &= ~( 1 << PA0 );
5
    
6
    //if( Status == 1 )
7
    //PORTA |= ( 1 << PA1 );
8
    //else
9
    //PORTA &= ~( 1 << PA1 );
10
    
11
    //if( Status == 2 )
12
    //PORTA &= ~( 1 << PA0 );
13
14
    //if( Status == 3 )
15
    //PORTA &= ~( 1 << PA1);

bei den Stati 2 und 3 schaltest du ja jeweils nur einen Port-pin aus. 
Aber wie soll da was eingeschaltet werden?

Mach dir halt mal eine Tabelle! Bei welchem Status (diesmal dann aber 
mit den krorrekten Status-Nummern), muss welcher Output-Pin wie stehen? 
Und das implementierst du dann.

: Bearbeitet durch User
von Sven B. (sven98)


Lesenswert?

Oh Schuldigung,

ich hab Dir den alten Code geschcikt.

Der letzte Abschnitt war folgenderweise.

    //if( Status == 0 )
    //PORTA |= ( 1 << PA0 );
    //else
    //PORTA &= ~( 1 << PA0 );

    //if( Status == 1 )
    //PORTA |= ( 1 << PA1 );
    //else
    //PORTA &= ~( 1 << PA1 );

    //if( Status == 2 )
    //PORTA &= ~( 1 << PA0 );
    //PORTA |= ( 1<< PA1 );

    //if( Status == 3 )
    //PORTA &= ~( 1 << PA1 );
    //PORTA |= ( 1 << PA0 );

und mein if( Status == 3 ) und nicht 4. Sorry!!!

von Karl H. (kbuchegg)


Lesenswert?

Im ersten Abschnitt der Antwort rede von der Stelle hier
1
....
2
 while(1)
3
  {
4
5
    PinNow = ( PINB & ( 1 << PB0 ) );  // Zuweisung : Variable "PinNow" = PINB an Port B0 ist 1 (Taster ist nicht gedrückt)
6
7
    if( PinNow != PinPrevious )      //  Abfrage: Hat sich der Pin an Port B0 verändert?
8
    {
9
      if( !PinNow )          // Ja, hat er. Was ist er jetzt?; Gedrückt oder Losgelassen?; Er ist gedrückt: mach was, der Benutzer hat gerade den Taster gedrückt
10
      {                                      
11
12
    #    if( Status == 4 )
13
    #    Status = 0;
14
    #   
15
    #   Status++;
16
17
...

wir sind wieder mal soweit, dass du Programm übernimmst (gut, ich hab es 
dir gegeben), ohne darüber nachzudenken und was noch viel schlimmer ist, 
sie zu verändern ohne darüber nachzudenken, was du eigentlich tust und 
welche Auswirkungen das hat.

von Sven B. (sven98)


Lesenswert?

Das stimmt zwar aber ich hab dein Programm nicht einfach soooo 
übernommen, ich hab versucht es zu verstehen und das hab ich jetzt auch.

Das Programm hattest Du mir schon vor paar Wochen gegeben und ich hab es 
auch nicht sofort übernommen, weil ich es nicht verstanden habe. Ich 
könnte auch das Programm neu schreiben und mit neuen Variablen aber das 
wäre das gleiche.

von Sven B. (sven98)


Lesenswert?

Hallo Karl Heinz,

ich hätte dann mal eine Frage zur deiner Erklärung vom 02.12.20013 17:16 
Uhr!

Wenn ich das soweit verstanden habe, dann dürft die LED bei diesem 
Befehl ja nicht leuchten oder?

.
.
.

        Status++;
        if( Status == 2 )
        Status = 0;

      }

      PinPrevious = PinNow;
      _delay_ms( 10 );   // Pseudoentprellung, in dem die Prellzeit
                         // ausgesessen wird
    }

        if( Status == 0 )
        PORTA |= ( 1 << PA0 );     // Blaue LED AN
        else
        PORTA &= ~( 1 << PA0 );    // Blaue LED AUS

  }
}

weil laut deiner Erklärung ( so weit ich das verstanden habe ) ist ja 
der if( Status == 2 ) und wenn ich jetzt den Taster drücke, dann bekomme 
ich ein 1. Und da in "if( Status == 2) steht, passiert nichts.

: Bearbeitet durch User
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.