Ich versuche, 3 verschiedene Tasten von einem Watchdog-Timeout-Interrupt auf einem ATtiny13 abzufragen.
Mein Code funktioniert perfekt für einzelne Schaltflächen, aber ich kann anscheinend nicht alle 3 in einer Schleife abfragen. Alle Schaltflächen sind mit einer beliebigen Nummer zur Identifizierung in 0x01, 0x02 und 0x04 verknüpft.
Dieser Code fragt beispielsweise die Schaltfläche 0x02 ab und funktioniert einwandfrei:
ISR (WDT_vect){
if (debounce(0x02)==1){
PORTB ^= _BV(PB1);//flip led 1
}}
Wenn ich jedoch versuche, alle 3 in einer Schleife abzufragen, scheint keine Erkennung zu erfolgen. In diesem Beispiel schalte ich einfach dieselbe LED für alle 3 Tasten um:
ISR (WDT_vect){
for (int d=0x01;d<0x04;d<<1){
if (debounce(d)==1){
PORTB ^= _BV(PB1);//flip led 1
}}}
Gestapelte if-else funktionieren auch nicht:
ISR (WDT_vect){
if (debounce(0x02)==1){
PORTB ^= _BV(PB1);//flip led 1
} else if (debounce(0x04)==1){
PORTB ^= _BV(PB3);//flip led 2
}
}
Der Rest des relevanten Codes zur Verdeutlichung gekürzt:
/***
* curbtn: one of 0x01,0x02,0x04, matches mute, vol+,vol-
* returns 1 if the button is considered pressed
*/
uint8_t debounce(uint8_t curbtn){
static uint8_t button_history = 0;
uint8_t pressed = 0;
button_history = button_history << 1;
button_history |= read_btn(curbtn);
if ((button_history & 0b11000111) == 0b00000111) {
pressed = 1;
button_history = 0b11111111;
}
return pressed;
}
/**
* sets up ports to read a specific button
* returns 1 if the selected button is pressed
*/
uint8_t read_btn(uint8_t curbtn){
uint8_t ret=0x00;
if (curbtn==0x01){
DDRB &=~_BV(PB2);//PB2 en entree
PORTB |=_BV(PB2);//pull-up actif
ret= ( (PINB & _BV(PB2)) == 0 );
} else if (curbtn==0x02){
DDRB |=_BV(PB2);//PB2 en sortie
PORTB &=~_BV(PB2);//PB2 a 0
DDRB &=~_BV(PB0);//PB0 en entree
PORTB |=_BV(PB0);//pull up sur PB0
ret= ( (PINB & _BV(PB0)) == 0 );
} else if (curbtn==0x04){
DDRB |=_BV(PB0);//PB0 en sortie
PORTB &=~_BV(PB0);//PB0 a 0
DDRB &=~_BV(PB4);//PB4 en entree
PORTB |=_BV(PB4);//pull up sur PB4
ret= ((PINB & (1<<PB4)) == 0);//lecture de PB0
}
return ret;
}
Ich würde gerne wissen, ob ich in die richtige Richtung gehe und wie mein Abfragecode korrigiert werden sollte.
Große Fortschritte gemacht, es gab 2 Probleme.
Wie von Martin und kkraambo vorgeschlagen, gab es das Problem, den Status aller 3 Schaltflächen korrekt zu verfolgen. Der von mir gepostete Code behielt eine statische Verlaufsvariable. Jetzt enthält der Hauptcode 3 verschiedene Verlaufsvariablen.
uint8_t mute_history=0;
uint8_t volp_history=0;
uint8_t volm_history=0;
uint8_t read_btn(uint8_t curbtn){
uint8_t ret=0x00;
if (curbtn==0x01){
DDRB &=~_BV(PB2);//PB2 en entree
PORTB |=_BV(PB2);//pull-up actif
nop();nop();nop();nop();
ret= ( (PINB & _BV(PB2)) == 0 );
} else if (curbtn==0x02){
DDRB |=_BV(PB2);//PB2 en sortie
PORTB &=~_BV(PB2);//PB2 a 0
DDRB &=~_BV(PB0);//PB0 en entree
PORTB |=_BV(PB0);//pull up sur PB0
nop();nop();nop();nop();
ret= ( (PINB & _BV(PB0)) == 0 );
} else if (curbtn==0x04){
DDRB |=_BV(PB0);//PB0 en sortie
PORTB &=~_BV(PB0);//PB0 a 0
DDRB &=~_BV(PB4);//PB4 en entree
PORTB |=_BV(PB4);//pull up sur PB4
nop();nop();nop();nop();
ret= ((PINB & (1<<PB4)) == 0);//lecture de PB0
}
return ret;
}
uint8_t debounce(uint8_t *button_history,uint8_t curbtn){
uint8_t pressed = 0;
*button_history = *button_history << 1;
*button_history |= read_btn(curbtn);
if ((*button_history & 0b11000111) == 0b00000111) {
pressed=1;
*button_history = 0b11111111;
}
return pressed;
}
ISR (WDT_vect){
if (debounce(&volp_history,0x02)==1){
PORTB ^= _BV(PB3);//flip led 2
}
if (debounce(&mute_history,0x01)==1){
PORTB &= ~_BV(PB1);//turn off
PORTB &= ~_BV(PB3);//turn off
}
if (debounce(&volm_history,0x04)==1){
PORTB ^= _BV(PB1);//flip led 2
}
}
Das zweite Problem war ein Timing-Problem, das mir von Benutzer Tom Carpenter in diesem Thread vorgeschlagen wurde . Seine Kommentare waren:
@Polyphil versuchen Sie, einige Nop-Anweisungen hinzuzufügen. Sie können Folgendes verwenden: #define nop() __asm__ __volatile__ ("nop \n\t"), und dann in Ihrem Code nop();nop();nop(); kurz bevor Sie die return-Anweisung machen.
@Polyphil Die Eingänge am ATTiny haben aufgrund einer Synchronisiererkette eine Latenzzeit von zwei Taktzyklen, sodass es nach dem Ändern des Pullup-Werts mindestens 2-3 Taktzyklen dauert, bis er sich im PIN-Register widerspiegelt. Das Hinzufügen eines nop veranlasst den Prozessor, einen Taktzyklus zu warten.
daher die nops().
Die Schaltung verhält sich im Moment wie erwartet.
Wie oft rufen Sie beim WDT an? Warum wählen Sie nicht einen WDT-Prescaller, damit Sie überhaupt nicht entprellen müssen? Wenn Sie die Schaltflächen nur alle (sagen wir) 50-100 ms überprüfen, sollten sie sich selbst entprellen, und Ihr Code kann so einfach sein, dass Sie einfach jede der Schaltflächen der Reihe nach nacheinander überprüfen und auf den Zustand reagieren.
Großer Josch
Großer Josch
Polyphil
krambo
debounce()
der Schaltflächenstatus von einem Aufruf zum nächsten? Wenn ja, kann es mehrere verschiedene Schaltflächen verfolgen oder nur eine einzelne Schaltfläche?Polyphil
button_history_xx
für jede Schaltfläche richtig zu implementieren?Martin
Lundin
JimmyB
Polyphil
Lundin
JimmyB