LIST P=16C84, F=INHX8M ; ERRORLEVEL 2 __CONFIG _CP_OFF & _WDT_OFF & _XT_OSC ;***************************************************************************** ; ; ; Program to read a standard 4x4 keyboard. ; Keypresses are detected on interrupt and ; debounced. Keyboard is connected to portb ; of the 16[cf]84. Key code is shown on 4 ; lower bits of porta for debugging purposes. ; Key code is clocked out on highest bit (ra4) of ; porta. This code can then be read by ; another uC. Pulse width and delay are determined ; by delay routines. Presently, pulse width is ; app. 0.5 mS and pulse delay (time between pulses) ; is app. 0.5 mS. ; ; RA4 is used as an open drain output pin. Therefore, ; a 10k pull-up resistor must be connected between RA4 ; and Vcc. ; ; RA0,1,2,3 can be used for debugging. Key code ; is shown on this port. Connect 4 LED's via 1k ; resistors to Vss. ; Note that this program has a start-up delay of ; app. 1 second because the four led's are flashed ; twice to verify correct program start. ; ; Used portions of code written by Mick Hodges ; (mick@g4ope.demon.co.uk) developed for ; controlling a AD7008 DDS. ; ;***************************************************************************** ; Program KEYB441.ASM ; Date 19980511 ; Author Charlos Potma ; ;***************************************************************************** ; Fosc = 4MHz ; Cycle_time = 1/Fosc / 4 = 1uSec ;***************************************************************************** ; CHANGE NEXT LINE TO REFLECT YOUR MPLAB SETUP include ;***************************************************************************** ; Equates, I/O, vars ;***************************************************************************** RESET_V EQU 0x0000 ; Address of RESET Vector ISR_V EQU 0x0004 ; Address of Interrupt Vector OSC_FREQ EQU D'4000000' ; Oscillator Frequency is 4 MHz ; PORTB bits RB7 EQU 7 ; Keyboard, col 1 RB6 EQU 6 ; Keyboard, col 2 RB5 EQU 5 ; Keyboard, col 3 RB4 EQU 4 ; Keyboard, col 4 RB3 EQU 3 ; Keyboard, row 4 RB2 EQU 2 ; Keyboard, row 3 RB1 EQU 1 ; Keyboard, row 2 RB0 EQU 0 ; Keyboard, row 1 ; PORTA bits RA4 EQU 4 ; Code out, pulse train, use 10k pull-up RA3 EQU 3 ; Key code, bit 3, use 1k + LED to Vss RA2 EQU 2 ; Key code, bit 2, use 1k + LED to Vss RA1 EQU 1 ; Key code, bit 1, use 1k + LED to Vss RA0 EQU 0 ; Key code, bit 0, use 1k + LED to Vss ;***************************************************************************** ; Equates, registers ;***************************************************************************** TEMP EQU 0x00C ; Temp storage LASTKEY EQU 0x00D ; Last key pressed KEYCNT EQU 0x00E ; Copy of LASTKEY ; Misc. DELAY EQU 0x00F ; Used in delay routines X_DELAY EQU 0x010 ; " COUNT EQU 0x011 ; Used as g.p. counter _W EQU 0x012 ; TEMPORARY STORE FOR W _STATUS EQU 0x013 ; TEMPORARY STORE FOR STATUS ;***************************************************************************** ; Program start ;***************************************************************************** ORG RESET_V ; RESET vector location RESET GOTO START ;***************************************************************************** ; This is the Peripheral Interrupt routine. ;***************************************************************************** ORG ISR_V ; Interrupt vector location MOVWF _W SWAPF STATUS,W MOVWF _STATUS BCF STATUS,RP0 ; Select bank 0 GOTO INTERRUPT ;***************************************************************************** ; Initialize processor registers ;***************************************************************************** START ; POWER_ON Reset (Beginning of program) CLRF STATUS ; Do initialization, Select bank 0 CLRF INTCON ; Clear int-flags, Disable interrupts CLRF PCLATH ; Keep in lower 2KByte CLRF PORTA ; ALL PORT output should output Low. CLRF PORTB BSF STATUS, RP0 ; Select bank 1 MOVLW B'00000000' ; RA4-0 as outputs MOVWF TRISA CLRF PORTB ;LATCH ALL LOW MOVLW B'11110000' ;RB0-RB3 OUTPUT LOW RB4-RB7 INPUT MOVWF TRISB BCF OPTION_REG, NOT_RBPU ; Enable weak pull-ups on port B BCF STATUS, RP0 ; Select bank 0 BCF INTCON, INTF ; Clear interrupt flag BSF INTCON, RBIE ; Enable interrupt on RB7-4 change BSF INTCON, GIE ; Enable interrupts ;***************************************************************************** ; Wait for keypress CALL FLASH ; Flash leds a few times LOOP GOTO LOOP ;***************************************************************************** ; Program ends here. ; Routines follow. ;***************************************************************************** ; FLASH flash leds a few times ;***************************************************************************** FLASH MOVLW B'00001111' MOVWF PORTA CALL SECWAIT CALL SECWAIT MOVLW B'00000000' MOVWF PORTA CALL SECWAIT CALL SECWAIT MOVLW B'00001111' MOVWF PORTA CALL SECWAIT CALL SECWAIT MOVLW B'00000000' MOVWF PORTA RETURN ;***************************************************************************** ; DISPLAY display key code on RA0,1,2,3 ;***************************************************************************** DISPLAY MOVF LASTKEY, W ANDLW 0x0F ; Make sure only 4 lower bits are valid MOVWF PORTA RETURN ;***************************************************************************** ; KEYOUT send key code to RA4 as a pulse train ;***************************************************************************** KEYOUT CALL PULSERA4 ; First wake up other uC with a short pulse MOVF LASTKEY, W BTFSC STATUS, Z ; If zero forget about more pulses RETURN MOVWF KEYCNT ; Copy lastkey to keycnt CALL PULSERA4 REPCNT DECFSZ KEYCNT, F ; Decrement keycnt, if zero, return GOTO SENDPULSE RETURN SENDPULSE CALL PULSERA4 ; not zero, send a pulse GOTO REPCNT ;***************************************************************************** ; PULSERA4 pulse RA4 pin high, then low ;***************************************************************************** PULSERA4 BSF PORTA, RA4 MOVLW d'1' ; Wait 1x0.5ms (high) CALL X_DELAY500 BCF PORTA, RA4 MOVLW d'1' ; Wait 1x0.5ms CALL X_DELAY500 RETURN ;***************************************************************************** ; DONE Return from interrupt ;***************************************************************************** DONE BCF STATUS,RP0 ; Select bank 0 CLRF PORTB ; Clear port b MOVF PORTB,F SWAPF _STATUS,W ; Restore saved registers MOVWF STATUS SWAPF _W,F SWAPF _W,W BCF INTCON,RBIF ; CLEAR Port B interrupt FLAG RETFIE ;***************************************************************************** ; INTERRUPT Service keyboard interrupt ;***************************************************************************** INTERRUPT BCF STATUS,RP0 MOVLW d'80' CALL X_DELAY500 ; 80 * 0.5mS = 40mS MOVLW B'11110000' ; CHECK FOR KEY DOWN MOVWF TEMP MOVF PORTB,W SUBWF TEMP,F BTFSC STATUS, Z GOTO DONE ; ALL KEYS UP SO RETURN CALL GETKEY ; KEY PRESSED NOW IN W (0 - 15) MOVWF LASTKEY ; SAVE IT CALL KEYOUT ; Send key code to RA4 as a pulse train CALL DISPLAY ; Display key code on RA0,1,2,3 GOTO DONE ;***************************************************************************** ;GETKEY ROUTINE THAT RETURNS WITH THE KEY PRESSED IN W. (0 to 15, 16 = NO KEY) ;***************************************************************************** GETKEY BTFSS PORTB, RB4 GOTO ROW1 BTFSS PORTB, RB5 GOTO ROW2 BTFSS PORTB, RB6 GOTO ROW3 BTFSS PORTB, RB7 GOTO ROW4 RETLW D'16' ROW1 BSF PORTB, RB0 BTFSC PORTB, RB4 RETLW D'1' ;1 BSF PORTB, RB1 BTFSC PORTB, RB4 RETLW D'2' ;2 BSF PORTB, RB2 BTFSC PORTB, RB4 RETLW D'3' ;3 BSF PORTB, RB3 BTFSC PORTB, RB4 RETLW D'15' ;FNC RETLW D'16' ROW2 BSF PORTB, RB0 BTFSC PORTB, RB5 RETLW D'4' ;4 BSF PORTB, RB1 BTFSC PORTB, RB5 RETLW D'5' ;5 BSF PORTB, RB2 BTFSC PORTB, RB5 RETLW D'6' ;6 BSF PORTB, RB3 BTFSC PORTB, RB5 RETLW D'14' ;RCL RETLW D'16' ROW3 BSF PORTB, RB0 BTFSC PORTB, RB6 RETLW D'7' ;7 BSF PORTB, RB1 BTFSC PORTB, RB6 RETLW D'8' ;8 BSF PORTB, RB2 BTFSC PORTB, RB6 RETLW D'9' ;9 BSF PORTB, RB3 BTFSC PORTB, RB6 RETLW D'13' ;STO RETLW D'16' ROW4 BSF PORTB, RB0 BTFSC PORTB, RB7 RETLW D'11' ;CLR BSF PORTB, RB1 BTFSC PORTB, RB7 RETLW D'0' ;0 BSF PORTB, RB2 BTFSC PORTB, RB7 RETLW D'10' ;DOT BSF PORTB, RB3 BTFSC PORTB, RB7 RETLW D'12' ;ENT RETLW D'16' ;***************************************************************************** ; Delay_time = ((DELAY_value * 3) + 4) * Cycle_time ; DELAY_value = (Delay_time - (4 * Cycle_time)) / (3 * Cycle_time) ; ; i.e. (@ 4MHz crystal) ; Delay_time = ((32 * 3) + 4) * 1uSec ; = 100uSec ; DELAY_value = (500uSec - 4) / 3 ; = 165.33 ; = 165 ;***************************************************************************** DELAY500 MOVLW D'165' ; +1 1 cycle MOVWF DELAY ; +2 1 cycle DELAY500_LOOP DECFSZ DELAY, F ; step 1 1 cycle GOTO DELAY500_LOOP ; step 2 2 cycles DELAY500_END RETURN ; +3 2 cycles ; ; X_DELAY500 MOVWF X_DELAY ; +1 1 cycle X_DELAY500_LOOP CALL DELAY500 ; step1 wait 500uSec DECFSZ X_DELAY, F ; step2 1 cycle GOTO X_DELAY500_LOOP ; step3 2 cycles X_DELAY500_END RETURN ; +2 2 cycles ;***************************************************************************** ;***************************************************************************** SECWAIT MOVLW D'20' ; 20 times 15 = 300 msec MOVWF COUNT SECLOOP MOVLW 0x01E ; 15 msec CALL X_DELAY500 DECFSZ COUNT, F GOTO SECLOOP SECLOOPEND RETURN END