Forum: Compiler & IDEs Code Idee um Display einmalig zu löschen (Arduino Uno)


von Toni K. (knieto)


Lesenswert?

Hallo zusammen,

ich habe ein 16x2 Display. Angesteuert beschreiben alles funktioniert. 
Kein Thema.

Allerdings habe ich mir was überlegt.
Ich habe ein Poti welcher zum scrollen verschiedener Seiten zuständig 
ist.
1. Seite: Namen eingeben
          OK druecken

Dieser OK Button soll ein Taster sein.
Wenn ich diesen betätige soll er mir den Text löschen der vorher da 
stand
das habe ich mit lcd.clear(); gemacht. Dann will ich einen neuen Text 
schreiben. Aber so lange der Taster ja noch den Zustand hat, das er 
gedrückt wurde, durchläuft er ja ewig die IF-Abfrage. Und cleart jedes 
mal mein Display. Ergo es flimmert dann immer wieder.
Einer eine Idee wie ich das elegant umgehen kann?

Danke


Wenn Ihr den Code wollt sagt einfach bescheid...
Ich arbeite mich grade in das Display ein und möchte eine Art Menü 
aufbauen.

: Verschoben durch User
von Karl H. (kbuchegg)


Lesenswert?

Du musst unterscheiden zwischen
* einer Aktion die ausgeführt wird, solange eine Taste gedrückt ist
* eine Aktion die einmalig beim Drücken einer Taste ausgeführt wird

Letzters sind genau die komplexeren Codestücke, die man immer wieder 
unter Tastenerkennung une Entprellung findet. Denn die Erkennung ist an 
und für sich simpel: Wenn der Taster vom Zustand 'nicht gedrückt' in den 
zustand 'gedrückt' wechselt, dann wurde die Taste offenbar 
niedergedrückt. Das ist nichts anderes als eine Flankenerkennung, die 
aus dem Vergleich von vorher und jetzt lebt. Die Schwierigkeit liegt in 
der Entprellung eines Tasters.


Da du Ardunio erwähnt hast. Für einen Arduino hab ich nichts vorrätig.
1
uint8_t vorher;
2
3
4
void loop()
5
{
6
  uint8_t jetzt;
7
8
  jetzt = digital_read( ... );
9
  if( jetzt != vorher ) {   // Irgendetwas ist an der Taste passiert
10
    vorher = jetzt;
11
    if( jetzt == LOW ) {    // ... sie wurde offenbar niedergedrückt
12
                            // (anders rum wäre sie ja losgelassen worden)
13
      ...
14
    }
15
  }

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Toni K. schrieb:
> Einer eine Idee wie ich das elegant umgehen kann?

Flankenerkennung programmieren, d.h. nur der Wechsel nach gedrückt löst 
die Aktion aus.
Bei vielen Entprellroutinen ist das schon implementiert.

von Xman (Gast)


Lesenswert?

Toni K. schrieb:
> Aber so lange der Taster ja noch den Zustand hat, das er
> gedrückt wurde, durchläuft er ja ewig die IF-Abfrage. Und cleart jedes
> mal mein Display. Ergo es flimmert dann immer wieder.
> Einer eine Idee wie ich das elegant umgehen kann?

Sorge einfach dafür, dass er den Zustand nicht mehr hat.

von Joachim B. (jar)


Lesenswert?

dann schreib doch den neuen Text erst wenn der Taster losgelassen wurde,
und oder merke dir das der Taster gedrückt wurde, setze ein Flag das 
erst wieder zurückgesetzt wird wenn der Taster losgelassen wurde, denn 
solange das Flag nicht steht braucht man nur einmal in die Löschroutine 
hüpfen und erst dann in den neuen Text wenn der Taster losgelassen wurde 
und das Flag nach löschen zurückgesetzt wurde.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Nur eine von vielen Möglichkeiten :
Toni K. schrieb:
> das habe ich mit lcd.clear(); gemacht.

Dann kannst du dir eine Flagge setzen a là 'DisplayIsClear'

Toni K. schrieb:
> Und cleart jedes
> mal mein Display.

Das überspringst du, wenn die Flagge 'DisplayIsClear' gesetzt ist.

Alledings gibt es viele Wege.
Hier ist es evtl. sogar besser, die Tastenabfrage umzugestalten derart, 
das du nur Tastenänderungen auswertest und damit Flaggen setzt. Eine 
Tastenentprellroutine wie diese hier ist da recht komfortabel:
https://www.mikrocontroller.net/articles/Entprellung

von MaWin (Gast)


Lesenswert?

Toni K. schrieb:
> Einer eine Idee wie ich das elegant umgehen kann?

Ordentlich programmieren lernen.

Bei Tastern entprellt man und fragt im Programm dann Flanken (also den 
Wechsel von 0 auf 1) ab.

http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29.1
http://www.mikrocontroller.net/articles/Entprellung

NICHT so:

http://we-mod-it.com/board6-allgemein/board108-how-to/board231-raspberry-arduino/2920-arduino-tutorial-1-2-taster-entprellen/

von Toni K. (knieto)


Lesenswert?

Ok, um das prellen zu vermeiden, müsste ich wahrscheinlich eine Delay 
einbauen.
Oder einen Extra Prellfreien Taster kaufen...

Eine kurzes Delay stört mich allerdings nicht.
ich möchte den Taster nur ein einziges mal zur Bestätigung Betätigen ;-) 
(hört sich gut an)

Ich habe es mir so gedacht :
1
#include <LiquidCrystal.h>
2
3
// initialize library with the numbers of the interface pins:
4
//               (RS, Enable, DB4, DB5, DB6, DB7)
5
LiquidCrystal lcd(7,  8,      9,   10,  11,  12);
6
int ok = 2;
7
int seite;
8
int poti;
9
const int sensorMin = 0;      // sensor minimum, discovered through experiment
10
const int sensorMax = 1023;    // sensor maximum, discovered through experiment
11
12
void setup() 
13
{
14
  // Das Display initialisieren also wieviele Spalten(16) und Zeilen(2) 
15
  lcd.begin(16, 2);
16
  pinMode(ok, INPUT);
17
  
18
}
19
20
void loop() 
21
{
22
  poti = analogRead(0);
23
  ok = digitalRead(2);
24
  // map the sensor range to a range of four options:
25
  int seite = map(poti, sensorMin, sensorMax, 0,5 );
26
  digitalRead(ok);
27
  
28
  
29
  
30
  
31
  
32
  switch (seite) 
33
  {
34
    case 0:
35
       if(ok == LOW)
36
       {
37
       lcd.setCursor(0, 0);
38
       lcd.print("Name eingeben!"); 
39
       lcd.setCursor(0, 1);
40
       lcd.print("OK druecken"); 
41
       }
42
       else
43
       {
44
       lcd.clear();
45
       lcd.setCursor(0, 1);
46
       lcd.print("neuer Text");
47
       } 
48
        
49
      break;
50
    case 1:
51
       lcd.setCursor(0, 0);
52
       lcd.print("2. Seite"); 
53
      break;
54
    case 2:
55
       lcd.setCursor(0, 0);
56
       lcd.print("3. Seite"); 
57
      break;
58
    case 3:
59
       lcd.setCursor(0, 0);
60
       lcd.print("4. Seite"); 
61
      break;
62
    case 4:
63
       lcd.setCursor(0, 0);
64
       lcd.print("5. Seite"); 
65
      break;
66
  
67
  }
68
  
69
  
70
 */ //lcd.clear();
71
if(ok==HIGH)
72
  {
73
    digitalWrite(ok, HIGH);
74
    lcd.print(" ");
75
    if(ok==HIGH)
76
    {
77
          lcd.setCursor(8, 1);
78
       lcd.print("HIGH"); 
79
    }
80
  }
81
}
82
*
83
}

von Karl H. (kbuchegg)


Lesenswert?

Toni K. schrieb:

>        if(ok == LOW)
>        {
>        lcd.setCursor(0, 0);
>        lcd.print("Name eingeben!");
>        lcd.setCursor(0, 1);
>        lcd.print("OK druecken");
>        }
>        else
>        {
>        lcd.clear();
>        lcd.setCursor(0, 1);
>        lcd.print("neuer Text");
>        }

Du kannst es drehen und wenden wie du willst, aber so wird das nichts


Du brauchst eine Flankenerkennung. Die lebt aus dem Vergleich von 
vorher/jetzt
1
uint8_t vorher;
2
3
4
void loop()
5
{
6
  uint8_t jetzt;
7
8
  jetzt = digital_read( ... );
9
  if( jetzt != vorher ) {   // Irgendetwas ist an der Taste passiert
10
    vorher = jetzt;
11
    if( jetzt == LOW ) {    // ... sie wurde offenbar niedergedrückt
12
                            // (anders rum wäre sie ja losgelassen worden)
13
      ...
14
    }
15
  }

Das ist der erste Schritt, um einmalig eine Aktion durchzuführen, die 
von einer Änderung des Eingangszustandes abhängt.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Sowas löst man zum Beispiel mit Zustandsautomaten. Lies dich mal zu 
diesem Thema ein. Auf den ersten Blick mag es verwirrend oder unnötig 
komplex aussehen. Aber du wirst bei praktischer Anwendung dieses 
Patterns schnell merken, dann man damit viele reale Aufgaben elegant und 
erweiterbar lösen kann.

Zustandsautomaten haben folgende grund-Eigenschaften:

Bei Arduino besteht das Haputprogramm ja stets aus einer Funktion, die 
endlos oft wiederholt wird. Das ist schonmal eine durchaus sinnvolle 
Vorgabe und passt perfekt zum Zustandsautomaten.

Es gibt (im Idealfall) keine Warteschleifen. Stattdessen wird immer nur 
auf Ereignisse reagiert. Wenn "dies", dann mach "das". Wenn kein 
interessantes Ereignis aufgetreten ist, endet die Prozedur. Und dank der 
Hauptschleife (des Arduino Frameworks) wird sie immer wieder erneut 
aufgerufen.

Aber, ein Ereignis soll nicht immer zur gleichen Reaktion führen, wie 
dein Beispiel mit dem Taster zeigt. Der Code "Wenn Taster gedrückt, dann 
lösche das Display" löscht das Display öfter, als gewünscht.

An dieser Stelle kommt der Zustand in Spiel, der dem Zustandsautomaten 
seinen Namen verleiht. Welche Ereignisse von Interesse sind und wie 
darauf reagiert wird, hängt vom Zustand der Maschine ab.

Typischerweise wird der Zustand in einer Variablen gespeichert und mit 
switch/case verzweigt.

Lies jetzt mal einen Wiki Artikel zum Zustandautomaten, danach lies hier 
weiter.

Nun gebe ich Dir eine kleine Hilfe, wie deine Aufgabe mit 
Zustandsautomat gelöst werden kann. Lass uns erstmal nur auf den Taster 
und das Löschen des Displays konzentrieren. Das Display soll nur 
gelöscht werden, wenn es noch nicht gelöscht wurde. Da haben wir zwei 
Zustände:

1=Display wurde noch nicht gelöscht
  Ereignis: Taste drücken
  Führt zu: Display löschen und Wechsel zu Zustand 2

2=Display ist gelöscht aber Taste ist immer noch gedrückt
  Ereignis: Taste loslassen
  Führt zu: Wechsel zu Zustand 1

Und so sieht das dann in Pseudo-Code aus (die Detailumsetzung in C 
bekommst du sicher selbst hin):
1
void tastenabfrage()
2
{
3
    static uint8_t status=1;
4
5
    switch (status)
6
    {
7
        case 1: // Das Display wurde noch nicht gelöscht
8
9
            if (taste_gedrueckt()==1)
10
            {
11
                clear_display();
12
                status=2;
13
            }         
14
            break;   
15
16
        case 2: // Display ist gelöscht aber Taste ist immer noch gedrückt
17
            
18
            if (taste_gedrueckt()==0)
19
            {
20
                status=1;
21
            }
22
            break;
23
    }
24
}
25
26
void loop()
27
{
28
    tastenabfrage();
29
}

Das coole dabei ist, dass man ein so gestaltetes Programm ganz simpel 
Multitaskingfähig machen kann. Als Beispiel sagen wir mal, wir haben 
einen Hardware-Timer (timerCounter) der alle 100ms hochgezählt wird. Und 
wir wollen, dass jede Sekunde abwechselnd klick-klack gemacht wird. 
Gleichzeitig soll die Taste aber noch wie gehabt funktionieren.
1
void tastenabfrage()
2
{
3
    ... // wie gehabt.
4
}
5
6
void ticken()
7
{
8
    static uint8_t status=1;
9
    static uint32t nextTime=0;
10
11
    switch (status)
12
    {
13
        case 1: // Wir warten auf die nächste Sekunde
14
15
           if (timerCounter > nextTime)
16
           {
17
               nextTime = (timerCounter/100+1)*100;
18
               klick();
19
               status=2;
20
               
21
           }
22
           break;
23
24
       case 2: // Wir warten auf die nächste Sekunde
25
26
           if (timerCounter > nextTime)
27
           {
28
               nextTime = (timerCounter/100+1)*100;
29
               klack();
30
               status=1;
31
               
32
           }
33
           break;           
34
    }
35
}
36
37
void loop()
38
{
39
    tastenabfrage();
40
    klicken();
41
}

Jetzt macht die Anwendung schon zwei Sachen quasi gleichzeitig. Sie 
fragt ständig den Zustand des Tasters ab, reagiert darauf und macht auch 
noch abwechselnd immer "klick" und "klack".

Eine kleine Erklärung zu: nextTime = (timerCounter/100+1)*100;

Indem ich zuerst durch hundert dividiere und dann wieder mit 100 
multipliziere, sorge ich für regelmäßige Intervalle von exakt 100ms.

Wenn zum Beispiel die Funktion beim Zählerstand 10500 ausgeführt werden 
müsste, aber aufgrund irgendeiner Verzögerung erst eine 100stel Sekunde 
später dran kommt, haben wir schon den Zählerstand 10501. Bei einer 
einfachen Addierung von 100 würden sich nun alle klicks und klacks 
verzögern, denn der nächste berechnete Zeitpunkt wäre 10601, dann 10701 
und so weiter. Wenn das öfter passiert, summieren sich die Verzögerungen 
auf. Die "Uhr" würde immer mehr hinterher hinken.

Durch die obige Berechnung jedoch falle ich immer wieder auf den 
richtigen Zeitpuntk zurück. Nach 10501 folgt nämlich 10600. 
Verzögerungen werden automatisch heraus gerechnet.

Anmerkung zu static:
Die Zustandsvariablen sind static, damit sie ihre Werte dauerhaft 
beibehalten. Wenn die Funktion endet und bei der nächsten Wiederholung 
von loop() erneut aufgerufen werden, haben sie immer noch ihre alten 
Werte aus dem vorherigen Durchlauf. Alternativ könnte man auch globale 
Variablen verwenden.

Hilft das?

von Toni K. (knieto)


Lesenswert?

Vielen Dank schon einmal für die vielen Antworten.

Da ich auch noch relativ neu auf dem Gebiet des Programmierens bin habe 
ich eine Frage zu der Funktion vom entprellen aus dem Link: 
https://www.mikrocontroller.net/articles/Entprellung

Das würde ich gerne so in mein Programm einpflegen. Allerdings verstehe 
ich die Funktion nicht so ganz.
Und wie ich sie dann bei mir in dem Fall aufrufen muss...

anbei wieder der code:
1
// include the LCD's library
2
#include <LiquidCrystal.h>
3
#define TASTERPORT PINC
4
#define TASTERBIT PINC1
5
6
7
8
char taster(void)
9
{
10
    static unsigned char zustand;
11
    char rw = 0;
12
 
13
    if(zustand == 0 && !(TASTERPORT & (1<<TASTERBIT)))   //Taster wird gedrueckt (steigende Flanke)
14
    {
15
        zustand = 1;
16
        rw = 1;
17
    }
18
    else if (zustand == 1 && !(TASTERPORT & (1<<TASTERBIT)))   //Taster wird gehalten
19
    {
20
         zustand = 2;
21
         rw = 0;
22
    }
23
    else if (zustand == 2 && (TASTERPORT & (1<<TASTERBIT)))   //Taster wird losgelassen (fallende Flanke)
24
    {
25
        zustand = 3;
26
        rw = 0;
27
    }
28
    else if (zustand == 3 && (TASTERPORT & (1<<TASTERBIT)))   //Taster losgelassen
29
    {
30
        zustand = 0;
31
        rw = 0;
32
    }
33
 
34
    return rw;
35
}
36
37
// initialize library with the numbers of the interface pins:
38
//               (RS, Enable, DB4, DB5, DB6, DB7)
39
LiquidCrystal lcd(7,  8,      9,   10,  11,  12);
40
int poti;
41
int seite;
42
int taster=2;
43
const int sensorMin = 0;      // sensor minimum, discovered through experiment
44
const int sensorMax = 1023;    // sensor maximum, discovered through experiment
45
46
void setup() 
47
{
48
  // Das Display initialisieren also wieviele Spalten(16) und Zeilen(2) 
49
  lcd.begin(16, 2);
50
  pinMode(zustand, INPUT);
51
  
52
}
53
54
void loop() 
55
{
56
  
57
  poti = analogRead(0);
58
  // map the sensor range to a range of four options:
59
  seite = map(poti, sensorMin, sensorMax, 0,5 );
60
  taster = digitalRead(2);
61
  digitalWrite(taster,LOW);
62
  
63
  
64
  switch (seite) 
65
  {
66
    case 0:
67
      
68
       lcd.setCursor(0, 0);
69
       lcd.print("Name eingeben!"); 
70
       lcd.setCursor(0, 1);
71
       lcd.print("OK druecken"); 
72
       taster();
73
        if(taster ==2)
74
       {
75
        lcd.clear();
76
       }
77
        
78
      break;
79
    case 1:
80
       lcd.setCursor(0, 0);
81
       lcd.print("2. Seite"); 
82
      break;
83
    case 2:
84
       lcd.setCursor(0, 0);
85
       lcd.print("3. Seite"); 
86
      break;
87
    case 3:
88
       lcd.setCursor(0, 0);
89
       lcd.print("4. Seite"); 
90
      break;
91
    case 4:
92
       lcd.setCursor(0, 0);
93
       lcd.print("5. Seite"); 
94
      break;
95
  
96
  }

von Stefan F. (Gast)


Lesenswert?

Da hast du deinen Zustandautomaten.

Die Funktion hat vier Zustände und jeder Zustand reagiert auf ein 
Ereignis. Die Funktion liefert genau einmal 1 zurück, wenn der Taster 
gerade gedrückt wurde.

Wenn der Taste gehalten wird, oder wenn er losgelassen wird, liefert sie 
eine 0 zurück.

von Toni K. (knieto)


Lesenswert?

Und auf was muss ich dann abfragen? Auf Zustand und/oder rw?

Naja eigentlich nur rw, wenn ich das richtig verstehe.
weil das der einzige wert ist, den die Funktion zurück liefert?!

von Toni K. (knieto)


Lesenswert?

Naj noch werde ich da nicht so ganz schlau raus. Bin leider noch im 
Anfangsstadium.
Ja ich habe die Methode mit dem Delay hinbekommen, aber die halte/finde 
ich nicht wirklich schön. Auch wenn es in meinem Anwendungsfall keine 
Zeitkritischen Punkte gibt.
Nur möchte ich es eben vernünftig lösen.

Daher würde ich euch nochmals bitten, mit den Code mal genauer zu 
erläutern.
1
#define TASTERPORT PINC // Das verstehe ich schon nicht.Warum muss ich #define machen? Ich möchte in meinem Fall, nur einen Taster auf meinem Breadboard auslesen.
2
#define TASTERBIT PINC1 // Das selbe hier
3
 
4
char taster(void) // warum char
5
{
6
    static unsigned char zustand; // auch diese beiden Verstehe ich nicht, weshalb ist das notwendig
7
    char rw = 0; // siehe oben
8
 
9
    if(zustand == 0 && !(TASTERPORT & (1<<TASTERBIT)))   //Taster wird gedrueckt (steigende Flanke)
10
// Was müsste ich denn eintragen, wenn es bei mir nur um einen Digitalen Input auf PIN 2 geht. Auch weiß ich nicht, was die Variable "zustand" mir sagen soll.
11
    {
12
        zustand = 1;
13
        rw = 1;
14
    }
15
    else if (zustand == 1 && !(TASTERPORT & (1<<TASTERBIT)))   //Taster wird gehalten
16
// Wenn ich das bis zu diesem Punkt verstanden haben sollte, denke ich, weiß ich was ich tun soll.
17
    {
18
         zustand = 2;
19
         rw = 0;
20
    }
21
    else if (zustand == 2 && (TASTERPORT & (1<<TASTERBIT)))   //Taster wird losgelassen (fallende Flanke)
22
    {
23
        zustand = 3;
24
        rw = 0;
25
    }
26
    else if (zustand == 3 && (TASTERPORT & (1<<TASTERBIT)))   //Taster losgelassen
27
    {
28
        zustand = 0;
29
        rw = 0;
30
    }
31
 
32
    return rw;
33
}

Vielen Dank im voraus

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Toni K. schrieb:

>     static unsigned char zustand; // auch diese beiden Verstehe ich
> nicht, weshalb ist das notwendig

zustand ist einfach nur ein Zustand, in dem sich die Tastenerkennung 
gerade befindet. Um die musst du dich nicht kümmern.
Das ist so, wie wenn ich dich frage: Was machst du gerade?
Und du antwortest: Ich gehe gerade die Treppe hinunter
Und was machst du jetzt?
Ich drücke die Türklinke hinunter
Und jetzt?
Ich öffne die Tür
usw. usw.

Du warst nacheinander in den Zuständen
* die Treppe hinuntergehend
* Türklinke niederdrückend
* Tür aufmachend
* ....

denk dir anstelle von textuellen Beschreibungen jetzt einfach Zahlen. 
Das ist genau das, was hier mit dieser Variablen gemacht wird.


>     if(zustand == 0 && !(TASTERPORT & (1<<TASTERBIT)))   //Taster wird
> gedrueckt (steigende Flanke)
> // Was müsste ich denn eintragen, wenn es bei mir nur um einen Digitalen
> Input auf PIN 2 geht.

Pin 2 von welchem Port?

Jetztz hast du natürlich ein Problem, weil dir das Arduino Framework mit 
seinem
1
  digitalRead(2);

schon zuviel wegabstrahiert hat. Aber man kann natürlich die Portpin 
Abfrage auch darauf umstellen.

Eine Tastenabfrage sieht in klassischem C für active Low Taster immer 
so:
1
  if( !(Port_an_dem_der_Taster_hängt & ( 1 << Bit_an_diesem_Port_mit_dem_Taster) )

Da hier zum Beispiel steht
1
    if(zustand == 0 && !(TASTERPORT & (1<<TASTERBIT)))

änderst du das um zu
1
    if( zustand == 0 && digitlRead(2) == LOW )

Aus
1
    else if (zustand == 2 && (TASTERPORT & (1<<TASTERBIT)))
wird
1
    else if (zustand == 2 && digitalRead(2) == HIGH )

wann immer die originale Tastenabfrage auf 0 getestet hat (erkennbar an 
der Negierung mittels !) testest du auf LOW, und wenn im Original kein ! 
vorkam, dann lautet der Vergleich auf HIGH

> // Wenn ich das bis zu diesem Punkt verstanden haben sollte, denke ich,
> weiß ich was ich tun soll.

Der Rest braucht dich alles nicht zu kümmern.
Die Erkennungsfunktion liefert dir den Tastendruck und gut ists.
1
int main()
2
{
3
.....
4
5
   if( taster() ) {
6
      mach was weil die Taste gedrückt wurde
7
   }
8
....

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

1
void setup() 
2
{
3
  // Das Display initialisieren also wieviele Spalten(16) und Zeilen(2) 
4
  lcd.begin(16, 2);
5
  pinMode(zustand, INPUT);
6
  
7
}

nein. Die Variable 'zustand' geht dich nichts an. Du willst den Portpin 
an dem dein Taster hängt auf Input schalten. Und du willst dort den 
Pullup aktivieren, wenn dein Taster active Low verdrahtet ist (was der 
Normalfall ist)
1
void setup() 
2
{
3
  // Das Display initialisieren also wieviele Spalten(16) und Zeilen(2) 
4
  lcd.begin(16, 2);
5
  pinMode( 2, INPUT_PULLUP );
6
}

1
uint8_t tmp = 0;
2
3
void loop() 
4
{
5
  if( taster() ) {
6
    lcd.setCursor(0, 0);
7
    lcd.print( tmp );
8
    tmp = 1 - tmp;
9
  }
10
}

jedesmal wenn du auf die Taste drückst, ändert die Variable ihren Wert 
von 0 auf 1 bzw. umgekehrt. Sie macht das nicht, SOLANGE du die Taste 
gedrückt hältst, sondern bei jedem Niederdrücken genau 1 mal. Das heißt: 
natürlich nur, wenn du die taster Funktion entsprechend richtig 
angepasst hast.

: Bearbeitet durch User
von Toni K. (knieto)


Lesenswert?

Vielen Dank für die Ausführliche Erklärung.
Jetzt habe ich die Funktion denke ich auch verstanden.

Allerdings würde ich gerne mal meinen Code posten, und euch fragen warum 
ich immer noch kein Ergebnis sehe.
1
// include the LCD's library
2
#include <LiquidCrystal.h>
3
4
// initialize library with the numbers of the interface pins:
5
//               (RS, Enable, DB4, DB5, DB6, DB7)
6
LiquidCrystal lcd(7,  8,      9,   10,  11,  12);
7
int poti;
8
int seite;
9
uint8_t tmp = 0;
10
const int sensorMin = 0;      // sensor minimum, discovered through experiment
11
const int sensorMax = 1023;    // sensor maximum, discovered through experiment
12
13
14
void setup() 
15
{
16
  // Das Display initialisieren also wieviele Spalten(16) und Zeilen(2) 
17
  lcd.begin(16, 2);
18
  pinMode( 2, INPUT_PULLUP ); //Meinen Taster habe ich wie folgt angeschlossen: 5V auf den Eingang des Tasters und der Ausgang geht dann auf mein PIN 2 vom Arduino UNO
19
}
20
21
22
//Funktion für die Taster Entprellung
23
  char taster(void) 
24
{
25
    static unsigned char zustand; 
26
    char rw = 0;
27
28
  if( zustand == 0 && digitalRead(2) == LOW )
29
       //Taster wird gedrueckt (steigende Flanke)
30
31
    {
32
        zustand = 1;
33
        rw = 1;
34
    }
35
    else if (zustand == 2 && digitalRead(2) == LOW )   //Taster wird gehalten
36
37
    {
38
         zustand = 2;
39
         rw = 0;
40
    }
41
    else if (zustand == 2 && digitalRead(2) == HIGH )   //Taster wird losgelassen (fallende Flanke)
42
    {
43
        zustand = 3;
44
        rw = 0;
45
    }
46
    else if (zustand == 3 && digitalRead(2) == HIGH )   //Taster losgelassen
47
    {
48
        zustand = 0;
49
        rw = 0;
50
    }
51
 
52
    return rw;
53
}
54
55
56
57
58
void loop() 
59
{
60
  
61
  poti = analogRead(0);
62
  // map the sensor range to a range of four options:
63
  seite = map(poti, sensorMin, sensorMax, 0,5 );
64
  //jetzt = digitalRead(taster);
65
  
66
67
  switch (seite) 
68
  {
69
    case 0:
70
      
71
       lcd.setCursor(0, 0);
72
       lcd.print("Name"); 
73
       lcd.setCursor(0, 1);
74
       lcd.print("OK");       
75
      break;
76
    case 1:
77
       lcd.setCursor(0, 0);
78
       lcd.print("2. Seite"); 
79
      break;
80
    case 2:
81
       lcd.setCursor(0, 0);
82
       lcd.print("3. Seite"); 
83
      break;
84
    case 3:
85
       lcd.setCursor(0, 0);
86
       lcd.print("4. Seite"); 
87
      break;
88
    case 4:
89
       lcd.setCursor(0, 0);
90
       lcd.print("5. Seite"); 
91
      break;
92
  
93
  }
94
95
     if( taster() ==1   ) 
96
     {
97
       lcd.setCursor(0, 0);
98
       lcd.print( tmp );
99
       tmp = 1 - tmp;
100
     }
101
     else
102
     {
103
       lcd.setCursor(4, 1);
104
       lcd.print("blabla");
105
     }
106
107
  
108
}

Ich bekomme natürlich jetzt angezeigt:
Name
OK  blabla


Aber beim betätigen, keine Änderung. Wie muss die IF Abfrage genau 
lauten?
Oder liegt es an der Hardware?
Ich könnte auch, vom Ausgang des tasters einen 10kOhm Widerstand auf GND 
ziehen, damit sollte der Taster ja ein definiertes Signal haben oder?
Aber auch das klappt nicht...

Kann doch nicht so schwer sein

von W.S. (Gast)


Lesenswert?

Toni K. schrieb:
> Ok, um das prellen zu vermeiden, müsste ich wahrscheinlich eine Delay
> einbauen.
> Oder einen Extra Prellfreien Taster kaufen...

Oh nein.....

Eigentlich ist das Ganze doch recht einfach:

- beim allerersten Erkennen des Gedrücktseins und Abwesenheit des 
Kennzeichens für das Entprellen mache deine Aktion

- direkt nach deiner Aktion setze ein Kennzeichen für das Entprellen

- solange dieses Kennzeichen gesetzt ist, teste, ob die Taste ungedrückt 
ist. Das sollte genügend oft passieren, um Prellen beim Loslassen zu 
unterdrücken. Wenn sich die Taste als oft genug ungedrückt gezeigt hat, 
lösche das Entprell-Kennzeichen.

Da du ohnehin mit nem Delay liebäugelst, wäre es genauso gut, am Ende 
deiner Schleife grundsätzlich darauf zu warten, daß die Taste 200x 
hintereinander ungedrückt ist.

W.S.

von Karl H. (kbuchegg)


Lesenswert?

Toni K. schrieb:

Ist zwar schon eine Weile her, aber ich war in der Zwischenzeit 
unterwegs.

> > Aber beim betätigen, keine Änderung.

> //Funktion für die Taster Entprellung
>   char taster(void)
> {
>     static unsigned char zustand;
>     char rw = 0;
>
>   if( zustand == 0 && digitalRead(2) == LOW )
>        //Taster wird gedrueckt (steigende Flanke)
>
>     {
>         zustand = 1;
>         rw = 1;
>     }
>     else if (zustand == 2 && digitalRead(2) == LOW )   //Taster wird
> gehalten

du musst schon ein wenig genau sein!
Die Abfrage hier lautete im Original nicht ob zustand gleich 2 ist, 
sondern ob zustand gleich 1 ist.

> Kann doch nicht so schwer sein

Ist es auch nicht. Aber Programmierung hat auch mit dem achten auf 
Details zu tun.

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.