PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Tastenzähler mit PIC16F628A



mario2104
26.01.2011, 20:26
Hallo

ich habe ein großes Problem, ich weiß nicht wie ich anfangen soll...
Alsoo ich habe schon ein Programm geschrieben das wunderbar funktioniert.
Sobald ich auf eine Tastatur drücke, führt der PIC einen Befehl aus und am Display erscheint eine meldung.

nur jz. würde ich gerne mitzählen wie oft diese Taste Gedrückt wurde und anschließend am Display ausgeben? geht das?

bitte um hilfe
danke

RoboHolIC
26.01.2011, 23:30
Hast du schon einen Timer-Interrupt laufen, der auch noch während der Zeitdauer minimal kurzer Tastendrücke mehrfach aufgerufen wird? Z.B. alle 1..10 Millisekunden? Wenn ja, prima; wenn nein, müsstest du eine soche Zeitbasis in deinem Programm einrichten.
In der Interruptroutine (ISR) wird dann die Portleitung der Taste bei jedem Durchlauf einmal gelesen. Ist sie gerade aktiv, wird eine Variable key_count um eins erhöht, weiter nichts.
Wenn die Portleitung bei einem späteren ISR-Durchlauf nicht mehr aktiv ist, wird der Tastvorgang als abgeschlossen betrachtet und es wird ausgewertet:
- ON-Zeit kleiner z.B. 20ms ist nur Kontaktprellen und wird ignoriert, key_count wird gelöscht.
- ON-Zeit 20..250ms wird als gültiger Tastendruck interpretiert, es wird eine Variable à la key_event mit einem Wert ungleich Null beschrieben und der Zähler key_count wieder gelöscht.
key_event ist ein Signal an das pollende (Haupt-)Programm, daß ein gültiger Tastendruck erfolgte.
Das Hauptprogramm prüft key_event <> 0, inkrementiert ggf. einen eigenen Ereigniszähler und löscht seinerseits das von der ISR gelieferte und nun verwertete Tastenevent key_event.

mario2104
26.01.2011, 23:38
dankeschön für die schnelle antwort

das muss ich mir einmal durchdenken, bin ganz neu in diesem Sektor :D

weist du vl. ein beispiel prog. wo ich mir das einmal anschauen könnte=?
wie das genau funktioniert mit dem Timer und so?

mfg mario

theborg
27.01.2011, 10:08
@RoboH...

Das dürfte nicht genau genug sein wen du den Taster auf PB0 hast kannst damit nen Interupt auslösen

mario2104
27.01.2011, 13:22
hmm..... :D
kann mir irgendwer einen Ansatzt für dieses Problem schicken??

einen Programmcode in Assembler were interessant bzw. nur tipps.

dankeee

RoboHolIC
27.01.2011, 17:15
@theborg
1..10ms Zeitauflösung, Finger-betätigte Taste, nicht genau genug ?
Na, ich weiß nicht.
Ein Taster an 'ner Interruptleitung muß auch wieder per HW oder Code entprellt werden. Und wenn grad' eine ISR aktiv ist, dauert's ja auch wieder, bis der Taster erkannt wird.
Letztlich wird die PB0-Variante genauso gut funktionieren wie mein Vorschlag.

@mario2104
Ich werd zusehen, daß ich dir einen Extrakt eines meiner ASM-Programme liefern kann, wo ich so was realisiert habe.

mario2104
27.01.2011, 17:45
@RoboHolIC
dankee ur leiwand von dir :D :D

RoboHolIC
28.01.2011, 00:22
Sooo, da bin ich wieder.
Ich habe -wie angekündigt- einen Extrakt meines aktuellen Projekts (das einfach nicht fertig werden will) angefertigt. Da sind alle Konfigurationen, Variablen, meine Tastenauswertung in voller Länge und kleine Anregungen für die Verwendung drin, die dich interessieren könnten.
Ich hab auch noch weitere Kommentare eingefügt, die dir zum Verständnis helfen sollen.




list p=16f876a ; list directive to define processor !!!!!!! ÄNDERN !!!!!!!
#include <P16F876A.INC> ; processor specific variable definitions !!!!!!! ÄNDERN !!!!!!!

__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC !!!!!!! ODER HALT ANDERS !!!!!!!!

;************************************************* ****************************
; '__CONFIG' directive is used to embed configuration data within .asm file.
; The labels following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.
;************************************************* ****************************


; STATUS bit definitions

#define _C STATUS,0 ; für die Kurzschreibung von Bitprüfungen: "BTFSS _C"
#define _Z STATUS,2 ;




; Hardware signals definitions

#define AUX5 sta_ra,4 ; Taste


;***** KONSTANTEN
;Tastenauswertung
K_NONE EQU 0x00 ; nix
K_FUZZI EQU 0x01 ; unklar
K_CLICK EQU 0x02 ; kurz
K_PRESS EQU 0x03 ; lang



;***********
flax EQU 0x27 ; diverse Flags
sta_ra EQU 0x63 ; Binärstatus von Port A
iscr EQU 0x6B ; scratch in der ISR
mscr EQU 0x6C ; scratch in der main()
key_cnt EQU 0x6E ; Anz. ISR-Zyklen "Taste ununterbrochen LOW" (=aktiv)
key_evt EQU 0x6F ; erkanntes Tastenevent


;***** GLOBALE VARIABLEN 0x70..0x7F
x70 EQU 0x70 ;
x71 EQU 0x71 ;
x72 EQU 0x72 ;
x73 EQU 0x73 ;
x74 EQU 0x74 ;
x75 EQU 0x75 ;
x76 EQU 0x76 ;
x77 EQU 0x77 ;
x78 EQU 0x78 ;
x79 EQU 0x79 ;
dlycnt EQU 0x7A ; Delay-Restzyklen zu je 1ms
ticker EQU 0x7B ; virtuelle Unruh; immerzu in Bewegung
temp_w EQU 0x7C ; variable used for context saving
temp_status EQU 0x7D ; variable used for context saving
temp_pclath EQU 0x7E ; variable used for context saving
temp_fsr EQU 0x7F ; variable used for context saving








;************************************************* *********************
;************************************************* *********************
ORG 0x0000 ; Begin of 2k-Code Page #0 (1st)
; processor reset vector
;************************************************* *********************
;************************************************* *********************

nop ; nop required for icd
goto MAIN ; go to beginning of program
nop
nop















;************************************************* *********************
;************************************************* *********************
ORG 0x0004 ; interrupt vector location ***************** hierher wird bei ALLEN Interrupt Requests verzweigt ****************
;************************************************* *********************
;************************************************* *********************


;********** Kontext sichern **********
movwf temp_w ; save off current W register contents
movf STATUS,w ; move status register into W register
movwf temp_status ; save off contents of STATUS register
movf PCLATH,w ; move pclath register into w register
movwf temp_pclath ; save off contents of PCLATH register
movf FSR,w ;
movwf temp_fsr ;

; Lead-In
;bcf INTCON,GIE ; globales IRQ-Disable ;;; das geschieht schon automatisch bei der IRQ response
bcf STATUS,RP0 ;
bcf STATUS,RP1 ; Bank 0 als default
bcf PCLATH,4 ;
bcf PCLATH,3 ; Code Page #0

; Identifizierung der Quelle
btfsc INTCON,T0IF ; der Timer0 ?
goto ISR_TMR0 ;
btfsc PIR2,CCP2IF ; das CCP2-Modul ? Dummy zur Strukturdarstellung
goto ISR_CCP2 ;
btfsc INTCON,INTF ; externer INT ? Dummy zur Strukturdarstellung
goto ISR_INT ;

goto ISR_RESTORE ; !!! Fangleine !!! (gegen ungewollt aktive IRQs)



; ab hier die Service-Routinen für die verschiedenen IRQ-Quellen

;********** ISR für den Timer0-Interrupt
ISR_TMR0
; IRQ-flag löschen und preload
bcf INTCON,T0IF ; Timer0-IRQ
movlw d'8' ; 256-(250-2!) = 8 für 1000,0 Hz @ 16,00MHz !!! DIESEN WERT AUCH BEIM INIT IM HAUPTPROGRAMM SETZEN !!!
movwf TMR0 ; preload = verkürzter Anlauf zum nächsten Überlauf-IRQ

; Eingänge lesen
movf PORTA,w ;
movwf sta_ra ; Port A in Abbildvariable einlesen




ISR_TMR0_1 ; *********** ein paar kleine Anregungen **************
; Millisekunden-Eieruhr
movf dlycnt,f ; Z-Flag generieren
btfss STATUS,Z ;
decf dlycnt,f ; dekr., wenn nicht null (Z=0)


; Millisekunden-Ticker (= virtuelle Unruh)
incf ticker,f ;



; ***************** und hier wird es interessant für dich *******************

ISR_KEY
; Tastenauswertung
; Tastenstatus elektrisch
btfsc sta_ra,4 ; LOW-aktiv !
goto ISR_KEY_1 ; NICHT betätigt, also auswerten
incf key_cnt,f ; betätigt, also hochzählen
movlw d'255' ; Endanschlag
subwf key_cnt,w ;
btfsc STATUS,Z ; auf Gleichheit prüfen
decf key_cnt,f ; Zählerstand deckeln
goto ISR_KEY_TAIL ; und Schluss
ISR_KEY_1
; Ereignis-Erkennung
movlw d'20' ; Max-Wert für Prellen
subwf key_cnt,w ;
btfss STATUS,C ; überschritten ?
goto ISR_KEY_END ; NEIN, dann Schluss
movlw K_CLICK ; JA!
movwf key_evt ; reicht für ein CLICK

movlw d'150' ; Max-Wert für CLICK
subwf key_cnt,w ;
btfss STATUS,C ; überschritten ?
goto ISR_KEY_END ; NEIN, dann Schluss
movlw K_FUZZI ; JA!
movwf key_evt ; reicht für ein FUZZI

movlw d'250' ; Max-Wert für FUZZI
subwf key_cnt,w ;
btfss STATUS,C ; überschritten ?
goto ISR_KEY_END ; NEIN, dann Schluss
movlw K_PRESS ; JA!
movwf key_evt ; reicht für ein PRESS
ISR_KEY_END
clrf key_cnt ; Event oder Prellen detektiert, daher löschen
ISR_KEY_TAIL


goto ISR_RESTORE ; Ende der Serviceroutine für den Timer0-Interrupt


;********** ISR für den CCP2-Interrupt ********** das hier nur noch beispielhaft; es gehört zur anfänglichen Verzweigung
ISR_CCP2
; das wäre der CCP2-Interrupt - derzeit ohne Funktion
bcf PIR2,CCP2IF ; auslösendes Flag löschen
; !!!!!!!!! hier dazwischen gehört dein eigener Code !!!!!!!!!!!!!
goto ISR_RESTORE ;



;********** ISR für den externen INT-Eingang ********** das hier nur noch beispielhaft; es gehört zur anfänglichen Verzweigung
ISR_INT
; das wäre der externe INT-Eingang - derzeit ohne Funktion
bcf INTCON,INTF ; auslösendes Flag löschen
; !!!!!!!!! hier dazwischen gehört dein eigener Code !!!!!!!!!!!!!
goto ISR_RESTORE ;



ISR_RESTORE
; Kontext wiederherstellen
movf temp_fsr,w ;
movwf FSR ;
movf temp_pclath,w ; retrieve copy of PCLATH register
movwf PCLATH ; restore pre-isr PCLATH register contents
movf temp_status,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf temp_w,f ; Kniff, um W zu laden, ohne den Status zu verändern !
swapf temp_w,w ; restore pre-isr W register contents

retfie ; return from interrupt (impliziert ein "bsf INTCON,GIE")




















;************************************************* *********************
MAIN ; Das Hauptprogramm
;************************************************* *********************


clrf INTCON ; alle Interruptquellen sperren, alle IRQs verwerfen



; Timer0 konfigurieren
bsf STATUS,RP0 ; Bank 1
clrwdt ; WDT-Register und implizit Prescaler löschen, das gehört sich so!
movlw b'10000011' ; int sys clk, 1:16, prescale assg. to TMR0
movwf OPTION_REG ;
bcf STATUS,RP0 ; Bank 0
movlw d'8' ; Presetwert vgl. Timer0-ISR
movwf TMR0 ;






; Startzustände herstellen
movlw d'0' ;
movwf ticker ;
movwf flax ; acht Flag-Bits

movlw K_NONE ;
movwf key_evt ;

bsf STATUS,RP0 ; Bank 1
clrf PIE1 ;
clrf PIE2 ;
bcf STATUS,RP0 ; Bank 0
clrf PIR1 ;
clrf PIR2 ;
clrf INTCON ; alle Quellen und IRQs disablen/rücksetzen



; Interrupts enablen bzw. in Gang setzen
bsf INTCON,T0IE ; Timer 0 enable
bsf INTCON,PEIE ; Gruppe der Peripherals
bsf INTCON,GIE ; globales Enable










; !!!!!!!!! hier dazwischen gehört dei eigener Code !!!!!!!!!!!!!


; und hier endlich die Hauptprogrammschleife
LOOOP

; auf Event K_PRESS prüfen
movlw K_PRESS ;
subwf key_evt,w ;
btfsc STATUS,Z ;
incf tastenzaehler ;


pagesel LOOOP ;
goto LOOOP ;






;************************************************* *********************
; wartet stur, bis die ISR den Zähler dlycnt bis Null heruntergezählt hat
******* Das ist das Gegenstück zur dlycnf-Manipulation in der ISR ****************
******* auch wieder nur als Anregung zu verstehen ****************
P0_IDLE
movwf dlycnt ; Delayzeit wird im W-Register geliefert
P0_IDLE_1
movf dlycnt,f ; zero flag generieren
btfss STATUS,Z ; bei Z=1 ausbrechen
goto P0_IDLE_1 ;

return ;
;************************************************* *********************






;************************************************* *********************
END ; directive 'end of program'
;************************************************* *********************



Hoffentlich habe ich dich nicht unterschätzt; langweilen will ich dich damit nicht. Ich nehme an, daß du mit MPLAB arbeitest, dann wirst du vieles schon kennen. Wenn du konkrete Fragen hast zu meinen Konstrukten - immer raus damit.
Das minimale Grundgerüst für Interrupts findest du noch übersichtlicher in der MPLAB-Installation, ich glaube unter dem Namen p16f628atemp.asm. Aber da bist du vermutlich auch gestartet.

Jetzt bist du dran, das gründlich durchzuarbeiten. Ist doch ne ganze Menge Code übrig geblieben. Allerdings hab ich mit flinker Schere geschnitten, da ist manche Franse dran, die noch weg müsste, vielleicht hab ich auch mal ins gute geschnitten - ich hab nicht getestet, ob's assemblierbar ist!