Programmingsmetod för att enbart känna av en input 1 gång

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Programmingsmetod för att enbart känna av en input 1 gång

Inlägg av Magnus_K »

Om jag har en knapp till en µC, som i koden är avstudsad (debounce:ad), hur löser man det vanligtvis/enklast programmeringsmässigt för att enbart polla(?) knappen 1 gång?
Hemskt gärna i C-kod men misstänker det ser lika ut för de flesta språk.

Vi försöker så här, tänk er nu att knappen är avstudsad:

Om jag lägger in det här i loopen:

Kod: Markera allt

if(button == 1) {
       Var1++;
}
Så kommer väl Var1 öka med 1 för varje loop som knappen hålls intryckt?

Låt då säga att jag gör så här:

Kod: Markera allt

if(button && !buttonActivated) { 
        Var1++;
        buttonActivated = 1;
}
else if(!button) {
        buttonActivated = 0;
}
Så kommer väl Var1 endast öka en gång per knapptryck?
Frågan är då, hur hade ni gjort för att få uppnådd funktion? Dvs att Var1 endast ökar en gång per knapptryck, oavsett hur länge den hålls intryckt.
Användarvisningsbild
Icecap
Inlägg: 26147
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Programmingsmetod för att enbart känna av en input 1 gån

Inlägg av Icecap »

Jag brukar ju har fler knappar på en port, vi kallar den KEY_PORT.

static _UBYTE Previous;
_UBYTE Keys, X;
X = KEY_PORT;
if(X & ~Previous) Keys |= X & ~Previous;
Previous = X;

Nu innehåller Keys ett bitmönster som uppträder 1 gång vid aktivering och sedan inte mer.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Programmingsmetod för att enbart känna av en input 1 gån

Inlägg av Magnus_K »

Hmm, njaa. Tror det är raden if(X & ~Previous) Keys |= X & ~Previous; Previous = X; som uträttar det jag önskar. Ge mig en stund så ska jag försöka förstå vad det står.
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43178
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Programmingsmetod för att enbart känna av en input 1 gån

Inlägg av sodjan »

Du har helt rätt i att det måste finnas *något* som håller reda på knappens
senaste status, annars går det ju inte att se om/när den släpps. Det kan så
klart sedan lösas på många olika sett, det du har är väl helt OK.

> ...för att enbart polla(?) knappen 1 gång?

Lite begreppsförvirring här tror jag. Polla måste du ju göra hela tiden,
däremot så ska kanske inte rutinen som körs då knappen trycks ska
köras mer än en gång (om man inte har repetering, så klart).

När det gäller Icecap's kod så har jag ingen speciell kommentar kring den,
förutom att jag tycker att kod som man behöver "en stund" för att
förstå är dålig kod...
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Programmingsmetod för att enbart känna av en input 1 gån

Inlägg av Magnus_K »

Håller med sodjan, pollning blev fel här, gick nog lite snabbt när jag skrev. Låter det stå kvar då jag fick en rättning :wink:

Ok, så är det jag skrev ganska begripligt för en utomstående. Bra.
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 45291
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: Programmingsmetod för att enbart känna av en input 1 gån

Inlägg av TomasL »

Om du sätter knappen på en portpinne som är interrupt-kapabel, så behöver du inte polla den.
Nerre
Inlägg: 26705
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Programmingsmetod för att enbart känna av en input 1 gån

Inlägg av Nerre »

Generellt när man läser av knappar brukar man väl försöka jobba "händelsebaserat". D.v.s. man måste hålla reda på hur knappen var senast och när knappen ändras så anropas en funktion för KnappNer() respektive KnappUpp().

Om vi försöker med lite pseudokod:

Kod: Markera allt

IF oldKnappStatus = Nere 
  IF KnappStatus = Uppe THEN
    KnappUpp()
    oldKnappStatus=KnappStatus
IF oldKnappStatus = Uppe 
  IF KnappStatus = Nere THEN
    KnappNer()
    oldKnappStatus=KnappStatus
Nu går det såklart att skriva detta lite "snitsigare", men det visar principen. Den där kryptiska kodraden gör ju ungefär detta, men den använder bitmasker och det faktum att 0 är false.

Uttrycket (X & ~Previous) blir 0 om X och Previous är lika, men icke-0 om de är olika.

Uttrycket Keys |= X & ~Previous; sätter de bitar i Keys där X och Previous skiljer sig från varandra. Den indikerar alltså vilka bitar som har ändrat sig.

Funktionerna KnappUpp() och KnappNer() behöver ju inte vara funktioner utan kan vara inline-kod (i ditt exempel Var1++;).

Och det gäller ju i princip oavsett om man pollar eller använder interrupt (om man nu inte kan få olika interrupt beroende på stigande eller fallande flank).
Användarvisningsbild
Icecap
Inlägg: 26147
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Programmingsmetod för att enbart känna av en input 1 gån

Inlägg av Icecap »

Generellt är det en god idé att använda interrupt för knappar - men det kräver en stabil debounce i hårdvara!

Själv läser jag knapp-porten medelst en timer-interrupt, två avläsningar som är identiska = giltig knapptryckning. Ingen annan debounce i mjukvaran behövs varför det går fort.

En tid mellan avläsningarna på 5ms är bra. Återigen använder jag en static variabel för att hålla reda på status.

Sedan, om två avläsningar är lika, gör jag denna maskning av knappar och evt. långt tryck kontra kort tryck osv.

Det viktiga är att varje avläsning i timer-ISR'n bara sker en enda gång! Resultatet sparas i en mellanvariabel, på det vis blir det inte trubbel om status ändrar sig mellan två avläsningar på samma interrupt.

Med detta sätt uppnår jag:
* Debounce ved avläsning med stabilt mellanrum. Ingen Delay() eller skit för detta alltså.
* En knapptryckning sker bara en gång.
* Med lite ändring kan man skilja mellan kort och lång tryckning.
* Med lite ändring kan man göra autorepeat på utvalda knappar.

Slutresultatet sparas i en variabel som ett bitmönster där en specifik bit motsvarar en specifik knapp. Detta kan sedan avkännas i main-loop och man kan välja att en reaktion på en knapp kan nollställa motsvarande bit i variabeln när den är behandlat eller att alla knappar behandlas och nollställs efter att allt är behandlat.

Jag har även vid vissa tillfällen skapat en buffer där jag lägger in knapptryckningar som väntar på att behandlas, de ligger då i sekvens och hämtas en efter en - men detta sätt är oftast överkurs.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Programmingsmetod för att enbart känna av en input 1 gån

Inlägg av Magnus_K »

Jag får tack för era förklaringar och eventuella tillvägagångssätt. Väldigt snällt med alla förklaringar.
Får se vart det slutar men nu har jag lite att kolla tillbaka på. Tackar!
Skriv svar