;************************************************************** ;keypad_test ;Tests keypad, writing key pressed to lcd display on ;Derbot Hand Controller. ;The lcd controller is S6A0069, whose initialisation is applied. ;TJW rev. 20.7.06 Tested 20.7.06 ;*************************************************************** ;Clock is 1MHz approx ;Configuration Word: RC oscillator, WDT off, power-up timer on, ; brown-out off, LVP off, all code protect on. ; ; Port A Port B Port C ; ------ ------ ------ ;0 lcd bus 2 not used Display RS ;1 lcd bus 3 keypad col 3 Display E ;2 lcd bus 4 keypad col 2 Interrupt op ;3 lcd bus 5 keypad col 1 SCL ;4 lcd bus 6 keypad row 4 SDA ;5 lcd bus 7 keypad row 3 Display R/W ;6 - keypad row 2 lcd bus 0 ;7 - keypad row 1 lcd bus 1 list p=16F873A #include p16f873A.inc ;Specify RAM delcntr1 equ 20 ;used in delays delcntr2 equ 21 temp equ 22 ;a temp location, to be used only in consecutive instructions lcd_op equ 23 ;holds word to be sent to display pointer equ 24 ;points to Character string Tables kpad_pat equ 25 ;holds pattern of keypad kpad_add equ 26 ;holds kpad address to lu table kpad_char equ 27 ;holds most recent character from keypad flags equ 28 ;bit 0 holds RS state during busy_check SR ;Specify some port bits ;Port C lcd_RS equ 0 ;0 for instruction, 1 for character lcd_E equ 1 lcd_RW equ 5 ;Port A lcd_busy equ 5 ; org 00 goto main org 04 ;interrupt vector goto kpad_to_lcd ;Initialise main bcf status,rp1 bsf status,rp0 ;select memory bank 1 movlw B'00000000' ;Port A & C initially all op movwf trisa movwf trisc movlw B'00000110' ;All Port A bits digital movwf adcon1 movlw B'11110000' ;Port B initially Row bits ip, column op movwf trisb ;(port B not used) bcf status,rp0 ;select bank 0 ; ;initialise display bcf portb,0 ;diagnostic, used in busy_check *** call delay200 ;wait for power supply to settle bcf portc,lcd_RS ;set control lines bcf portc,lcd_RW ;Relies first on automatic initialisation, as described in data sheet ;now send four command words. Busy Flag not used. movlw B'00001111' ;first command word, Function Set, rotated by 2 bits movwf porta bsf portc,lcd_E bcf portc,lcd_E call delay1 ;wait at least 39us ; movlw B'00000011' ;next command, Display ON/OFF movwf porta bsf portc,6 bsf portc,7 bsf portc,lcd_E bcf portc,lcd_E call delay1 ;wait at least 39us ; movlw B'00000000' ;next command, Display Clear movwf porta bcf portc,7 bsf portc,6 bsf portc,lcd_E bcf portc,lcd_E call delay1 call delay1 ;wait at least 1.53ms ; movlw B'00000001' ;next command, Entry Mode Set movwf porta bsf portc,7 bcf portc,6 bsf portc,lcd_E bcf portc,lcd_E call delay1 ; ;initialise interrupt, enable port change clrf portb ;initialise keypad value bcf intcon,rbif bsf intcon,rbie bsf intcon,gie loop goto loop ;await keypad entries ;*********************************************************** ;Interrupt Service Routine. ;*********************************************************** ;Keypad press has been detected through Port B Interrupt on Change.Gets keypad pattern, ;converts to character, stores in kpad_char, sends to lcd, awaits key release, kpad_to_lcd call kpad_rd ;now convert code to character, forming address used in lu table call kp_code_conv ;now send to lcd movf kpad_char,0 ;move character to lcd buffer movwf lcd_op bsf portc,lcd_RS ;set for character op call lcd_write ;test now for keypad release rel_test call kpad_rd movf kpad_pat,0 andlw 0fe ;suppress lsb, which is not used sublw 0fe ;test if inactive btfss status,z goto rel_test bcf intcon,rbif ;clear interrupt flag retfie ; ;*********************************************************** ;SUBROUTINES ;*********************************************************** ;Reads keypad, places pattern into kpad_pat, and resets keypad interface kpad_rd movf portb,w ;read portb value, this will be row pattern andlw B'11110000' ;ensure unwanted bits are suppressed movwf kpad_pat bsf status,rp0 ;set row to op, column to ip movlw B'00001110' movwf trisb bcf status,rp0 movlw 00 movwf portb ;ensure output values still zero movf portb,w ;read portb value, this will be column pattern andlw B'00001110' ;ensure unwanted bits are suppressed iorwf kpad_pat,1 ;OR those results into the pattern ;reset keypad interface bsf status,rp0 ;set row to ip, column to op movlw B'11110000' movwf trisb bcf status,rp0 clrf portb ;ensure output values still zero return ;Converts keypad pattern held in kpad_pat to ASCII character, first forming ;address (in kpad_add) that is used in lu table. Returns with character held in kpad_char kp_code_conv bcf status,c rrf kpad_pat,1 ;discard bit 0 which is not used clrf kpad_add ;deduce row btfsc kpad_pat,6 goto kp1 goto col_find ;here if row 1, kpad_add stays as is kp1 btfsc kpad_pat,5 goto kp2 movlw B'00000100' ;here if row 2 iorwf kpad_add,1 ;form table address goto col_find kp2 btfsc kpad_pat,4 goto kp3 movlw B'00001000' ;here if row 3 iorwf kpad_add,1 ;form table address goto col_find kp3 btfsc kpad_pat,3 goto kp4 movlw B'00001100' ;here if row 3 iorwf kpad_add,1 ;form table address goto col_find kp4 movlw D'16' ;no row detected, return "E" via Table goto keypad_op ;now deduce column col_find btfsc kpad_pat,2 goto cf1 goto keypad_op ;here if column 1, kpad_add stays as is cf1 btfsc kpad_pat,1 goto cf2 movlw B'00000001' ;here if column 2 iorwf kpad_add,1 ;form table address goto keypad_op ;assume now column 3 cf2 movlw B'00000010' iorwf kpad_add,1 ;form table address keypad_op movf kpad_add,0 call kp_table movwf kpad_char ;save the character return ; ;Table called to convert pattern recd from keypad to actual character. Note that ;ASCII codes will be returned, as each digit is in format 'D'. kp_table addwf pcl,1 retlw '1' ;row 1 retlw '2' retlw '3' retlw 'A' ;Error code retlw '4' ;row 2 retlw '5' retlw '6' retlw 'B' ;Error code retlw '7' ;row 3 retlw '8' retlw '9' retlw 'C' ;Error code retlw '*' ;row 4 retlw '0' retlw '#' retlw 'D' ;Error code retlw 'E' ;Error code ; ;Waits until busy clear, and writes word held in lcd_op to display. ;RS must be preset to required value, this status is preserved. lcd_write call busy_check bcf portc,lcd_rw bcf status,c rrf lcd_op,1 ;form output bits, op word sits across ports a & c bcf portc,6 ;set value of bit 0 of bus btfsc status,c bsf portc,6 bcf status,c rrf lcd_op,1 bcf portc,7 ;set value of bit 1 of bus btfsc status,c bsf portc,7 movf lcd_op,0 movwf porta bsf portc,lcd_E bcf portc,lcd_E return ;Test Busy Flag, and wait till cleared busy_check bsf status,rp0 ;select memory bank 1 movlw B'00111111' ;set port A all ip movwf trisa bcf status,rp0 bcf flags,0 btfsc portc,lcd_RS ;save RS bit in flags, 0 bsf flags,0 bcf portc,lcd_RS ;access instruction register bsf portc,lcd_RW ;set to read busy_loop bcf portc,lcd_E bsf portc,lcd_E btfsc porta,lcd_busy ;test the busy flag, loop if still busy goto busy_loop bcf portc,lcd_E bsf status,rp0 ;select memory bank 1 movlw B'00000000' ;set port A all op, movwf trisa bcf status,rp0 bcf portc,lcd_RS btfsc flags,0 ;reinstate RS bit bsf portc,lcd_RS return ; ;introduces delay of 100us approx delay100u movlw D'6' ;6 cycles called, each taking 16us movwf delcntr1 del1001 nop ;4 inst cycles in this loop, ie 16us decfsz delcntr1,1 goto del1001 return ;introduces delay of 1ms approx delay1 movlw D'62' ;62 cycles called, each taking 16us movwf delcntr1 del1 nop ;4 inst cycles in this loop, ie 16us decfsz delcntr1,1 goto del1 return ; ;introduces delay of 5ms approx delay5 movlw D'250' ;250 cycles called movwf delcntr1 del51 nop ;5 inst cycles in this loop, ie 20us nop decfsz delcntr1,1 goto del51 return ; ;introduces delay of 200ms approx, by 200 calls to delay1 delay200 movlw D'200' movwf delcntr2 del2 call delay1 decfsz delcntr2,1 goto del2 return ; end