PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Taster entprellen und anschliessen



orph
01.10.2006, 14:20
Hallo Leute

Ich möchte einen (später noch ein paar mehr) Taster an den PORTB <7:4> drantun, der dann bei Betätigung einen Interrupt auslöst. Dieser Interrupt sollte dann dazu führen, dass der Timer 1 zu laufen beginnt.
Ich dachte eigentlich, dass das ne ziemlich simple Sache sein sollte, doch so langsam bin ich mit meinem Latein am Ende und das Ding läuft noch immer nicht.
Als Taster verwende ich so ein Ding: http://www.distrelec.com/ishopWebFront/catalog/product.do/para/language/is/de/and/shop/is/CH/and/id/is/01/and/node/is/aeacacacadah/and/series/is/1.html
Dieser ist einerseits an 5V, und über eine Pull-Down-Widerstand von 470 Ohm mit der Masse verbunden. Ich habe das ganze auch mal mit dem Multimeter getestet und bekomme bei offenem Taster 0.1mV und bei gedrücktem Taster 5.01V. Somit ist da noch das Problem des Entprellens, doch das sollte ich eigentlich softwaremässig mit einer Warteschleife von 20ms überbrückt haben.
Doch auch so reagiert der PIC nicht auf die Betätigung des Tasters.

Das Programm sieht dann so aus:
ISR ;interupt service routine
movwf copyw
swapf STATUS, W
bcf STATUS, RP0
movwf copys

btfsc PIR1, TMR1IF
goto TMR1ISR
btfsc PORTB, 7
goto RBInt
goto ISRend


..........


RBInt
bcf INTCON, RBIF
bsf UPDRBI
goto ISRend


ISRend ;interupt end routine
swapf copys, w
movwf STATUS
swapf copyw, f
swapf copyw, w
bsf UPDLCD
retfie


...............


InitTimer
bcf STATUS, RP0
movlw B'00110101' ;prescaler: 1:8; internal clock; no synchronize; Timer1 enabled
movwf T1CON
bsf STATUS, RP0
bcf PIE1, TMR1IE
bcf STATUS, RP0
bsf INTCON, RBIE
bsf INTCON, PEIE
bsf INTCON, GIE
return

Main
btfsc UPDLCD
goto WriteLcd
call Init
call InitLCD
call InitTimer

WriteLcd
bcf UPDLCD
btfsc UPDRBI
goto TestRBI
call printzehn
call printseke
call printsekz
call printmine
call printminz
call printstde
call printstdz
movlw b'11001111'
call OutLcdControl
movlw D'10'
movwf loops
call WAIT
goto WriteLcd

TestRBI
bcf UPDRBI
movlw D'20'
movwf loops
call WAIT
btfsc PORTB, 7
goto StartTMR
goto WriteLcd

StartTMR
bsf STATUS, RP0
bsf PIE1, TMR1IE
bcf STATUS, RP0
goto WriteLcd


Die Hardware und der restliche Code sollten einwandfrei sein, da das ganze ohne den Taster ohne Probs funktionniert

Etwas lustiges ist mir auch noch aufgefallen: Wenn ich den Pull-Down Widerstand am Taster entferne, und dann nur ein Bein des Widerstands an die Masse hänge, läuft der Timer/Uhr. (Das 2. Bein hängt in der Luft) Das ist irgendwie ein bisschen komisch. ^^

Hat jemand schon mal so etwas gemacht, und könnte mir sagen, was ich ändern sollte?

mfg orph

stegr
01.10.2006, 14:36
Zwei Sachen:
- Bitte sagen welchen PIC du nimmst, damit ich mir die ISR-Register im Datenblatt mal anschaun kann
- deinen Code (zumindest im relevanten Teil) etwas kommentieren, also hinschreiben was passieren soll. Dann ist das überprüfen und nachvollziehen durch andere viel leichter.

MfG
Stefan

orph
01.10.2006, 15:02
Ok, dann also mal folgende Angaben:
- PIC 16F88



ISR ;interupt service routine
movwf copyw ;Status und W retten
swapf STATUS, W
bcf STATUS, RP0
movwf copys

btfsc PIR1, TMR1IF ;testet Timer 1 Interrupt-Flag
goto TMR1ISR ; wenn gesetzt, zur Timer-Inkrementierung gehen
btfsc PORTB, 7 ; wenn nicht gesetzt, testen ob der Taster den Interrupt ausgelöst hat (nur Reaktion, wenn aufsteigende Flanke den Interrupt ausgelöst hat)
goto RBInt ; wenn ja, zur Taster-Rutine gehen
goto ISRend ; wenn nicht, ISR beenden


..........


RBInt ;Taster-ISR
bcf INTCON, RBIF ;PORTB-Interrupt-Flag löschen
bsf UPDRBI ;Update-Flag für PORTB setzten (bedingt Reaktion im Hautprogramm)
goto ISRend ; Interrupt beenden


ISRend ;iRutine, um ISR zu beenden
swapf copys, w ;Status, und w wieder laden
movwf STATUS
swapf copyw, f
swapf copyw, w
bsf UPDLCD ;Flag setzen, damit das LCD neu beschrieben wird
retfie ;ISR-ende


...............


InitTimer ;Init des Timer, "PIE1, TMR1IE" wird noch nicht gesetzt (Timer1 interrupt enable-bit)
bcf STATUS, RP0
movlw B'00110101' ;prescaler: 1:8; internal clock; no synchronize; Timer1 enabled
movwf T1CON
bsf STATUS, RP0
bcf PIE1, TMR1IE
bcf STATUS, RP0
bsf INTCON, RBIE ;PORTB-Interrupt an
bsf INTCON, PEIE ;Periphäre-Interrupts an
bsf INTCON, GIE ;Global-Interrupt an
return

Main
btfsc UPDLCD ;Testen, ob das LCD neu beschrieben werden muss (bei Reset nicht der Fall)
goto WriteLcd
call Init ;Initialisierungen
call InitLCD ;Initialisierungen
call InitTimer ;Initialisierungen

WriteLcd ;Endlosschleife des Hauptprogramms,
bcf UPDLCD ;LCD-Update-Flag löschen
btfsc UPDRBI ;testen, ob der Taster gedrückt wurde
goto TestRBI ;zur Taster-Rutine gehen
call printzehn ;LCD schreiben
call printseke ;LCD schreiben
call printsekz ;LCD schreiben
call printmine ;LCD schreiben
call printminz ;LCD schreiben
call printstde ;LCD schreiben
call printstdz ;LCD schreiben
movlw b'11001111' ;Cursor an letzte Position
call OutLcdControl
movlw D'10' ;Warteschleife, um LCD nicht zu überlasten
movwf loops
call WAIT
goto WriteLcd ;Endlosschleife

TestRBI ;Testen, ob der Taster wirklich gedrückt wurde
bcf UPDRBI ;Flag löschen
movlw D'20' ;Warteschleife, um prellen abzuwarten
movwf loops
call WAIT
btfsc PORTB, 7 ;Ist der Taster immer noch angeschaltet?
goto StartTMR ;wenn ja, zur Timer-Start-Rutine gehen
goto WriteLcd ;wenn nein, abbruch

StartTMR ;Timer starten
bsf STATUS, RP0 ;bank 1
bsf PIE1, TMR1IE ;Timer1 Enable-Bit setzten
bcf STATUS, RP0 ;Bank 0
goto WriteLcd ;zurück zum Hauptprogramm



So, sorry, dass ich die Kommentare vergessen habe. Diese sollten weiterhelfen.

Guss orph

stegr
01.10.2006, 15:42
Die erste Sache, die mir in den Sinn kommt:
möglicherweise wird die ISR zu oft nacheinander aufgerufen...
Wäre denkbar, aber müsste sich (glaub ich zumindest) anders verhalten.

Was ich als erstes prüfen würde:
- in der ISR einen Portpin setzen und damit schaun, ob die wirklich aufgerufen wird
- im Hauptprogramm in der TestRBI-Routine einen Portpin setzen und damit schaun, ob die wirklich aufgerufen wird

Nach dem Ausprobieren bitte hier posten - dann kann man weiterverfolgen wo der Fehler liegt.

Btw. hast du die Tristate-Register (TRISB) richtig gesetzt?

MfG
Stefan

orph
01.10.2006, 19:14
moin

Durch den Test mit den LED's habe ich bemerkt, dass der PIC irgendwie gleich nach dem Reset (Timer1 ausgeschaltet, Uhr läuft nicht, Taste nicht gedrückt) zu der ISR springt.
Ich habe nun mal eine 100nF-Kondensator parallel zum Taster geschaltet, um die Software-Entprellung zu umgehen, doch nun läuft die Uhr wieder gleich nach dem Reset los. Manchmal werden auch einzelene Stellen auf dem LCD ohne Grund mit einer "0" überschrieben.

Hier mal der gesamte Code:
list p=16F88
#include <p16f88.inc>


__CONFIG _CONFIG1, _CP_OFF & _LVP_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _HS_OSC


; variables
copyw Equ 0x20
copys Equ 0x21
LcdDaten Equ 0x22
LcdStatus Equ 0x23
loops Equ 0x24
loops2 Equ 0x25
stde Equ 0x27
stdz Equ 0x2C
mine Equ 0x2D
minz Equ 0x30
seke Equ 0x31 ; einerstelle sekunden
sekz Equ 0x32 ;zehnerstelle sekunden
Flags Equ 0x40
zehn Equ 0x41


; constants
PORTD Equ PORTB

#define LcdE PORTA, 2
#define LcdRw PORTA, 0
#define LcdRs PORTA, 1
#define UPDLCD Flags, 0
#define UPDRBI Flags, 1




org 0x00
goto Main

org 0x04

ISR ;interupt service routine
movwf copyw
swapf STATUS, W
bcf STATUS, RP0
movwf copys

btfsc PIR1, TMR1IF ;Test TMR1 Interrupt-Flag
goto TMR1ISR
btfsc INTCON, RBIF ;Test PORTB Interrupt-Flag
goto RBInt
goto ISRend

TMR1ISR
bcf STATUS, RP0
bcf PIR1, TMR1IF ;clear interupt flag

nop
nop
nop
nop
nop
nop
nop
nop

movlw 0x0B
movwf TMR1H
movlw 0xDA
movwf TMR1L

incf zehn, f
movfw zehn
sublw .10
btfss STATUS, Z
goto ISRend
clrf zehn
incf seke, f ;seke +1
movfw seke
sublw .10 ;seke -10 ;result negativ => z=0
btfss STATUS, Z ;test z, if z=1 => skip next order
goto ISRend
clrf seke
incf sekz, f
movf sekz, w
sublw .6
btfss STATUS, Z
goto ISRend
clrf sekz
incf mine, f
movf mine, w
sublw .10
btfss STATUS, Z
goto ISRend
clrf mine
incf minz, f
movf minz, w
sublw .6
btfss STATUS, Z
goto ISRend
clrf minz
incf stde, f
movf stde, w
sublw .10
btfss STATUS, Z
goto ISRend
clrf stde
incf stdz, f
movf stdz, w
sublw .10
btfss STATUS, Z
goto ISRend
clrf stdz
goto ISRend

RBInt
bcf INTCON, RBIF
bsf UPDRBI
goto ISRend


ISRend ;interupt end routine
swapf copys, w
movwf STATUS
swapf copyw, f
swapf copyw, w
bsf UPDLCD
retfie

Init

bcf INTCON, GIE
bcf INTCON, PEIE
bcf INTCON, RBIE
bsf STATUS, RP0
movlw B'11110000'
movwf TRISB
movlw B'00000000'
movwf TRISA
movlw B'00000000'
movwf ANSEL
bcf STATUS, RP0
clrf stde
clrf stdz
clrf mine
clrf minz
clrf seke
clrf sekz
clrf zehn
clrf LcdDaten
clrf LcdStatus
return

InitTimer
bcf STATUS, RP0
movlw B'00110101' ;prescaler: 1:8; internal clock; no synchronize; Timer1 enabled
movwf T1CON
bsf STATUS, RP0
bcf PIE1, TMR1IE
bcf STATUS, RP0
bsf INTCON, RBIE
bsf INTCON, PEIE
bsf INTCON, GIE
return

Main
btfsc UPDLCD
goto WriteLcd
call Init
call InitLCD
call InitTimer

WriteLcd
bcf UPDLCD
btfsc UPDRBI
goto TestRBI
call printzehn
call printseke
call printsekz
call printmine
call printminz
call printstde
call printstdz
movlw b'11001111'
call OutLcdControl
movlw D'10'
movwf loops
call WAIT
goto WriteLcd

TestRBI
bcf UPDRBI
goto StartTMR

StartTMR
bsf STATUS, RP0
bsf PIE1, TMR1IE
bcf STATUS, RP0
goto WriteLcd

WAIT
wai movlw .249
movwf loops2
wai2 nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
decfsz loops2, F
goto wai2

decfsz loops, F
goto wai
return

InitLCD
movlw D'10'
movwf loops
call WAIT
movlw B'00000010'
call OutLcdControl
movlw B'00101000'
call OutLcdControl
movlw B'00001101'
call OutLcdControl
movlw B'00000001'
call OutLcdControl
movlw B'00000110'
call OutLcdControl
movlw 'C'
call OutLcdDaten
movlw 'l'
call OutLcdDaten
movlw 'o'
call OutLcdDaten
movlw 'c'
call OutLcdDaten
movlw 'k'
call OutLcdDaten
movlw ':'
call OutLcdDaten
movlw ' '
call OutLcdDaten
movlw 'r'
call OutLcdDaten
movlw 'u'
call OutLcdDaten
movlw 'n'
call OutLcdDaten
movlw B'11000011'
call OutLcdControl
movlw '0'
call OutLcdDaten
movlw '0'
call OutLcdDaten
movlw ':'
call OutLcdDaten
movlw '0'
call OutLcdDaten
movlw '0'
call OutLcdDaten
movlw ':'
call OutLcdDaten
movlw '0'
call OutLcdDaten
movlw '0'
call OutLcdDaten
movlw '.'
call OutLcdDaten
movlw '0'
call OutLcdDaten
return

LcdBusy
bsf STATUS, RP0
movlw B'11111111'
movwf TRISB
bcf STATUS, RP0
BusyLoop
bcf LcdRs
bsf LcdRw
bsf LcdE
nop
movf PORTD, w
movwf LcdStatus
bcf LcdE
nop
bsf LcdE
nop
bcf LcdE
btfsc LcdStatus, 3
goto BusyLoop
bcf LcdRw
bsf STATUS, RP0
movlw B'11110000'
movwf TRISB
bcf STATUS, RP0
return

OutLcdControl
movwf LcdDaten
call LcdBusy
swapf LcdDaten, w
andlw H'0F'
movwf PORTD
bsf LcdE
nop
bcf LcdE
movf LcdDaten, w
andlw H'0F'
movwf PORTD
bsf LcdE
nop
bcf LcdE
return

OutLcdDaten
movwf LcdDaten
call LcdBusy
swapf LcdDaten, w
andlw H'0F'
movwf PORTD
bsf LcdRs
bsf LcdE
nop
bcf LcdE
movf LcdDaten, w
andlw H'0F'
movwf PORTD
bsf LcdRs
bsf LcdE
nop
bcf LcdE
bcf LcdRs
return

printzehn
movlw b'11001100'
call OutLcdControl
movfw zehn
addlw '0'
call OutLcdDaten
return

printseke ; ausgabe von seke
movlw b'11001010'
call OutLcdControl
movfw seke
addlw '0'
call OutLcdDaten
return

printsekz
movlw b'11001001'
call OutLcdControl
movfw sekz
addlw '0'
call OutLcdDaten
return

printmine
movlw b'11000111'
call OutLcdControl
movfw mine
addlw '0'
call OutLcdDaten
return

printminz
movlw b'11000110'
call OutLcdControl
movfw minz
addlw '0'
call OutLcdDaten
return

printstde
movlw b'11000100'
call OutLcdControl
movfw stde
addlw '0'
call OutLcdDaten
return

printstdz
movlw b'11000011'
call OutLcdControl
movfw stdz
addlw '0'
call OutLcdDaten
return

end

Was kann hier nur so falsch sein?

mbg hans

stegr
02.10.2006, 13:32
Hast du mal geschaut, ob er aus der ISR auch noch rauskommt?

orph
02.10.2006, 23:40
Hallo

Den Test mit den LEDs habe ich jetzt nochmals gemacht. Ich habe 2 LEDs am PORTA. Eines sollte zu Beginn der ISR kurz blinken, und das andere beim Verlassen der ISR. Nach einem Reset beginnen jedoch beide LEDs "optisch gleichzeitig" dauerhaft zu leuchten. Respektive, sie blinken in enorm kleinen Abständen, heisst so viel wie der PIC ist in einer ISR-Endlosschleife. Ich werde dann das Problem heute nochmals angehen.

Noch eine andere Frage: Es ist schon richtig, dass beim offenen Taster 0V am PORT-Pin liegt und beim gedrückten Taster 5V, nicht umgekehrt?

gruss, Hans-Jakob

kalledom
06.10.2006, 17:48
Hallo Hans-Jakob,
wenn Du in Assembler programmierst, dann kannst Du Dir mal meine Assemblerbeispiele unter http://www.domnick-elektronik.de/picasm.htm bei 'EntprTast1' in der 'Isr_TMR2' anschauen.
Die Philosophie ist folgende:
Jede Millisekunde wird per Timer-Interrupt eine ISR aufgerufen. Die wird natürlich so kurz wie möglich gehalten und nur das erledigt, was zeitkritisch ist.
Das Abfragen eines Tasters ist so eine zeitkritische Sache. Immerhin benötigt man 30...80ms Entprellzeit. Bei mir wird das meistens so geregelt, daß bei Taster = aktiv eine Zählervariable jede Millisekunde incrementiert wird, bis sie eben 30...80 erreicht. Dann setze ich ein Flag / Bit und inkrementiere nicht weiter. Ist der Taster inaktiv, wird die Zählvariable bis auf Null dekrementiert und das Flag wieder gelöscht.
Wenn der Taster stark prellt, wird der Zähler rauf ... runter ... rauf ... zählen, bis der Taster nur noch aktiv bleibt und dann bis 30...80 hochgezählt werden kann.
Du benötigst für jeden Taster eine Zählvariable und ein Bit / Flag.
In der Haupschleife kannst Du dann hin und wieder mal nachschauen, ob ein Flag gesetzt ist und dann verzweigen.
Entgehen kann nichts, weil die Taster im Interrupt abgefragt werden. Das ist wie eine Garantie (wenn Du auch aus der ISR wieder raus gehst).