;*************************************************************************** ; ; AT Keyboard Scan Code Debug Interface V1.02 ; =========================================== ; ; written by Peter Luethi, 12.07.2000, Dietikon, Switzerland ; http://www.electronic-engineering.ch ; last update: 25.03.2005 ; ; V1.02: Re-structured entire ISR and RS232 echo sub-routines ; (18.04.2004) ; V1.01: Changed keyboard data pin to PORTA,4 (open-collector). ; (16.08.2003) ; V1.00: Initial release (12.7.2000) ; ; This code and accompanying files may be distributed freely and ; modified, provided this header with my name and this notice remain ; intact. Ownership rights remain with me. ; You may not sell this software without my approval. ; ; This software comes with no guarantee or warranty except for my ; good intentions. By using this code you agree to indemnify me from ; any liability that might arise from its use. ; ; ; SPECIFICATIONS: ; =============== ; Processor: Microchip PIC 16F84 ; Clock Frequency: 4.00 MHz XT ; Throughput: 1 MIPS ; RS232 Baud Rate: 19200 baud (depends on the module included) ; Serial Output: 19200 baud, 8 bit, no parity, 1 stopbit ; Keyboard Routine Features: Capability of uni-directional ; communication between microcontroller ; and keyboard ; Acquisition Methodology: Non-preemptive, interrupt-based ; keyboard scan pattern acquisition ; Code Size of entire Program: 208 instruction words ; Required Hardware: AT Keyboard, MAX 232 ; Required Software: RS232 terminal (recommended: Excel 97 ; RS232-Debug-Interface) ; ; DESCRIPTION: ; ============ ; Developed and tested on PIC 16F84. ; Any key stroke on the keyboard connected to the PIC will send the ; corresponding key scan code to the computer terminal via the RS232 ; connection. ; Verification of keyboard scan patterns and to get the scan code of ; unknown keys on non-english or non-german keyboards. ; ; The keyboard scan code capture and decoding is done by an interrupt ; service routine. The event, which triggers the interrupt is a falling ; edge on the keyboard clock line at the KBDclkpin (PORTB,0). ; The keyboard data (scan code) will be fetched at the KBDdatapin ; (PORTA,4). ; There is only RS232 transmission, so only the TXport is connected. ; No reception is necessary because there aren't any output devices ; attached to the microcontroller and PORTB,0 is already used by the ; keyboard clock line. The configuration of the KBDclkpin (PORTB,0) ; interrupt is done by the RS232init procedure (although used by the ; keyboard), because all settings are the same. ; ; ; IMPORTANT: ; ========== ; To get all parts of a complete scan pattern, it is recommended to ; use this code in compliance with the above specifications. ; Otherwise, consecutive interrupt calls are launched before the ; termination of the ISR. As a consequence, parts of scan patterns ; will not be displayed or in worst case, a system crash will happen. ; Of course, it is possible to use this code with a faster crystal ; and/or with RS232 modules specified for higher baud rates. ; ; ; CREDITS: ; ======== ; - Craig Peacock, the author of the excellent page about keyboards ; "Interfacing the PC's Keyboard" available at his website: ; http://www.beyondlogic.org/keyboard/keybrd.htm ; - Steve Lawther for inspirations concerning the scan code fetch ; routine. ; ;*************************************************************************** ;***** EXCLUDE COMPILATION MESSAGES & WARNINGS ***** ERRORLEVEL -207 ; found label after column 1 ERRORLEVEL -302 ; register in operand not in bank 0 ;***** PROCESSOR DECLARATION & CONFIGURATION ***** PROCESSOR 16F84 #include "p16f84.inc" ; embed configuration data within .asm file __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC ;***** MEMORY STRUCTURE ***** ORG 0x00 ; processor reset vector goto MAIN ; interrupt service routine at ORG 0x04 declared below ;***** PORT DECLARATION ***** #define TXport PORTA,0x00 ; RS232 output port, could be #define TXtris TRISA,0x00 ; any active push/pull port #define KBDdatapin PORTA,0x04 ; keyboard data input port #define KBDdatatris TRISA,0x04 ; (open-collector pin) #define KBDclkpin PORTB,0x00 ; keyboard clock input port (IntB) #define KBDclktris TRISB,0x00 ; @ INTF interrupt source (RB0) ;***** CONSTANT DECLARATION ***** CONSTANT BASE = 0x0C ; Base address of user file registers ;***** REGISTER DECLARATION ***** TEMP1 set BASE+d'0' ; universal temporary register TEMP2 set BASE+d'1' TEMP3 set BASE+d'2' TEMP4 set BASE+d'3' TXD equ BASE+d'4' ; RS232 TX-Data register RXD equ BASE+d'5' ; RS232 RX-Data register ; interrupt context save/restore W_TEMP equ BASE+d'6' ; context register (ISR) STATUS_TEMP equ BASE+d'7' ; context register (ISR) PCLATH_TEMP equ BASE+d'8' ; context register (ISR) FSR_TEMP equ BASE+d'9' ; context register (ISR) ISRtmp1 equ BASE+d'10' ; ISR temporary register ISRtmp2 equ BASE+d'11' ; ISR temporary register KBD equ BASE+d'12' ; keyboard data register ;***** INCLUDE FILES ***** ORG 0x50 #include "..\..\m_bank.asm" ; standard macros #include "..\..\m_wait.asm" ;#include "..\..\m_rs096.asm" ; 9600 baud, not recommended #include "..\..\m_rs192.asm" ; 19200 baud @ 4 MHz ;***** INTERRUPT SERVICE ROUTINE ***** ORG 0x04 ; interrupt vector location ISR ;************************ ;*** ISR CONTEXT SAVE *** ;************************ bcf INTCON,GIE ; disable all interrupts btfsc INTCON,GIE ; assure interrupts are disabled goto ISR movwf W_TEMP ; context save: W swapf STATUS,W ; context save: STATUS movwf STATUS_TEMP ; context save clrf STATUS ; bank 0, regardless of current bank movfw PCLATH ; context save: PCLATH movwf PCLATH_TEMP ; context save clrf PCLATH ; page zero, regardless of current page bcf STATUS,IRP ; return to bank 0 movfw FSR ; context save: FSR movwf FSR_TEMP ; context save ;*** context save done *** ;************************** ;*** ISR MAIN EXECUTION *** ;************************** ;*** Until now, already 16 cycles (16 us) have been passed *** btfsc KBDdatapin ; test start bit of keyboard data input goto KBDabort ; no valid start bit, abort movlw 0x08 ; 8 data bits to receive / counter movwf ISRtmp1 waitHI btfss KBDclkpin ; loop, wait for kbd clk HIGH transition goto waitHI waitLO btfsc KBDclkpin ; loop, wait for kbd clk LO transition goto waitLO btfss KBDdatapin goto KBD_1 bsf KBD,0x07 goto KBD_2 KBD_1 bcf KBD,0x07 KBD_2 decfsz ISRtmp1,W ; skip if ISRtmp1 == 1 rrf KBD,F ; do this only 7 times decfsz ISRtmp1,F goto waitHI ; loop 8 times ;*** ignore parity bit, check stop bit: *** movlw 0x02 ; set counter movwf ISRtmp1 waitHIp btfss KBDclkpin ; loop, wait for kbd clk HIGH transition goto waitHIp waitLOp btfsc KBDclkpin ; loop, wait for kbd clk LO transition goto waitLOp decfsz ISRtmp1,F goto waitHIp btfsc KBDdatapin ; check if stop bit is valid goto KBD_3 ; if valid, continue execution of ISR KBDabort clrf KBD ; else, abort / invalid data goto ISRend ; terminate execution of ISR ;*** STALL KEYBOARD TO DECODE DATA *** KBD_3 BANK1 ; hold keyboard (with kbd clk low): bcf KBDclktris ; set clk line to output BANK0 bcf KBDclkpin ; set keyboard clk line low (stall) movfw KBD SENDw ; send actual pressed keyboard character ;*** DISABLE STALL *** BANK1 bsf KBDclktris ; set clk line back to input (and goes high) BANK0 ; (release stall) ;*********************************** ;*** CLEARING OF INTERRUPT FLAGS *** ;*********************************** _ISR_RS232error _ISR_RS232end bcf INTCON,INTF ; clear RB0/INT interrupt flag ;goto ISRend ; terminate execution of ISR ;***************************************** ;*** ISR TERMINATION (CONTEXT RESTORE) *** ;***************************************** ISRend movfw FSR_TEMP ; context restore movwf FSR ; context restore movfw PCLATH_TEMP ; context restore movwf PCLATH ; context restore swapf STATUS_TEMP,W ; context restore movwf STATUS ; context restore swapf W_TEMP,F ; context restore swapf W_TEMP,W ; context restore RETFIE ; enable global interrupt (INTCON,GIE) ;***** END OF INTERRUPT SERVICE ROUTINE ***** ;************** MAIN ************** ORG 0xB0 MAIN BANK1 clrf OPTION_REG ; PORTB pull-ups enabled bsf KBDclktris bsf KBDdatatris BANK0 RS232init ; RS232 initialization WAIT d'5' MLoop movlw d'39' ; store amount of table items in counter movwf TEMP3 _LOOP movlw HIGH WelcomeTable ; get correct page for PCLATH movwf PCLATH ; prepare right page bits for table read movfw TEMP3 ; get actual count-down value sublw d'39' ; table offset: w = d'39' - TEMP3 call WelcomeTable ; call lookup table SENDw decfsz TEMP3,F ; decrement counter goto _LOOP WAITX d'255',d'7' ; wait 17 seconds @ 4 MHz goto MLoop WelcomeTable addwf PCL,F DT "PIC 16F84 Keyboard Decoder connected" ; create table retlw CR ; Carriage Return retlw LF ; Line Feed WTableEND retlw LF ; Line Feed IF (high (WelcomeTable) != high (WTableEND)) ERROR "Welcome table hits page boundary!" ENDIF END