; PC keyboard interface. V 0.03 ; By Phil Ruston. 16-3-2005 ; internal ~4MHz source clock - 1 uS per instruction ; Stuff NOT implemented in software yet: ;--------------------------------------- ; 1. NMI and CPU reset key recognition and line pulses ; 2. Test to make sure previous byte has been read before replacing with new data ; 3. Control of keyboard clock and data lines (to allow interface to tell KB to wait). ; 4. F7 keycode not trapped. ;---------------------------------------------------------------------- list p=16f628 ; define processor list r=decimal ; default number base #include ; processor specific defs #define bank0 bcf STATUS,RP0 ;macros #define bank1 bsf STATUS,RP0 #define skipifzero btfss STATUS,Z #define skipifnotzero btfsc STATUS,Z #define skipifcarry btfss STATUS,C #define skipifnotcarry btfsc STATUS,C ;----- PIC H/W OPTIONS ---------------------------------------------- __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _LVP_OFF ;----- PROJECT EQUATES ---------------------------------------------- ; ----- PORT A ------- kb_clk_in equ 5 ;input - RA5 is always an input kb_data_in equ 4 ;input kb_clk_out equ 2 ;output kb_data_out equ 3 ;output busy_status equ 0 ;input set_irq_out equ 1 ;output cpu_reset_out equ 6 ;output cpu_nmi_out equ 7 ;output ; data dir = 00110001 ;----- VARIABLES------------------------------------------------------------------------------ shiftcount equ 0x20 ;first address of user reg space (bank 0) shiftreg equ 0x21 countdown1 equ 0x22 countdown2 equ 0x23 timeout equ 0x24 looptime equ 0x25 breakmode equ 0x26 ;---------------------------------------------------------------------------------------------- w_temp equ 0x70 ; variable used for context saving status_temp equ 0x71 ; variable used for context saving ;********************************************************************************************* ORG 0x000 ; processor reset vector goto main ; go to beginning of program ORG 0x004 ; interrupt vector location movwf w_temp ; save off current W register contents movf STATUS,w ; move status register into W register movwf status_temp ; save off contents of STATUS register call irq_code movf status_temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_temp,f swapf w_temp,w ; restore pre-isr W register contents retfie ; return from interrupt ;--------------------------------------------------------------------------------------------- main ; INITIALIZE CHIP movlw b'00000111' movwf CMCON ; use digital mode for PORTB (disable comparitors) clrf PORTA clrf PORTB banksel TRISA movlw b'00110001' ; set data direction for port A movwf TRISA movlw b'00000000' ; set data direction for port B movwf TRISB banksel PORTA ;-------------------------------------------------------------------------------------------- init movlw 9 movwf shiftcount clrf shiftreg clrf breakmode clrf PORTA clrf PORTB bsf PORTA,cpu_reset_out ;set active low outputs high bsf PORTA,cpu_nmi_out call wait100ms ;wait 0.1 seconds to settle before reading first data ;------------------------------------------------------------------------------------------- mainloop call waitclk btfsc timeout,0 ;was wait between clocks too long? goto timedout rotate rrf shiftreg,f ;move bits to the right bsf shiftreg,7 ;put new bit in on left btfss PORTA,kb_data_in bcf shiftreg,7 decfsz shiftcount,f ;counting 9 bits loses first start bit goto mainloop movf shiftreg,w sublw 0xf0 ;is it a release code prefix? skipifnotzero goto relcode movf shiftreg,w sublw 0xe0 ;is it an "e0" code? skipifnotzero goto ignoree0 movf shiftreg,w iorwf breakmode,w movwf PORTB ;copy full shift register to PORT B call waitclk ;ignore parity bit call waitclk ;ignore stop bit bsf PORTA,set_irq_out ;pulse to set irq flipflop clrf breakmode bcf PORTA,set_irq_out movlw 9 movwf shiftcount goto mainloop timedout movlw 9 ;if wait between clocks was 10 x normal then movwf shiftcount ;assume this is first bit of new 11 bit sequence goto rotate relcode bsf breakmode,7 ;dont bother with interrupt but set breakmode bit ignoree0 call waitclk ;ignore last 2 bits of data stream call waitclk movlw 9 movwf shiftcount goto mainloop ;---------------------------------------------------------------------------------------- waitclk clrf timeout clrf looptime waitclk1 incf looptime,f ;if clock is already low going in, wait for skipifnotzero ;clock to go high bsf timeout,0 btfss PORTA,kb_clk_in goto waitclk1 waitclk2 incf looptime,f ;now wait for clock to go low skipifnotzero bsf timeout,0 btfsc PORTA,kb_clk_in goto waitclk2 return ;----------------------------------------------------------------------------------------- wait1ms movlw 248 ; 1 us movwf countdown1 ; 1 us wait1msl nop ; 1 us decfsz countdown1,f ; 1 us goto wait1msl ; 2 us nop ; 1 us nop ; 1 us nop ; 1 us return ; 2 us wait100ms movlw 100 movwf countdown2 wait100l call wait1ms decfsz countdown2,f goto wait100l return ;----------------------------------------------------------------------------------------- irq_code return ;******************************************************************************************** END ; directive 'end of program'