| CODE |
| ;********************************************************************** ; ; Capture Keyboard and replay it on a keypad ; First release, Version 0.2.0, Dec 22, 2001 ; Copyright 2001 by Rick Huang ; ; Revision ; V 0.1.0 First release ; V 0.2.0 Update to send repeated keystrokes when the ; buttons are pressed for a long time ; ; - You can use this code for watever you wish, but I take no ; responsability for any injury, damage to property. ; - Connection infomration will be posted when I have time.... ; ;********************************************************************** include <p16f84.inc> __config _RC_OSC & _WDT_OFF KeyData EQU 0ch SpecKey EQU 0dh Counter EQU 0eh TimeOut EQU 0fh PadData EQU 10h PadDatb EQU 11h OldPada EQU 12h OldPadb EQU 13h ReCount EQU 14h TempLo0 EQU 15h TempHi0 EQU 16h SpeKeyL EQU 17h SpeKeyH EQU 18h Parrity EQU 19h DelayCT EQU 1ah KeyBuff EQU 1bh XferBuf EQU 1ch ResendT EQU 1dh Temp1 EQU 1eh goto start ORG 4 ;waiting for <0004> ; ;interrupt vector ;***************************************************************** ;** Interrupt Int: btfss INTCON, T0IE;If timer0 interrupt is not enabled goto IntProgram;Interrupt is generated by programing cycle bsf PORTA, 2;Read Cycle start here goto dummy1 ;Send pulse on data latch dummy1: ;Wait cycle bcf PORTA, 2 movlw 10h ;initialize 16 cycles movwf ReCount ReadCycle: CLRC btfsc PORTA, 4;Read data first SETC rrf PadData, F rrf PadDatb, F;Save data in a 16bit memory bcf PORTA, 3 goto dummy2 ;Send clock --\__/-- low going dummy2: ;Wait... bsf PORTA, 3 decfsz ReCount, F goto ReadCycle;Loop ;*******************************Check for the difference in data movfw PadDatb xorwf OldPadb, W movwf TempLo0 ;Save the change in TempLo0 movfw PadData xorwf OldPada, W movwf TempHi0 movfw PadDatb movwf OldPadb ;Now the new data become the old data movfw PadData movwf OldPada movlw b'00001111' andwf TempHi0, W iorwf TempLo0, W btfsc STATUS, Z goto NoChange;Nothing changed, resend keyboard pulse clrf ResendT InitSend: ;Need to use the PadDatab register movlw 0ch ; movwf ReCount ;Initial loop for 12bit SendCycle: rrf TempHi0, F rrf TempLo0, F BNC NextCycle ;Change of data located at? rrf PadData, F rrf PadDatb, F BC KeyUp ;1 = key up, 0 = key down ;KeyDown movfw ReCount call LookUp BNC NormalDown;Carry - Special Key ;Special Key movwf KeyBuff movlw 0e0h call SendData call FourDelay movfw KeyBuff NormalDown: call SendData call FourDelay call FourDelay decfsz ReCount, F goto SendCycle goto ExitInt KeyUp: ;KeyUp movfw ReCount call LookUp movwf KeyBuff BNC NormalUp ;Special Key movlw 0e0h call SendData call FourDelay NormalUp: movlw 0f0h call SendData ;Add proper delay call FourDelay movfw KeyBuff call SendData call FourDelay call FourDelay decfsz ReCount, F goto SendCycle goto ExitInt NextCycle: ;NoChange, take next item in the PadDatb rrf PadData, F rrf PadDatb, F decfsz ReCount, F goto SendCycle;End of loop, exit ;******************************* No change in keyboard data, detect resend condition NoChange: movlw b'11110000' iorwf PadData, W andwf PadDatb, W movwf Temp1 comf Temp1, W btfsc STATUS, Z goto ExitInt incf ResendT, F movlw d'30' ;Half a sec per resend xorwf ResendT, W btfss STATUS, Z goto ExitInt ;Clear data buffer movlw 0ffh xorwf OldPadb, W movwf TempLo0 ;Save the change in TempLo0 movlw 0ffh xorwf OldPada, W movwf TempHi0 movlw d'25' movwf ResendT goto InitSend ;******************************* Exit ExitInt: ;return from interrupt bcf INTCON, 2 retfie ;******************************* Send keyboard style data SendData: movwf KeyData movlw b'00001000' movwf PORTB ;disable keyboard data path CLRC call SendBit ;Start bit movlw 08h movwf Counter clrf Parrity SendLoop: rrf KeyData, F call SendBit decfsz Counter, F goto SendLoop ;Parrity incf Parrity, F rrf Parrity, F call SendBit ;Stop SETC nop nop nop call SendBit ;Add delay goto dummyb1 dummyb1: goto dummyb2 dummyb2: bsf STATUS, RP0 bsf PORTB, 0 bcf STATUS, RP0 bcf PORTB, 3 bsf PORTB, 2;Enable keyboard data path return ;******************************* SendBit SendBit: bsf STATUS, RP0 bsf PORTB, 0;Clock High ;Add delay here SKPC ;This is a reverse! goto SendZero sendOne: incf Parrity, F bsf PORTB, 1;Data High goto BitEnd SendZero: bcf PORTB, 1;Data Low goto BitEnd BitEnd: goto delaySB1;delay for High cycle, 10dummy delaySB1: goto delaySB2 delaySB2: goto delaySB3 delaySB3: goto delaySB4 delaySB4: goto delaySB5 delaySB5: bcf PORTB, 0;Clock Low goto delaySB11;delay for low cycle, 8dummy delaySB11: goto delaySB12 delaySB12: goto delaySB13 delaySB13: goto delaySB14 delaySB14: bcf STATUS, RP0 ;NOTE high - process send data, in the subroutine ; low - fetch data, outside the subroutine return ;******************************* 4ms delay FourDelay: clrf Counter FourLoop: goto FourDummy0 FourDummy0: incfsz Counter, F goto FourLoop return ;******************************* Lookup Table of Keys LookUp: movwf KeyData movlw 88h ;Indirect address of EECON1 movwf FSR movlw 0ch ;Get Special Key Status movwf EEADR bsf INDF, RD;Indirect point to EECON1 movfw EEDATA movwf SpeKeyH incf EEADR, F;Get Lower Special Key bsf INDF, RD;Indirect point to EECON1 movfw EEDATA movwf SpeKeyL movfw KeyData movwf EEADR decf EEADR, F bsf INDF, RD;Indirect point to EECON1 movfw EEDATA LookLoop: rrf SpeKeyH, F rrf SpeKeyL, F decfsz KeyData, F goto LookLoop return ;***************************************************************** ;** Initialization start: ;Setup for interrupt on Timer 0 clrwdt bsf STATUS, RP0;Set prescaler for timer0 32:1 movlw b'10000100' movwf TMR0 bcf STATUS, RP0;First bank movlw b'00100000';NOTE GIE is not enabled at this point movwf INTCON ;Setup for input/output movlw b'00001000';Data Clock normaly HIGH movwf PORTA bsf STATUS, RP0;Second bank Note: bit0 - Clock I/O movlw b'10000011';Input on bit 7 bit1 - DATA I/O movwf TRISB ;Set port-B for output movlw b'00010000' movwf TRISA ;Set port-A for input / bit 4 bcf STATUS, RP0 ;***************************************************************** ;** Main program loop ;call Capture movlw b'00000100' movwf PORTB btfsc PORTB, 7 goto Program bsf INTCON, GIE;Enable the interrupt at this point Loop: goto Loop ;***************************************************************** ;** Interrupt generated for program IntProgram: movwf KeyBuff movfw PORTB movwf XferBuf bcf INTCON, INTF movfw KeyBuff retfie ;***************************************************************** ;** Program: ;Setup Interrupt-on-change on PortB<0> movlw b'00010000' movwf INTCON ;Note, GIE is not on! bsf PORTB, 4 ProgramLoop: bcf PORTB, 5 call FullCapture ;Display a successful capture bcf PORTB, 4 btfsc SpecKey, 7 bsf PORTB, 5 call ReadPad ;Read key# on the pad call WriteData;Write into EEprom ;Display a successful Read bsf PORTB, 4 goto ProgramLoop ;***************************************************************** ;** Read Pad ReadPad: movlw 0bh movwf PadData bsf PORTA, 2;Read Cycle start here goto Pdummy1 ;Send pulse on data latch Pdummy1: ;Wait cycle bcf PORTA, 2 movlw 0ch ;initialize 16 cycles movwf ReCount PReadCycle: btfss PORTA, 4;Read data first return decf PadData, F bcf PORTA, 3 goto Pdummy2 ;Send clock --\__/-- low going Pdummy2: ;Wait... bsf PORTA, 3 decfsz ReCount, F goto PReadCycle;Loop goto ReadPad ;All key empty! ;***************************************************************** ;** Full Capture FullCapture: call Capture TSTF SpecKey SKPNZ return ;Regular key. movlw 0e0h ;Special key? if not, Retry xorwf SpecKey, W BNZ FullCapture movlw 0f0h ;Key Up follows? If so, Retry xorwf KeyBuff, W BZ FullCapture return ;***************************************************************** ;** Capture Keyboard data Capture: bsf INTCON, GIE;Enable interrupt bsf XferBuf, 0;Enable interrupt for next cycle clrf SpecKey movlw 09h movwf Counter KeyLoop: call WaitCycle SKPNC ;Timeout goto Capture ;Resample CLRC btfsc XferBuf, 1 SETC rrf SpecKey, F bsf XferBuf, 0;Enable interrupt for next cycle decfsz Counter, F goto KeyLoop ;******************************* two dummy data / Parrity and stop bit call WaitCycle SKPNC goto Capture bsf XferBuf, 0;Enable interrupt for next cycle call WaitCycle SKPNC goto Capture bsf XferBuf, 0;Enable interrupt for next cycle ;******************************* Capture special key! clrf KeyData movlw 09h movwf Counter KeyLoopS: call WaitCycleL SKPNC ;Timeout goto NoSpecKey;Resample CLRC btfsc XferBuf, 1 SETC rrf KeyData, F bsf XferBuf, 0;Enable interrupt for next cycle decfsz Counter, F goto KeyLoopS ;******************************* two dummy data / Parrity and stop bit call WaitCycle SKPNC goto Capture bsf XferBuf, 0;Enable interrupt for next cycle call WaitCycle SKPNC goto Capture bsf XferBuf, 0;Enable interrupt for next cycle bcf INTCON, GIE return NoSpecKey: movfw SpecKey movwf KeyData clrf SpecKey bcf INTCON, GIE return ;******************************* Wait Cycle WaitCycle: clrf TimeOut LCLoop: btfsc XferBuf, 0 goto IncTimeLC;wait for low CLRC return IncTimeLC: decfsz TimeOut, F goto LCLoop SETC return ;******************************* Wait Cycle Long WaitCycleL: movlw 03h movwf DelayCT LLongLoop: clrf TimeOut LLowLoop: btfsc XferBuf, 0 goto LIncTime CLRC return LIncTime: decfsz TimeOut, F goto LLowLoop decfsz DelayCT, F goto LLongLoop SETC return ;***************************************************************** ;** EEprom writing sequence WriteData: movfw PadData movwf EEADR movfw KeyData ;First Byte movwf EEDATA call EEwrite ;****************************** Start to write special key data movwf KeyData movlw 88h ;Indirect address of EECON1 movwf FSR movlw 0ch ;Get Special Key Status movwf EEADR bsf INDF, RD;Indirect point to EECON1 movfw EEDATA movwf SpeKeyH incf EEADR, F;Get Lower Special Key bsf INDF, RD;Indirect point to EECON1 movfw EEDATA movwf SpeKeyL clrf TempLo0 clrf TempHi0 incf PadData, F SETC WriteLoop: rlf TempLo0, F rlf TempHi0, F decfsz PadData, F goto WriteLoop TSTF SpecKey SKPNZ goto CleanBit;No special key, CleanSpecial bit movfw TempLo0 iorwf SpeKeyL, F movfw TempHi0 iorwf SpeKeyH, F goto WriteBack CleanBit: comf TempLo0, W andwf SpeKeyL, F comf TempHi0, W andwf SpeKeyH, F ;******************************* Write back the data WriteBack: movlw 0ch movwf EEADR movfw SpeKeyH ;First Byte movwf EEDATA call EEwrite incf EEADR, F movfw SpeKeyL movwf EEDATA call EEwrite return ;***************************************************************** ;** EEprom Write EEwrite: bsf STATUS, RP0 bcf INTCON, GIE;Writing sequence bsf EECON1, WREN movlw 55h movwf EECON2 movlw 0aah movwf EECON2 bsf EECON1, WR NotDone1: btfsc EECON1, WR goto NotDone1 bcf STATUS, RP0;Finish writing KeyData, return ;***************************************************************** ;** End end |