Sida 2 av 4
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 8 juni 2010, 15:53:50
av tessier
Scott Dattalo kan man lita på
Mycket intressant lösning då man kan köra åtta knappar parallellt med bara tre minnesregister.
http://www.dattalo.com/technical/softwa ... rtcnt.html
// Stefan
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 12:41:22
av JimmyAndersson
Dattalo-länken innehöll lite för många sidor djuplodande läsning för min smak, om jag ska vara ärlig, och det ska man ju.

edit: Det var pdf-filen på förra sidan jag tänkte på egentligen, men raden ovan stämmer iofs ändå. Jobbigt att bara döpa variabler till två bokstäver..
Jag har testat bl.a Swech's och Icecap's metoder. Tydligen har jag en väldigt rosslig knapp,
för vilken av rutinerna jag än använder så blir det ändå studsar när jag ska "toggla" någon funktion eller lysdiod.
Knappen är helt ny, av
den här modellen kopplad till PORTA,4 med pulldown-motstånd.
Jag har testat med lite olika kondingar (47pF - 100nF) över knappen, utan någon större skillnad.
Såhär ser den nuvarande rutinen ut som körs med 100Hz (interrupt från en timer, verifierad frekvens med oscilloskop.) :
Kod: Markera allt
knapp_test
;Knapp-koll
bcf knapp_pos, 0 ;Nolla knappens avlästa läge.
btfsc PORTA, 4 ;Knappen är intryckt? Om inte: Hoppa över nästa rad.
bsf knapp_pos, 0 ;Knappen avläst som intryckt en gång..
;Spara current
movf knapp_pos, 0 ;knapp_pos till W.
movwf knapp_current ;W till knapp_current.
;Resultat
movf knapp_previous, 0 ;knapp_previous till W.
andwf knapp_current, 0 ;knapp_current AND W (knapp_previous). Resultatet till W.
movwf knapp_resultat ;W (resultatet) till knapp_resultat.
;Spara nästa previous
movf knapp_current, 0 ;knapp_current till W.
movwf knapp_previous ;W (current) till knapp_previous.
;Knapp_toggle
btfsc knapp_current, 0 ;Är knapp_current = 1 ? Om inte: Hoppa över nästa rad.
comf knapp_onoff, 1 ;Toggla knapp_onoff.
;LED_visning
btfsc knapp_onoff, 0 ;Är knapp_onoff = 1 ? Om inte: Hoppa över nästa rad.
movlw h'00' ;Tänd lysdioderna. (Inverterat, därav 00.)
btfss knapp_onoff, 0 ;Är knapp_onoff = 0 ? Om inte: Hoppa över nästa rad.
movlw h'ff' ;Släck lysdioderna. (Inverterat.)
movwf PORTC ;Lysdioderna..
return
"knapp_koll" och de två sista 'delarna' kan kanske göras snyggare om man vill.
I MPLAB_SIM fungerar det fint, men där finns ju inte heller någon knappstuds.
Förslag på ändringar i mjukvara eller hårdvara?
(Har provat andra knappar av samma sort. Tyvärr har jag ingen annan modell som får plats där den ska sitta.)
edit: Glömde berätta att elektroniken sitter på ett kretskort. Knappen är ansluten med 8cm långa tvinnade flerkardeliga sladdar.
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 13:31:55
av electronix
Testa med att lägga ett 100 ohm motstånd i serie direkt vid portpinnen och kondingarna mot jord efter motståndet, men det kanske du redan har försökt med.
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 13:57:08
av JimmyAndersson
Jag har testat med 220 ohm och diverse kondingar utan skillnad, men jag kanske inte har hittat rätt konding.
Det är lite olika bud på storleken i de andra trådarna som handlar som kontaktavstuds..
I dessa trådar nämns även att det räcker med avstuds i mjukvaran.
Men jag verkar inte lyckas med både avstuds i mjukvara *och* hårdvara...
Vissa dagar går verkligen allt som smort...

Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 14:00:17
av tecno
Dags att hiva in en Schmitt-trigger?
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 14:04:36
av Icecap
Jimmy: din rutin är lite konstig. Ena stunden använder du en bit till att hålla reda på huruvida knappen är aktiverat och sparar detta i en byte som en bit - varefter du använder hela byten som indikering av tryckt eller inte. Är du SÄKER på att hela byten är nollad?
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 14:39:24
av JimmyAndersson
Jag har kört runt några gånger med simulatorn och hela byten blir nollad som den ska innan loopen där koden bara kör runt och väntar på timer-interrupt.
Att jag först använder en bit och sedan går över till bytes är för att jag (än så läge)
inte har hittat något smidigt sätt att flytta en bit från ett register till ett annat (via W).
I början av rutinen nollar jag biten och ändrar den (till 1) ifall PORTA,4 är hög,
men det kändes omständigt att använda den principen i hela rutinen.
Egentligen skulle jag iochförsig kunna använda bytes hela vägen (h'00' och h'FF').
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 15:02:22
av sodjan
> att jag (än så läge)
> inte har hittat något smidigt sätt att flytta en bit från ett register till ett annat (via W)
Om det är samma position, ett par AND/OR borde fixa det.
Om det är olika position, en BTFSS/BTFSC och lite mer logik fixar det.
I fall två (som i och för sig funegrar i båda fallen) behövs inte W.
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 16:34:36
av JimmyAndersson
Jag har testat med AND för att "filtrera bort" allt utom första biten i varje byte, men ändå ingen framgång tyvärr.
Hur pass bra ska en avstuds-rutin av den här typen fungera egentligen?
"Bra" är ju relativt, men som exempel:
1) Hänger det på att man har en guldpläterad brytare i toppskick?
2) Eller ska det fungera med en sådan som jag länkade till tidigare?
3) Ska det rent av fungera om man är lite darrig och sätter två sladdar mot varandra?
Jag vet faktiskt inte riktigt hur/var jag ska gå vidare nu.
RC-filter, mjukvaru-avstuds.. ska jag verkligen behöva slänga in en schmitt-trigger också?
I andra mjukvaruavstuds-trådar har jag fått intrycket av att det ska räcka med avstudshantering i mjukvaran.
Hela min kod som den ser ut nu, ifall någon vill testa:
Kod: Markera allt
;****************************************************
list p=PIC16F688
include "p16f688.inc"
;****************************************************
;
; PIC16F688. Intern oscillator på 8MHz.
;
;
; Lysdioder 1 - 6 : RC0 - RC5.
; Knapp (JP1) : RA4. (pin 3).
;
;
;****************************************************
__CONFIG _INTRC_OSC_NOCLKOUT & _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF
errorlevel -302
;****************************************************
; Definiera diverse namn...
; #define KNAPP PORTA, 4
;****************************************************
;knapp_vars UDATA_SHR
;variabel RES 1
; det blir mer här senare..
;****************************************************
Boot CODE h'0000'
goto start
;****************************************************
Int_vect CODE h'0004'
goto isr_rutin
;****************************************************
; MACRO
; kommer senare...
;****************************************************
Main CODE
Start
;Generell setup
banksel OPTION_REG
bsf OPTION_REG, NOT_RAPU ;PORT A pull-ups disabled
bsf OPTION_REG, INTEDG ;Interrupt on rising edge of RA2/INT --
bcf OPTION_REG, T0CS ;TMR0 internal clock --
bcf OPTION_REG, PSA ;Prescaler är tilldelad Timer0-modulen --
bsf OPTION_REG, PS2 ;Prescaler 1:128
bsf OPTION_REG, PS1 ;Prescaler 1:128
bcf OPTION_REG, PS0 ;Prescaler 1:128
banksel WDTCON
bcf WDTCON, SWDTEN ;WDT turned off
; Interrupt
banksel INTCON
bsf INTCON, GIE ;Global interrupt enable bit <--
bsf INTCON, PEIE ;Enable unmasked peripheral interrupts <--
bsf INTCON, T0IE ;Enable the Timer0 interrupt <--
bcf INTCON, INTE ;Disable the RA2/INT external interrupt
bcf INTCON, RAIE ;Disable the PORTA change interrupt <--
bcf INTCON, T0IF ;Timer0 did not overflow <--
bcf INTCON, INTF ;RA2/INT external interrupt did not occur
bcf INTCON, RAIF ;None of the PORTA-pins have changed state <--
banksel IOCA
movlw b'00000000' ;Inga interrupt on change på PORTA. <--
movwf IOCA
banksel PIE1
bcf PIE1, EEIE ;Disable the EE write complete interrupt
bcf PIE1, ADIE ;Disable the ADC-interrupt <-- DISABLED NU
bcf PIE1, RCIE ;Disable the EUSART receive interrupt
bcf PIE1, C2IE ;Disable the comparator C2 interrupt
bcf PIE1, C1IE ;Disable the comparator C1 interrupt
bcf PIE1, OSFIE ;Disable the oscillator fail interrupt
bcf PIE1, TXIE ;Disable the EUSART transmit interrupt
bcf PIE1, TMR1IE ;Disable the Timer1 overflow interrupt <<<<
banksel PIR1
clrf PIR1 ;Cleara alla interrupt
bcf PIR1, ADIF ;AD interrupt clear <--
; Klocka
banksel OSCCON
bsf OSCCON, IRCF2 ;8MHz
bsf OSCCON, IRCF1 ;8MHz
bsf OSCCON, IRCF0 ;8MHz
bcf OSCCON, SCS ;Fosc = systemklockan
; I/O
banksel TRISA
; movlw b'00010100' ;Allt till utgångar, bortsett från knappen (R4) och poten (R2).
movlw b'00010000' ;Allt till utgångar, bortsett från knappen (R4).
movwf TRISA
banksel TRISC
clrf TRISC ;Alla till utgångar, för lysdioderna.
banksel PORTA
clrf PORTA ;Tomt
banksel PORTC
movlw h'FF' ;Tomt (OBS: Inverterat för lysdioderna). <<<<<<<<<
movwf PORTC
banksel WPUA
clrf WPUA ;Inga pull-ups
; Timers
banksel TMR0
movlw d'100' ;TMR0 start. <<<<<<<<<<<<<<<<
movwf TMR0
banksel T1CON
bcf T1CON, TMR1ON ;Timer1 avstängd
; Comparator
banksel CMCON0
bsf CMCON0, CM2 ;Comparators avstängda
bsf CMCON0, CM1 ;Comparators avstängda
bsf CMCON0, CM0 ;Comparators avstängda
banksel VRCON
bcf VRCON, VREN ;CVref powered down
; ADC
banksel ANSEL
; movlw b'00000100' ;AN2 (pin 11) analog. Resten digitala
movlw b'00000000' ;Digitala ingångar.
movwf ANSEL
banksel ADCON0
bsf ADCON0, ADFM ;Högerjusterad AD
bcf ADCON0, VCFG ;Vdd som referens
bcf ADCON0, CHS2 ;Channel: AN2 (pin 11)
bsf ADCON0, CHS1 ;Channel: AN2 (pin 11)
bcf ADCON0, CHS0 ;Channel: AN2 (pin 11)
bcf ADCON0, ADON ;ADC disabled <-- DISABLED!!
bcf ADCON0, GO_DONE ;AD-conversion NOT in progress <--
banksel ADCON1
bcf ADCON1, ADCS2 ;AD Conversion clock: Fosc/32 = 250kHz
bsf ADCON1, ADCS1 ;AD Conversion clock: Fosc/32 = 250kHz
bcf ADCON1, ADCS0 ;AD Conversion clock: Fosc/32 = 250kHz
; USART
banksel TXSTA
bcf TXSTA, TXEN ;EUSART transmit disabled
clrf RCSTA ;EUSART port disabled
bcf BAUDCTL,ABDEN ;Auto-baud detect disabled
;Rensa. (För att lättare se i MPLAB SIM.)
clrf rakna_knapp
clrf knapp_onoff
;****************************************************
;****************************************************
;****************************************************
;Main-loopen
loop
goto loop ;Om och om igen...
;****************************************************
;****************************************************
;****************************************************
; Sub-rutiner här under
;****************************************************
knapp_vars UDATA_SHR
knapp_pos RES 1
knapp_onoff RES 1 ;Knappen. (Togglas vid nedtryck.)
knapp_current RES 1
knapp_resultat RES 1
knapp_previous RES 1
sub_rutiner CODE
;****************************************************
knapp_test
;Knapp-koll
bcf knapp_pos, 0 ;Nolla knappens avlästa läge.
btfsc PORTA, 4 ;Knappen är intryckt? Om inte: Hoppa över nästa rad.
bsf knapp_pos, 0 ;Knappen avläst som intryckt en gång..
;Spara current
movf knapp_pos, 0 ;knapp_pos till W.
andlw b'00000001' ;TEST för att försäkra mig om att bara första biten används. <<
movwf knapp_current ;W till knapp_current.
;Resultat
movf knapp_previous, 0 ;knapp_previous till W.
andlw b'00000001' ;TEST för att försäkra mig om att bara första biten används. <<
andwf knapp_current, 0 ;knapp_current AND W (knapp_previous). Resultatet till W.
andlw b'00000001' ;TEST för att försäkra mig om att bara första biten används. <<
movwf knapp_resultat ;W (resultatet) till knapp_resultat.
;Spara nästa previous
movf knapp_current, 0 ;knapp_current till W.
andlw b'00000001' ;TEST för att försäkra mig om att bara första biten används. <<
movwf knapp_previous ;W (current) till knapp_previous.
;Knapp_toggle
btfss knapp_current, 0 ;Är knapp_pos = 1 ? Isåfall: Hoppa över nästa rad.
goto LED_visning
comf knapp_onoff, 0 ;Toggla knapp_onoff. TEST: Resultatet till W.
andlw b'00000001' ;TEST för att försäkra mig om att bara första biten används. <<
movwf knapp_onoff ;TEST tillbaka med resultatet till knapp_onoff.
LED_visning
btfsc knapp_onoff, 0 ;Är knapp_onoff = 1 ? Om inte: Hoppa över nästa rad.
movlw h'00' ;Tänd lysdioderna. (Inverterat, därav 00.)
btfss knapp_onoff, 0 ;Är knapp_onoff = 0 ? Om inte: Hoppa över nästa rad.
movlw h'ff' ;Släck lysdioderna. (Inverterat.)
movwf PORTC ;Lysdioderna..
return
;****************************************************
;****************************************************
; Interrupt
isr_vars UDATA_SHR
pot_lo RES 1
pot_hi RES 1
isr_rutin CODE
isr_rutin
;Timer0 Interrupt. (TMR0 start: 100. Frekvens: 100.16 Hz. Period: 0.009984 sek.)
banksel INTCON
btfss INTCON, T0IF ;TMR0 interrupt? Isåfall: Hoppa över nästa rad.
goto timer0_slut ;Hoppa till slutet.
call knapp_test ;Hoppa till rutinen som läser av knappen.
bcf INTCON, T0IF ;Cleara TMR0 interrupt-flaggan.
bsf INTCON, T0IE ;Redo för nytt interrupt.
movlw d'100' ;TMR0 start. <<<<<<<<<<<<<
movwf TMR0
timer0_slut
retfie
;****************************************************
end
(Dessa tabbar när man klistrar in kod här....

Varför blir det bra på vissa rader men åt skogen på andra?)
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 16:53:52
av sneaky
Bara en tanke. Du nämner att du verifierat frekvensen av interrupten med ett oscilloskop men har du kikat på hur knappen beter sig också? Där kan du ju lätt se hur länge det fladdrar osv.
Nu är inte jag den mest erfarne på forumet (dagens underdrift) men enligt allt jag läst och själv testat så ska det räcka fint med mjukvara.
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 17:10:45
av JimmyAndersson
Bra fråga, det hade jag glömt att skriva.
Nu har jag inget oscilloskop med minne i närheten, men vad jag kan se på det analoga så är det i genomsnitt 5ms "skräp"
precis när man trycker ner knappen. Nu brukar jag inte mäta knappar, men av vad jag sett från oscilloskop-skärmdumpar
(på sajter som handlar om detta) så är min knapps "skräp" ganska normalt.
Jag lyckades gräva fram en påse knappar som är guldpläterade både på insidan och utsidan. Kan jämföra med dem senare.

Tyvärr är de inte momentana (dvs de behåller läget även efter man släppt knappen), men de borde fungera för att mäta med.
Om någon gör jämförande mätningar: Ta mina 5ms med en nypa salt. Det är svårt att hinna se på ett analogt oscilloskop.
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 17:31:46
av bos
Jag har inte lusläst tråden, men finns det någon anledning till att du inte implementerar avstudsaren i hårdvara? En kondensator och ett motstånd är allt som behövs:
Kod: Markera allt
+V ----[SW]--+--+---- [µC]
| |
[R][C]
| |
+--+
GND
10k och 1µF är lagom värden. Detta ger följande resultat (grön kurva, den blå är samma typ av avstudsare men aktiv låg istället):

Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 17:38:55
av Icecap
Det finns lite nackdelar med hårdvaran.
Frånsett fler komponenter och därmed högre pris och fler felkällor är den koppling du anger en störning i sig.
Med en 1µF kondensator kommer ett tryck på knappen att ladda upp kondensatorn mycket snabbt, detta kräver en hel del ström och ge ett dyk i VDD = störning. Ett motstånd (kanske 100 ohm) i serie med knappen kan sänka den ström men är ytterligare en kostnad och felkälla.
Så det finns goda anledningar att INTE ha avstutsning i hårdvara faktisk.
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 17:44:50
av bos
Visst finns det nackdelar, men det finns ju nackdelar med mjukvarulösning också. Ökad kodkomplexitet är en. Allt handlar ju om en avvägning mellan för- och nackdelar för en viss lösning. Min undran rörde sig om det fanns en anledning till att just en mjukvarulösning eftersträvades.
Re: PIC: Hur gör man en bra avstuds-rutin?
Postat: 11 juni 2010, 18:18:52
av Swech
Kan du inte testa att köra med 10hz för att verifiera att din avstudsning funkar
i mjukvaran?
Swech