Viele if-Schleifen hintereinander

Gast #2147812
Lesenswert?

Hallo,

ich bin gerade dabei, eine Abfrage für eine Tastatur zu schreiben. Die 
Funktion read_keypad_if soll dabei die Wertigkeit der Taste zurückgeben.
Funktion funktioniert, wenn man sie nur für zwei Tasten verwendet, also:
1
int debounce_if (const volatile uint8_t *debounce_if_port, uint8_t debounce_if_pin){
2
  if ((*debounce_if_port & (1 << debounce_if_pin)) == 0){
3
    while ((*debounce_if_port & (1 << debounce_if_pin)) == 0){
4
    }
5
    return 1;
6
  }
7
  return 0;
8
}
9

10
int read_keypad_if (void){
11
  if (debounce_if (&PIND, 5) == 1){ //Taste 1
12
    return 1;
13
  }
14
  if (debounce_if (&PINC, 1) == 1){ //Taste 2
15
    return 2;
16
  }
17
  return 0;
18
}
Wenn man allerdings alle Tasten miteinbezieht, wird gar keine Taste 
erkannt:
1
int debounce_if (const volatile uint8_t *debounce_if_port, uint8_t debounce_if_pin){
2
  if ((*debounce_if_port & (1 << debounce_if_pin)) == 0){
3
    while ((*debounce_if_port & (1 << debounce_if_pin)) == 0){
4
    }
5
    return 1;
6
  }
7
  return 0;
8
}
9

10
int read_keypad_if (void){
11
  if (debounce_if (&PIND, 5) == 1){ //Taste 1
12
    return 1;
13
  }
14
  if (debounce_if (&PINC, 1) == 1){ //Taste 2
15
    return 2;
16
  }
17
  if (debounce_if (&PINC, 5) == 1){ //Taste 3
18
    return 3;
19
  }
20
  if (debounce_if (&PIND, 4) == 1){ //Taste 4
21
    return 4;
22
  }
23
  if (debounce_if (&PINC, 0) == 1){ //Taste 5
24
    return 5;
25
  }
26
  if (debounce_if (&PINC, 4) == 1){ //Taste 6
27
    return 6;
28
  }
29
  if (debounce_if (&PIND, 3) == 1){ //Taste 7
30
    return 7;
31
  }
32
  if (debounce_if (&PIND, 7) == 1){ //Taste 8
33
    return 8;
34
  }
35
  if (debounce_if (&PINC, 3) == 1){ //Taste 9
36
    return 9;
37
  }
38
  if (debounce_if (&PIND, 2) == 1){ //Taste * = 10
39
    return 10;
40
  }
41
  if (debounce_if (&PIND, 6) == 1){ //Taste 0 = 11
42
    return 11;
43
  }
44
  if (debounce_if (&PINC, 2) == 1){ //Taste # = 12
45
    return 12;
46
  }
47
  return 0;
48
}
Aufruf und Auswertung im Hauptprogramm:
1
while (1){
2
    if (read_keypad_if () == 2){
3
      PORTA &= ~(1 << 5);
4
      _delay_ms (1000);
5
      PORTA |= (1 << 5);
6
    }
7
  }
Liegt das Problem bei den vielen if-Schleifen?

Danke im Voraus.
#2147818
Lesenswert?

if-Schleife schrieb:
> http://www.if-schleife.de/

Das wollte ich auch schreiben :(
statt
>(debounce_if (&PIND, 5) == 1){
und
>if ((*debounce_if_port & (1 << debounce_if_pin)) == 0){
schreibst du besser
(debounce_if (&PIND, (1<<5)) == 1){
und
if ((*debounce_if_port & debounce_if_pin) == 0){
Das kann der Compiler schon beim Kompilieren ausrechnen und der µC muss 
nichtmehr um n schieben, wofür es keine spezielle Instruktion gibt -> 
langsam
Moderator #2147835
Lesenswert?

Einmal abgesehen davon, dass die Funktion debounce_if entgegen ihrem
Namen die Taster nicht entrpellt, fällt mir an dem Programmstück nichts
Verdächtiges auf. Die paar if-Anweisungen hintereinander bringen den
Compiler nicht zum Verzweifeln.

Bist du sicher, dass während des Tests nicht die ganze Zeit Taster 1
geschlossen oder irgendwie überbrückt ist?

Die Taster schalten doch alle gegen GND und sind jeweils mit einem
Pullup-Widerstand (im Controller oder extern) versehen?
#2147876
Lesenswert?

solange die Taste nicht gedrückt wird, blockiert doch
1
  if ((*debounce_if_port & (1 << debounce_if_pin)) == 0){
2
    while ((*debounce_if_port & (1 << debounce_if_pin)) == 0){
3
    }
4
    return 1;
5
  }

wenn man jetzt sukzessive die einzelnen Tasten abfragt, bleibt
man bei der ersten "gefangen" .. ganz unabhängig davon ob
die anderen gedrückt sind. Das ganze stellt doch eine Art
priorisierte Tastenabfrage dar. Ich verstehe ausserdem nicht
ganz warum dieselben Tasten mehrfach abgefragt werden.
#2147884
Lesenswert?

mcb schrieb:
> Ich frage dieselben PINs an unterschiedlichen PORTs ab! Siehe &PINC und
> &PIND!

ah gütiger :)
was spricht dagegen so ein Schema anzuwenden

// PORTA Schalter
#define TASTE_LICHT 0
#define TASTE_MOTOR 1
...
#define TASTE_XYZ   7

// PORTB Schalter
#define TASTE_ABC 0
...
#define TASTE_SOUNDSO 7

der Programmcode muss "reden" ;)
#2147893
Lesenswert?

Da die zweite Version von read_keypad_if sich von der ersten nur durch 
das unterscheidet, was nach der Abfrage der Taste 2 kommt, müssen beide 
Programme auf einen Druck der Taste 2 gleich reagieren.

Also funktionieren für die 2 entweder beide Versionen, oder keine.
Gast #2147925
Lesenswert?

Zur allgemeinen Schaltinformation. Alle Taster der Tastatur sind mit den 
COM-Anschluss gegen GND geschalten. Die einzelnen PINs sind dann an die 
I/Os des Controllers angeschlossen. In der Software werden dann für 
diese PINs die internen Pull-Ups aktiviert. Bei der Funktion debounce_if 
wird abgefragt, ob die Taste gedückt ist. Wenn ja, wird gewartet, bis 
die Taste losgelassen wurde und dann 1 zurückgegeben, wenn nein, wird 0 
zurückgegeben.
#2148128
Lesenswert?

soso, wenn das so ist, dann stimmt meine Argumentation von oben nicht.
Denn ich habe positive Logik angenommen .. 1=gedrückt

while (1){
    if (read_keypad_if () == 2){
      PORTA &= ~(1 << 5);
      _delay_ms (1000);
      PORTA |= (1 << 5);
    }
  }

Du erwartest nicht zufällig ein Blinken zur Bestättigung hier?
#2148267
Lesenswert?

mcb schrieb:
> Doch. Wenn die Taste 2 gedrückt wird, soll die LED kurz (1s) aufblinken.
> Das funktioniert ja auch beim 1.Fall (also nur mit den Tasten 1 und 2 in
> der Funktion). Beim 2.Fall aber nicht.

eine 0 bzw Löschen des Pines am PORT lässt die LED leuchten?
(kann gut sein, ohne schematic lässt sich das nicht ersehen)

hmm, was könnte noch als Ursache in Betracht kommen ...
eine Taste, die dauernd "an" (0) ist und die Abfragekette blockiert?
Dennoch, wenn das nicht gerade die erste Taste ist, sollten die
am Kopf der Abfragekette stehenden Tasten funkionieren.

mir ist übrigens die Übergabeform &PIND als Zeiger nicht bekannt.
ich glaube zwar, dass es so richtig ist, und volatile ist dein
Zeiger ja auch. Wenn ich gar nicht weiterwusste würde ich die Funktion
umschreiben .. ohne Zeiger und den Code einfach duplizieren, je
nach Port
1
int debounce_if (uint8_t port_id, uint8_t debounce_if_pin){
2
  switch(port_id) {
3
      case PORTD_ID:
4
        if ((PIND & (1 << debounce_if_pin)) == 0){
5
          while ((PIND & (1 << debounce_if_pin)) == 0);
6
          return 1;
7
        }
8
        return 0;
9
       case PORTC_ID: /* the same */
10
       default: return 0;
11
}
Gast #2151302
Lesenswert?

Ich hab jetz mal die Funktion wait (Nachfolger von debounce) durch 
das Aufblinken einer weiteren LED anzeigen lassen, dass die Taste 
gedrückt und wieder losgelassen wurde:
1
int wait(volatile uint8_t *wait_port, uint8_t wait_pin){
2
  if ((*wait_port & (1 << wait_pin)) == 0){
3
    while ((*wait_port & (1 << wait_pin)) == 0){
4
    }
5
    PORTA |= (1 << 4);
6
    _delay_ms (200);
7
    PORTA &= ~(1 << 4);
8
    return 1;
9
  }
10
  else return 0;
11
}
Lässt man nun beim Aufruf im Hauptprogramm (vorerst ohne Auswertung) die 
letzte Spalte der Tastatur (also Tasten 3, 6, 9, #) weg, und drückt dann 
irgendeine andere Taste, blinkt die LED auf:
1
int main (void){
2
  //DDRs definieren
3
  DDRA = 0b11111111;
4
  DDRB = 0b11111111;
5
  DDRC = 0b11000000;
6
  DDRD = 0b00000011;
7
  //PORTs definieren
8
  PORTA = 0b00000000;
9
  PORTB = 0b00000000;
10
  PORTC = 0b00111111; //interne Pull-ups für Tasten aktivieren
11
  PORTD = 0b11111100; //interne Pull-ups für Tasten aktivieren
12
  while (1){
13
    wait (&PIND, 5);
14
    wait (&PINC, 1);
15
    //wait (&PINC, 5);
16
    wait (&PIND, 4);
17
    wait (&PINC, 0);
18
    //wait (&PINC, 4);
19
    wait (&PIND, 3);
20
    wait (&PIND, 7);
21
    //wait (&PINC, 3);
22
    wait (&PIND, 2);
23
    wait (&PIND, 6);
24
    //wait (&PINC, 2);
25
  }
26
  return 0;
27
}
Ich kann mir nicht erklären, warum das nicht funktionieren sollte, die 
anderen Tasten auch abzufragen.
#2151343
Lesenswert?

Erstmal Fusseln vom Mund wisch.

- Deine CPU stoppt komplett, solange eine Taste gedrückt ist

- Beim Loslassen macht sie dann noch nen Hickup von elendig langen 200ms 
(4 Millionen CPU-Zyklen).

- Die Reaktion erfolgt erst beim Loslassen. Ergonomisch wäre aber eine 
Reaktion beim Betätigen.


Falls Deine Programmnutzer mit diesen Nachteilen leben können und ein 
laienhaftes Feeling tolerieren, meinetwegen.


Peter
Gast #2151497
Lesenswert?

So besser? Allerdings weiß ich nicht welchen Wert ich bei *_delay_ms 
(xx)* verwenden soll.
1
uint8_t debounce(const volatile uint8_t *debounce_port, uint8_t debounce_pin){
2
  if ((*debounce_port & (1 << debounce_pin)) == 0){
3
    _delay_ms (50);
4
    return 1;
5
  }
6
  return 0;
7
}
Aufruf und Auswertung auf die übliche Form:
1
if ((debounce (&PIND, 5) == 1)){ //PD5 =^ Taster 1
2
  //irgendetwas machen
3
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren