Forum: Mikrocontroller und Digitale Elektronik Was genau passt hier nicht beim Auslesen der Pins?


von Pumba (Gast)


Lesenswert?

Bekomme dauerhaft von der Funktion den Wert 1 zurückgeliefert bei allen 
Tastern.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
#define BUTTON_MODE    PINB0
5
#define BUTTON_START  PINB1
6
#define BUTTON_STOP    PINB2
7
8
int8_t button_read(volatile uint8_t *port, uint8_t bit, uint8_t *last_state);
9
10
int main(void)
11
{
12
  DDRB &= ~((1<<BUTTON_MODE) | (1<<BUTTON_START) | (1<<BUTTON_STOP));
13
  PORTB |= (1<<BUTTON_MODE) | (1<<BUTTON_START) | (1<<BUTTON_STOP);
14
15
  while(1)
16
  {    
17
    static uint8_t last_state_start;
18
    if(button_read(&PINB, BUTTON_START, &last_state_start))
19
    {
20
      uart_puts("START\r\n");
21
    }
22
    
23
    static uint8_t last_state_stop;
24
    if(button_read(&PINB, BUTTON_STOP, &last_state_stop))
25
    {
26
      uart_puts("STOP\r\n");
27
    }
28
    
29
    static uint8_t mode;
30
    static uint8_t last_state_mode;
31
    if(button_read(&PINB, BUTTON_MODE, &last_state_mode))
32
    {
33
      if(++mode >= 10) mode = 0;
34
      uart_puts("MODE>");
35
      uart_putc(mode+'0');
36
      uart_puts("\r\n");
37
    }
38
39
  }
40
}
41
42
int8_t button_read(volatile uint8_t *port, uint8_t bit, uint8_t *last_state)
43
{
44
  uint8_t return_value;
45
  
46
  // Taster wird gedrueckt (steigende Flanke)
47
  if(*last_state == 0 && !(*port & (1<<bit)))
48
  {
49
    *last_state = 1;
50
    return_value = 1;
51
    _delay_ms(50);
52
  }
53
  
54
  // Taster wird gehalten
55
  else if(*last_state == 1 && !(*port & (1<<bit)))
56
  {
57
    *last_state = 2;
58
    return_value = 0;
59
  }
60
  
61
  // Taster wird losgelassen (fallende Flanke)
62
  else if(*last_state == 2 && (*port & (1<<bit)))
63
  {
64
    *last_state = 3;
65
    return_value = 0;
66
  }
67
  
68
  // Taster losgelassen
69
  else if(*last_state == 3 && (*port & (1<<bit)))
70
  {
71
    *last_state = 0;
72
    return_value = 0;
73
  }
74
  
75
  return return_value;
76
}

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


Lesenswert?

Die AVR unterscheiden strikt zwischen Programmspeicher, RAM Speicher und 
Ein/Ausgabe Adressraum. Du wirst mit deinem Konstrukt also auf die 
Adresse des RAM zugreifen, statt auf den I/O Adressraum und die RAM 
Zelle auslesen, die die gleiche Adresse hat (aber im RAM Adressraum) wie 
der Port B, weil der Kompiler bei Pointern davon ausgeht, das sie in den 
RAM zeigen.

von Stefan F. (Gast)


Lesenswert?

Ich hatte das auch mal versucht (Port und Bit Nummer als Parameter 
übergeben) und scheiterte an der gleichen Stelle. Deswegen interessiert 
mich auch, wie man das elegant lösen kann.

Mein Programm enthält aktuelle eine große switch Anweisung, wo für jeden 
möglichen Port der gleiche Code wiederholt wird. Funktioniert, aber 
schön ist es nicht.

von Axel S. (a-za-z0-9)


Lesenswert?

Das Lesen der Pins ist schon richtig so (siehe auch 
http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_port_pass).

Was nicht korrekt ist, ist die Funktion button_read() selber. Zum einen 
wird die Variable return_value nicht initialisiert. Es ist also durchaus 
möglich, daß die Funktion einen undefinierten Wert zurückliefert.

Viel schlimmer ist aber der logische Fehler. Anscheinend soll das eine 
Statemachine sein. Die funktioniert aber nur dann so wie erwartet, wenn 
der Taster entprellt ist und wenn die Funktion häufig genug aufgerufen 
wird. Sonst kann es passieren, daß die Statemachine in einem Zustand 
hängen bleibt.

Nehmen wir z.B. an, beim letzten Aufruf wäre die Statemachine in den 
Zustand last_state == 1 (Tastendruck erkannt) übergegangen. Nun ist der 
Taster zwischenzeitlich aber schon wieder losgelassen worden (bzw. hat 
geprellt). Beim nächsten Aufruf der Funktion ist das Portbit also 1. 
Dann wird keiner der if/else Zweige genommen. Denn von Zustand 1 ist 
nur der eine Weg nach Zustand 2 vorgesehen, wenn der Taster gedrückt 
bleibt (das Portbit beim Test gerade 0 ist). Und genau an dieser Stelle 
wird dann auch ein undefinierter Wert von return_value zurückgegeben.

Um das sauber zu machen, muß die Statemachine in jedem Zustand jeden 
möglichen Input bewerten. Man muß also auch die "unmöglichen" Übergänge 
berücksichtigen. Weil die eben doch möglich sind.

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.