Sida 1 av 4
PIC: Hur gör man en bra avstuds-rutin? *Fixat*
Postat: 28 maj 2010, 14:21:05
av JimmyAndersson
(PIC16F688. Assembler.)
Jag har sökt på "debounce" och hittade bl.a
den här och
den här men jag ser inte koden för själva avstuds-hanteringen.
Flera har skrivit att de använder timers och liknande för att läsa av knapparna flera gånger.
Jag kan inte riktigt se koden för timer-lösningen framför mig.
Min senaste variant bygger inte på timers:
Kod: Markera allt
isr_rutin
;Knapp-interrupt.
banksel INTCON
btfsc INTCON, RAIF ;PORTA change interrupt? Om inte: Hoppa över nästa rad.
;--
debounce
btfss PORTA, 4 ;Intryckt knapp? Isåfall: Hoppa över nästa rad.
goto knappslut
incf rakna_knapp, 1 ;Öka rakna_knapp med 1.
btfss rakna_knapp, 7 ;Bit 7 satt (dvs rakna_knapp >=128) Isåfall: Hoppa över nästa rad.
goto debounce
comf PORTC, 1 ;Toggla PORTC
;--
knappslut
clrf rakna_knapp ;Rensa
banksel INTCON
bcf INTCON, RAIF ;Clerara PORTA change interrupt.
bsf INTCON, RAIE
(förbaskade tabbar som inte håller sig på plats....)
Jag är medveten om att det är dumt att ha en såndär loop i ISR-rutinen,
men så länge jag bara exprimenterar med avstudsningen så gör det ju inget.
Jag satte några lysdioder på PORTC och en knapp med pulldown till PORTA.4.
Koden fungerar, men som avstuds är den ganska dålig. Man får oftast trycka 2-3 gånger för att PORTC ska ändras.
Testade att sätta en rad NOP i avstuds-rutinen och det blev bättre, men jag är lite tveksam till att det är en bra metod...
Jag skulle behöva lite råd på vad jag ska göra annorlunda. Det vore trevligt att se en avstuds-rutin för PIC.
Språk kvittar, men gärna assembler eftersom jag har återupptagit det.
edit: Det slog mig just.. Det är inte så att det krävs en lite annan lösning just eftersom jag använder "interrupt on change" ?
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 28 maj 2010, 14:36:55
av Swech
Ett bra sätt är följande.
Sätt upp en timer som ger interrupt med 100Hz
I varje interrupt läser du av porten med knapparna.
Sätt "knapp status" = 0
100HZ
Läs av port
Är biten 1 = knapp intryckt så öka "Knapp intryckt" räknare med 1 Räkna till max 20
Är biten 0 = knapp ej intryckt så minska "Knapp intryckt" räknare med 1 Räkna till min 0
Är knapp status = 0 och "Knapp intryckt" > 15 så sätt knapp status = 1 (end)
Är knapp status = 1 och "Knapp intryckt" < 5 så sätt knapp status = 0 (end)
end
Får ju modifieras om knappen sluter mot + eller gnd samt utökas om fler knappar ansluts.
Swech
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 28 maj 2010, 14:42:26
av JimmyAndersson
Aha!
Jag hade inte haft en tanke på att man skulle räkna ner också. Nu ser jag varför.
Stort tack!

Du är bra till mycket du..

Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 28 maj 2010, 16:39:33
av BJ
Jag brukar nollställa räknaren varje gång som
det kommer en nolla.
Om man gör så här...
100 Hz
Läs av porten.
Är biten 1 = knapp intryckt, så öka "Knapp intryckt"-räknare
med 1. Räkna till högst 20.
Är biten 0 = knapp inte intryckt, så nollställ "Knapp intryckt".
Är "Knapp intryckt" 20 så sätt knapp status = 1. (end)
end
Då får huvudprogrammet nollställa varje ny
knapptryckning.
Blir det nån annan skillnad? Den kommer att bli
lite långsammare kanske?
Tillägg:
Nu tänkte jag på återfjädrande knappar.
Det kanske inte var det som Jimmy och Swech
tänkte på.
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 28 maj 2010, 17:35:22
av sneaky
Jag brukar göra som du BJ, nollar räknaren varje gång statusen för pinnen inte är det jag söker.
Har även använt en variant av metoden som beskrivs på sidan 21 i följande PDF. Ett smart sätt att läsa av många olika inputs samtidigt. Hela PDFen är för övrigt ganska intressant läsning:
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 28 maj 2010, 18:32:04
av Oskar
Smarta tips! Wiki kanske?
Har för mig att jag gjorde så att pinnen måste ha samma tillstånd x antal pollningar i rad innan det räknas som en giltig nivå. Var länge sedan jag behövde göra någon avstuds.
/Oskar
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 28 maj 2010, 19:03:22
av Icecap
Jag använder också en timer på 100Hz men har sedan länge skippat att räkna upp/ner osv.
Jag läser porten 1(!) gg per interrupt. Ska detta värde användas fler gångar i interrupten sparas det i en variabel.
Har även en variabel med den förra avläsning i, dessa två värden AND'er jag och resultatet är aktiva knapptryckningar.
Fungerar klickfritt i en del olika applikationer.
Alltså:
1: Läs porten.
2: Spara värdet till "Current"
3: Result = Current & Previous;
4: Previous = Current;
5: Utföra en n-key-rollover
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 28 maj 2010, 20:50:00
av Swech
Allt hänger på hur hårt man vill filtrera.
Har man ett system där man skall t.ex. utföra något så länge som knappen är nedtryckt så kan det hicka till om
man nollställer sin avstudsning direkt då en 0a uppträder.
Men i de flesta fall funkar det bra ändå, Likaså Icecaps princip funkar också bra.
Något som däremot inbjuder till problem är att använda capture interrupt. Alltså trig då nivå ändrar sig.
Dessa interrupt är avsedda för att detektera klockpulser och data, inte mekaniska brytare eftersom
dessa studsar. I värsta fall kan processorn bli tokig då den interruptas med såpass korta intervall som uppstår
vid just kontaktstuds.
Swech
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 29 maj 2010, 10:50:33
av anlamotte
Kan väl bidra med min metod

Jag använder en timer intruppt på ca 100hz.
Till detta 3 variabler som håller koll på status
Kod: Markera allt
Sw0 aktiveras när knappen trycks ner
Sw1 aktiveras när knappen släpps
Sw2 aktiveras när knappen hålls in en stund (för att snabbt stega i menyer m.m)
Varje knapp använder 1 bit i varje variabel så knapp1 använder Sw0.0, Sw1.0 och Sw2.0
Funktionen blir att knapparna aktiveras när de släpps istället för när de trycks in.
Kod: Markera allt
Timer_ISR:
If Pinb.6 = 1 And Sw0.1 = 1 Then ' knappen har släppts efter den var intryckt!
If Sw2.1 = 0 Then Sw1.1 = 1 ' knapp aktiverad
Sw0.1 = 0 ' nollställ
Sw2.1 = 0 ' nollställ
Sw_tmr1 = 0 ' nollställ
End If
If Pinb.6 = 0 Then ' knapp intryckt
Sw0.1 = 1 ' spara knappstatus
Incr Sw_tmr1 ' knapp timer
If Sw_tmr1 > 120 Then Sw2.1 = 1 ' knappen har hålts intryckt
End If
Return
I huvudprogrammet:
Kod: Markera allt
If Sw1.0 = 1 Or Sw2.0 = 1 then ' knapp1 automatisk repetition
....gör vad som ska göras
....
Sw1.0 = 0
End if
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 31 maj 2010, 00:08:01
av v-g
Kör med ismannens metod och den fungerar super. Har aldrig fått studsproblem.
Det gäller också att man har pullup/down-motstånd så att inte knappen svävar i ena läget. Samt att man använder en hyffsad brytare då också såklart.
Man kan även sätta en kondensator för att hindra för snabba omslag.
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 2 juni 2010, 14:25:15
av JimmyAndersson
Här var många bra tips. Håller med om att de borde skrivas in i wikin.

Nu fick jag även grepp om Icecaps' metod. Ska testa den också, för den verkar väldigt enkel och smidig.
Tackar!

Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 2 juni 2010, 16:29:42
av sugarman64
Fattade inte den (Icecap's metod alltså). Någon som skulle vilja ge sig på att försöka förklara den lite närmare?
Ska snart skapa lite menyer och koppla in lite knappar till ett projekt, så denna tråd kom väldigt lägligt

Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 2 juni 2010, 16:36:19
av sodjan
> Fattade inte den (Icecap's metod alltså).
Om du får "knapp tryckt" två gånger i rad så *är* "knapp tryckt". Ungefär...
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 3 juni 2010, 23:56:07
av sugarman64
Var väl ungefär det jag trodde. Verkade lite för enkelt bara.
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 4 juni 2010, 06:27:22
av baron3d
Jaha.. Här har vi en annan.
Kod: Markera allt
char inkey;
---
---
// Anropas lämpligen i 100Hz interrupt.
// lägger värde i "inkey"
void ReadKeys(void) {
static char a0 a1, a2;
a0=a1;
a1=a2;
a2=(~PORTA)&15; //Maska bort oanvända bitar
if(a2==a1 && a2>a0) {
inkey|=a2;
}
}
Efter man läst "inkey" nollställer man variabeln.
Alltså: