; File: LCDRS232.ASM ; First time that it works: 3 August of 2000. ; Author: Alejandro Lavarello - R.O. del Uruguay - South America ; Contact: alejol@adinet.com.uy ; Colocado en la PicListLatina el 4/7/00. ; PicListLatina: Lista de correos dedicada a micro PIC y clones (SCENIX) en ; portugues y espanol. ; Gracias Norberto por compartir tu codigo! :) ; Part of the code is adapted from the magazine "Electronica y Computadores" edited by CEKIT. ; Abstract: ; =========== ; The basic idea is to made a simple character terminal that can be used as ; man-machine interfce in some equipment. ; The PIC1F84 is conected to a 4 x 4 matrix keyboard. RA1 and RA0 are connected ; to a MAX232 in order to convert TTL/RS232 levels. ; Each keypressed in the 4x4 keyboard is send to a PC runningan terminal emulator ; like "Hyperterminal". ; Each key pressed in the PC is displayed in a LCD module atached to the PIC. ; Neither TMR0 nor interrupts are used. Because it, I think that a OTP PICMICRO ; may be used in final version in order to make the device more cheap. ; ; Disadvantages/drawbacks/ future improvements needed: ; ==================================================== ; 0) Make the code more easily readable...sorry, I am not an English speaker... ; 1) Txspeed = Rx speed = 1200 bauds (fixed) , 8 bits, no parity, 1 stop bit. ; No flow control implemented. ; 2) The null character ( 0 ) is not send nor received, it is ignored. ; 3) No display control ( "clear display", "position cursor", etc) are implemented. ; 4) It is possible to connect the pin R/W to ground and liberate RA3 for another use. ; 5) Only one key pressed admited, the firmware rejects simultaneous keys pressed. ; Basic ideas: ; ============ ; 1) This code is based in "isocrhonous code", this is, each routine have a fixed execution time. ; In case of branches inside a routine, just before each "return" I have added a adjustable ; software delay in order to mantain the same execution time. ; 2) The MAIN_LOOP is "perpetual" and executes in 277 microseconds. This allows to sample ; 3 times each bit at 1200bauds. The value ("1" or "0") of the pin Pin_RX is sampled ; 3 times spaced 2 microseconds, and the pin value is decided by majority. ; 3) The routines RS232 and READ_KEYBOARD using state machines. ; 4) Is not implemented "auto repeat" of the keys. Only one charater is send and ; READ_KEYBOARD waits for key release. ; ; Hardware notes: ;================= ; Display used model: JM161A (1 line x 16 characters). Web page: ; http://www.china-lcd.com/english/eindex.html ; ; Each pin of the PORTB has a 100 ohm series resistor (I have seen this in various circuits...) ; PORTA,4 has a pull-up resistor of 1 kohm. ; PORTB<3..0> are used as outputs, and are conected to DB7..DB4 of the LCD, and too to the ; LINE1 to LINE4 of the 4 x 4 keyboard. ; PORTB<7..4> are inputs conected to the keyboard columns COL4 to COL1. ; Contrast adjust of the LCD (input named V5 of the LCD) are made with a 5k multi- potentiometer ; The best contrast is achieved with about 0,7 V in V5. ; Low nibble of the LCD _DATA_ bus (DB3 to DB0) are connected to ground. ; ; The MAX232 has capacitors of 10 microfarads. Pin 11 of MAX232 connected to PORTA, 1 ; and pin 12 to PORTA, 0 ; The 4x4 matrix keyb. has 0 to 9 keys, plus: "HELP" key, "2ND" key, ; up arrow, down arrow , "CANCEL" and "ENTER". ; Keyboard is labelled "MADE BY ACT"(the most cheap that I have encountered). LIST P=16F84 ; The old and good PIC16F84 INCLUDE "P16F84.INC" ; Standard file of Microchip with equates that match _DATA_sheets. __CONFIG _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC ; Configuration word= 0x11, tis is, ; Code protection= OFF, Watchdog = Not used, Power On Timer= Used, ; Oscillator type= XT Crystal ; Crystal used: 4 MHz ; Delays dependent of crystal value. ; ******************************************** ; **** User RAM ("file registers")*********** ; ******************************************** _DATA__REG equ 0x0C ; Aux. reg. to write in display. REG_1mseg EQU 0x0D ; Loop counter for delay of aprox 1ms. REG_Various_ms equ 0x0E ; Another loop counter for delay. SHADOWB EQU 0x0F ; Used to "create" the value that will be write in PORTB KEY equ 0x10 ; ASCII code of the key pressed. CONTROL_TX equ 0x11 ; Variable that controls progress of TX state-machine. CONTROL_RX equ 0x12 ; idem RX CONTROL_KEYBOARD equ 0x13 ; Idem for the keyboard state machine. TX_REG equ 0x14 ; Character to transmit.Destroyed in Tx. CHAR_RX equ 0x15 ; Character received. RX_REG equ 0x16 ; Temporal storing of received bits. REG_LOOP equ 0x17 ; Counter for variable delays. SHADOWA equ 0x18 ; Used "to make" the byte that will be write in PORTA. SCAN_CODE equ 0x19 ; "Crude" value of keyboard scan (must be converted to ASCII) AUX equ 0x1A ; Auxilar variable. DELAY_KEYBOARD equ 0x1B ; Help in wait for keyboard debounces. SCAN_PORTB equ 0x1C ; Stores which line of PORTB is zero in order to scan keyb. LINE equ 0x1D ; Which line is scanned (1, 2, 3, 4) COUNT_CHARACTERS equ 0x1E ; How many char. were written to the LCD. Used for ; wraparound. ; *********** End of RAM definition ****** ; ******************************** ; *** Various bit equates ***** ; ******************************** E EQU 0x04 ;Connected to LCD's "Enable" (a kind of "clock")! Pin of PORTA RS EQU 0x02 ; " " LCD's "Register Select" pin. RW EQU 0x03 ; " " LCD's pin "Read/Write" . Pin_TX EQU 0x01 ; Output Rs232.( TTL level) Pin_RX EQU 0x00 ; Input RS232.( TTL level) ; ********* End of bit equates ***** ; ************************************* ; ****** MAIN PROGRAM *********** ; ************************************* ORG 0x00 ; Reset vector. goto BEGIN ORG 0x04 ; Interrupt vector. Not used. nop ;------------------------------------------------------------------ ORG 0x100 BEGIN ; In the power-up, begins here. ; Microchip reccomends "not to use TRIS" "not to use OPTION". ; It works very fine and saves instructions. movlw b'00000000' ; Pull-ups enabled, etc. OPTION movlw b'00000001' ; PORTA: All outputs except PORTA, 0 TRIS PORTA movlw b'11110000' ; Port B: high nibble inputs, low outputs. TRIS PORTB clrf PORTA ; I will write-only in the LCD. CLRF PORTB ; (The R/W pin may be connected to ground). bsf PORTA, Pin_TX ; "IDLE STATE" for the RS232 TX line. ; ----------------------------------------- ; ** Power ON wait *** ; ----------------------------------------- movlw d'60' ; Will wait about 60 milliseconds - wait for movwf REG_Various_ms ; the LCD to wake-up -. INITIAL_DELAY call DELAY_1ms decfsz REG_Various_ms, F goto INITIAL_DELAY ; -------End of Power-On wait ------------- ; --------------------------------------------- ; --------- DISPLAY INITIALIZATION --------- ; --------------------------------------------- ; We need 5 steps : ; Step 1 movlw 0x02 ; 4 bits interface initialization. call CONTROL ; Seems to be redundant wit step 2, call DELAY_1ms ; but is really needed. call DELAY_1ms ; Step 2 movlw b'00101000' ; Initializing 4 bits and 2 lines. call CONTROL ; Instruction named: call DELAY_1ms ; "FUNCTION SET" ; Paso 3 movlw b'00001111' ; Display On, cursor On, blink on call CONTROL ; Instruction named: call DELAY_1ms ; "DISPLAY ON/OFF CONTROL" ; Paso 4 movlw b'00000110' ; Name: "ENTRY MODE SET" call CONTROL ; Right display shifting call DELAY_1ms ; Entire display shifting: disabled. ; Paso 5 movlw b'00000001' ; Name: call CONTROL ; "CLEAR DISPLAY". call DELAY_1ms ; Display RAM pointer set to 0. call DELAY_1ms call DELAY_1ms ; Approx. 1.53 millsec. minimum exec. time. movlw 0x80 ; Set display's RAM pointer to 0 call CONTROL ; (perhaps redundant...) call DELAY_1ms ; ;--------- Initialization of important variables ------ clrf CONTROL_TX clrf CONTROL_RX clrf CONTROL_KEYBOARD clrf COUNT_CHARACTERS movlw ">" ; After power-up, sends a ">" to the PC signalling "i am alive" movwf KEY movlw ":" ; Writes this in the LCD at power on. movwf CHAR_RX ; ******************************************************* MAIN_LOOP call RS232 ; Routine rx/tx : 39 machine cycles = 39 usec with 4MHz ; crystal. call READ_KEYBOARD ; 40 cycles call WRITE_TO_DISPLAY ; 153 cycles call SEND_KEY ; 14 cycles ; 246 cycles. Need a total time of 277 usec. ;----------------- movlw d'08' call Variable_Wait ; 28 cycles ;---------------- nop ; 1 cycle goto MAIN_LOOP ; 2 cycles ; MAIN_LOOP is executed in 246 +28+1+2 = 277 microseconds. ; ******************************************************* DELAY_1ms ; Delay of about 1 msec. clrf REG_1mseg DECRE_1 decfsz REG_1mseg, F goto DECRE_1 RET_230 ; delay of about 234 usec. movlw d'76' movwf REG_1mseg DECRE_2 decfsz REG_1mseg, F goto DECRE_2 return ;-------------------------------------------- SEND_KEY movf CONTROL_TX, F ; control=0 ? (is the TX machine free to send?) btfsS STATUS, Z goto No_SEND_KEY1 ; wait for TX state machine ... movf KEY, F ; KEY to send is 0? btfsc STATUS, Z goto No_SEND_KEY2 ; yes, is zero,no send it. ; nop, is different of zero, send it. incf CONTROL_TX, F movf KEY, W movwf TX_REG clrf KEY ; "Eating" the KEY :) return No_SEND_KEY1 goto $+1 nop No_SEND_KEY2 nop goto $+1 return ;-------------------------------------------- WRITE_TO_DISPLAY movf CHAR_RX, W btfss STATUS, Z goto Write_Char_Received GOTO No_Write Write_Char_Received ; COUNT_CHARACTERS incremented with each caracter OR control ; bytes sends to the LCD module. incf COUNT_CHARACTERS, F ; How many characters writed? movlw d'09' xorwf COUNT_CHARACTERS, W ; Is the 9nth. write to the LCD? btfsc STATUS, Z goto SECOND_LINE movlw d'18' xorwf COUNT_CHARACTERS, W ; Is the 18nth write to the LCD? btfsc STATUS, Z goto FIRST_LINE ; Wraparound of the LCD display. Write_LCD movf CHAR_RX, W nop clrf CHAR_RX ; "Eat" the just-received character. goto _DATA_ ; We will use the RETURN of the _DATA_ routine. SECOND_LINE nop goto $+1 goto $+1 movlw 0xC0 ; Point to the first "second line" position. goto CONTROL ; Next char in the virtual "second line" ; RETURN of the CONTROL routine used. FIRST_LINE clrf COUNT_CHARACTERS movlw 0x80 ; Point to the very first character in display's RAM. goto CONTROL ; No_Write movlw d'46' call Variable_Wait ;------------------- nop return ;----------------------------------------------- ; Variable_Wait = 2 (call) + 3*n +2 (return) = 3*n + 4 ; n is the W value. Variable_Wait movwf REG_LOOP Repeat decfsz REG_LOOP, F goto Repeat return ;-------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------- CONTROL ; Receive a byte in W and writes it to the LCD as control code. bcf PORTA, RS ;Signals to the LCD that is a control code. goto $+1 goto _DATA_2 _DATA_ ; The byte in W is passed as _DATA_ . bsf PORTA, RS ;Signals that char. is a _DATA_ char. goto $+1 goto _DATA_2 _DATA_2 bsf PORTA, E ; Rises E (LCD's clock) goto $+1 ; 4 bit Interface , the _DATA_ is send ; in two nibbles. movwf _DATA__REG ; Save char in aux. register. swapf _DATA__REG, W ; Write high nibble. movwf PORTB goto $+1 goto $+1 ;Falling edge in E. bcf PORTA, E ; Nibble latched here. goto $+1 goto $+1 bsf PORTA, E ; Rises E for next time. ;------------------ movlw d'15' call Variable_Wait ;------------------ movf _DATA__REG, W ; Go for the low nibble... movwf PORTB goto $+1 goto $+1 ; Second pulse in E... bcf PORTA, E ; Nibble latched... goto $+1 goto $+1 bsf PORTA, E ;------------------ movlw d'15' call Variable_Wait ;----------------- return ;-------------- End of CONTROL/_DATA_ routine. ;-------------- ;----------------------------------- ORG 0x005 RS232 ; TX clrf PCLATH ; Take care with PCLATH in computed gotos! movf CONTROL_TX, W addwf PCL, F ; TX state machine. goto OUT_TX ; 0 goto SEND_STARTbit ; 1 goto WAIT_TX ; 2 goto WAIT_TX ; 3 goto SEND_BIT ; 4 bit 0 goto WAIT_TX ; 5 goto WAIT_TX ; 6 goto SEND_BIT ; 7 bit 1 goto WAIT_TX ; 8 goto WAIT_TX ; 9 goto SEND_BIT ; 10 bit 2 goto WAIT_TX ; 11 goto WAIT_TX ; 12 goto SEND_BIT ; 13 bit 3 goto WAIT_TX ; 14 goto WAIT_TX ; 15 goto SEND_BIT ; 16 bit 4 goto WAIT_TX ; 17 goto WAIT_TX ; 18 goto SEND_BIT ; 19 bit 5 goto WAIT_TX ; 20 goto WAIT_TX ; 21 goto SEND_BIT ; 22 bit 6 goto WAIT_TX ; 23 goto WAIT_TX ; 24 goto SEND_BIT ; 25 bit 7 goto WAIT_TX ; 25 goto WAIT_TX ; 27 goto SEND_BIT ; 28 STOP BIT goto WAIT_TX ; 29 goto OUT_TX ; 30 SEND_STARTbit goto $+1 goto $+1 goto $+1 bcf PORTA, Pin_TX goto $+1 incf CONTROL_TX, F goto RX ; ciclo 17 SEND_BIT movf PORTA, W ; First I "make" the bit in SHADOWA... movwf SHADOWA bcf SHADOWA, Pin_TX btfsc TX_REG, 0 bsf SHADOWA, Pin_TX movf SHADOWA, W movwf PORTA ;... and then writes the bit in PORTA, Pin_TX bsf STATUS, C ; Shift the TXreg for the next time... rrf TX_REG, F incf CONTROL_TX, F goto RX WAIT_TX goto $+1 goto $+1 goto $+1 goto $+1 nop incf CONTROL_TX, F goto RX OUT_TX goto $+1 goto $+1 goto $+1 goto $+1 nop clrf CONTROL_TX goto RX RX clrf SHADOWA ; Here Pin_RX is sampled 3 times. btfsc PORTA, Pin_RX incf SHADOWA, F btfsc PORTA, Pin_RX incf SHADOWA, F btfsc PORTA, Pin_RX incf SHADOWA, F ; If Pin_RX was "1" the majority of the time, ; then SADOWA,1 is "1" too. movf CONTROL_RX, W ; RX state machine. addwf PCL, F goto LOOK_FOR_STARTbit ; 0 goto LOOK_FOR_STARTbit ; 1 goto WAIT_RX ; 2 goto WAIT_RX ; 3 goto RECEIVE_A_BIT ; 4 bit 0 goto WAIT_RX ; 5 goto WAIT_RX ; 6 goto RECEIVE_A_BIT ; 7 bit 1 goto WAIT_RX ; 8 goto WAIT_RX ; 9 goto RECEIVE_A_BIT ; 10 bit 2 goto WAIT_RX ; 11 goto WAIT_RX ; 12 goto RECEIVE_A_BIT ; 13 bit 3 goto WAIT_RX ; 14 goto WAIT_RX ; 15 goto RECEIVE_A_BIT ; 16 bit 4 goto WAIT_RX ; 17 goto WAIT_RX ; 18 goto RECEIVE_A_BIT ; 19 bit 5 goto WAIT_RX ; 20 goto WAIT_RX ; 21 goto RECEIVE_A_BIT ; 22 bit 6 goto WAIT_RX ; 23 goto WAIT_RX ; 24 goto RECEIVE_A_BIT ; 25 bit 7 goto WAIT_RX ; 26 goto WAIT_RX ; 27 goto CONFIRM_STOP ; 28 STOP? LOOK_FOR_STARTbit incf CONTROL_RX, F btfsc SHADOWA, 1 ; Is Pin_RX promedially equal to 0? clrf CONTROL_RX ; nope, look the next time. goto $+1 ; yes, goto the next step in state machine. goto $+1 goto END_RS232 WAIT_RX incf CONTROL_RX, F goto $+1 goto $+1 goto $+1 goto END_RS232 RECEIVE_A_BIT incf CONTROL_RX, F rrf SHADOWA, F rrf SHADOWA, F rrf RX_REG, F goto $+1 nop goto END_RS232 CONFIRM_STOP ; Is stop bit present? If not, clear all and start again. clrf CONTROL_RX btfsc SHADOWA, 1 goto Rx_Ok ; yes, stop bit is present. goto $+1 goto $+1 goto END_RS232 ; ciclo 37 Rx_Ok nop movf RX_REG, W movwf CHAR_RX ; Stores byte received for future use. goto END_RS232 END_RS232 RETURN ;---- End of RS232 routine -------------- ;----------------------------------------- ORG 0x200 READ_KEYBOARD bCf PCLATH,0 bSf PCLATH,1 ; Take care of the annoying PCLATH... _CONVERT_KEY EQU d'13' _WAIT_FOR_RELEASE EQU d'14' _WARNING_TIME EQU d'15' movf CONTROL_KEYBOARD, W addwf PCL, F ; Keyboard state machine. goto KEY_PRESSED? ; 0 goto LOOK_OTHER_LINE ; 1 goto STILL ; 2 goto WE_HAVE_KEY? ; 3 goto LOOK_OTHER_LINE ; 4 goto STILL ; 5 goto WE_HAVE_KEY? ; 6 goto LOOK_OTHER_LINE ; 7 goto STILL ; 8 goto WE_HAVE_KEY? ; 9 goto LOOK_OTHER_LINE ; 10 goto STILL ; 11 goto WE_HAVE_KEY? ; 12 goto CONVERT_KEY ; 13 goto WAIT_FOR_RELEASE ; 14 goto WARNING_TIME ; 15 ;------------------------------------ KEY_PRESSED? clrf PORTB goto $+1 goto $+1 movf PORTB, W xorlw b'11110000' btfsc STATUS, Z ; All "ones"? goto No_Pressed ; yes, neither key pressed. movlw 0x01 ; A "zero" exist! Next step, scan lines. movwf CONTROL_KEYBOARD clrf LINE ; Prepare to scan keyboard... movlw b'11101111' movwf SCAN_PORTB ;-------------------- movlw d'03' call Variable_Wait goto $+1 return No_Pressed clrf CONTROL_KEYBOARD ;------------ movlw d'04' call Variable_Wait goto $+1 return ;---------------------------------------- LOOK_OTHER_LINE incf LINE, F ; Next line to scan... bsf STATUS, C rrf SCAN_PORTB, F ; Put only this line to zero. movf SCAN_PORTB, W movwf PORTB goto $+1 goto $+1 movf PORTB, W ; Catch keys... movwf SCAN_CODE ; Store for next comparison. incf CONTROL_KEYBOARD, F ; Next steps: make a pause, then compare SCAN_CODE. movlw d'18' ; pause of about 5 millisecond (18 passes of the MAIN_LOOP) movwf DELAY_KEYBOARD ;----------- movlw d'03' call Variable_Wait goto $+1 return ;----------------------------------------- STILL decfsz DELAY_KEYBOARD, F ; Is the 18th decrement ? GOTO Still_Waiting incf CONTROL_KEYBOARD, F ; Next step: look what happens ; after this wait. ;------------- Still_Waiting movlw d'07' call Variable_Wait nop return ;----------------------------------------- WE_HAVE_KEY? movf SCAN_PORTB, W movwf PORTB goto $+1 goto $+1 movf PORTB, W xorwf SCAN_CODE, W btfss STATUS, Z goto Not_Coincident1 ; --- Try if only one key is pressed. clrf AUX btfss SCAN_CODE, 7 ; incf AUX, F btfss SCAN_CODE, 6 ; incf AUX, F btfss SCAN_CODE, 5 ; incf AUX, F btfss SCAN_CODE, 4 ; incf AUX, F ; ; Each zero in SCAN_CODE, AUX was incremented. movlw 0x01 ; xorwf AUX, W ; AUX = 1 ? btfss STATUS, Z ; KEY acceptable? goto Not_Coincident2 movlw _CONVERT_KEY ; 24 movwf CONTROL_KEYBOARD ; KEY is good!!! Convert it to ASCII. return Not_Coincident1 ; Reads not match. Go for the next line. incf CONTROL_KEYBOARD, F btfsc LINE, 2 ; The 4th line was scanned? clrf CONTROL_KEYBOARD ; If yes, we no have luck, no valid key... ; If not, go for next line. ;------------------- movlw d'03' call Variable_Wait goto $+1 return Not_Coincident2 ; Trying next LINE. incf CONTROL_KEYBOARD, F btfsc LINE, 2 ; Is the 4th line? clrf CONTROL_KEYBOARD ; if yes, no good keys. Restart. ; if not, go for next line. goto $+1 nop ; This is the most long code segment in READ_KEYBOARD. return ;------------------------------------------------ CONVERT_KEY ; Here we makes the assignment of ASCII values. btfss SCAN_CODE, 4 movlw 0x00 btfss SCAN_CODE, 5 movlw 0x01 btfss SCAN_CODE, 6 movlw 0x02 btfss SCAN_CODE, 7 movlw 0x03 bcf STATUS, C ; Multiply LINE by 4 rlf LINE, F rlf LINE, F addwf LINE, W call ASCII_TABLE MOVWF KEY ; KEY OBTAINED!!! MOVLW _WAIT_FOR_RELEASE ; Wait for the person to loose the key. MOVWF CONTROL_KEYBOARD ;-------------- MOVLW d'01' CALL Variable_Wait RETURN ;------------------------------------------------- WAIT_FOR_RELEASE clrf PORTB goto $+1 goto $+1 movlw 0xF0 xorwf PORTB, W btfss STATUS, Z goto Still_Pressed movlw d'18' movwf DELAY_KEYBOARD ;Wait for 18 MAIN_LOOP passes. movlw _WARNING_TIME movwf CONTROL_KEYBOARD ;-------------- movlw d'04' call Variable_Wait return Still_Pressed ;-------------- movlw d'05' call Variable_Wait return ;------------------------------------------------- WARNING_TIME decfsz DELAY_KEYBOARD, F goto Wait_only_a_few clrf CONTROL_KEYBOARD ; Ready to initiate the keyboard scan again. Wait_only_a_few ;------------- movlw d'07' call Variable_Wait nop return ;---------------------------------------------- ; ----------------- ASCII table: assigns scan-codes with arbitrary ------------ ; ------------------ ASCII's characters. ----------------------------------- ; The 4x4 matrix keyb. has 0 to 9 keys, plus: "HELP" key, "2ND" key, ; up arrow, down arrow , "CANCEL" and "ENTER". ORG 0x300 ASCII_TABLE bsf PCLATH, 0 bsf PCLATH, 1 addwf PCL, F LIN0 ; Error, the count begins with line 1. RETLW "." ; Error characters. RETLW ";" RETLW "-" RETLW "*" LIN1 ; First valid line. retlw "1" retlw "2" retlw "3" retlw "u" ; Up arrow. LIN2 retlw "4" retlw "5" retlw "6" retlw "d" ; Down arrow. LIN3 retlw "7" retlw "8" retlw "9" retlw "N" ; KEY labelled as "2ND" LIN4 retlw "C" ; KEY labelled "CANCEL" retlw "0" retlw "H" ; KEY "HELP" retlw "E" ; KEY "ENTER" END ;********************************************* ; ********* FIN :-) ***************************** ; *********************************************** ;and now in Spanish: ;Archivo: LCDRS232.ASM ; Primera vez que funcionó: 3 de agosto de 2000. ; Autor: Alejandro Lavarello - R.O. del Uruguay ; Contacto: alejol at adinet.com.uy ; Colocado en la PicListLatina el 4/7/00. ; ¡Gracias Norberto por compartir tu código! :) ; Parte del codigo está adaptado de la revista "Electrónica y Computadores" ; editada por CEKIT. ; Para qué sirve esto: ; ==================== ; El PIC16F84 esta conectado a un teclado 4x4 ; y a un conversor TTL / RS232 (el clásico MAX232). ; Cada tecla apretada se envía a un PC que corre ; un emulador de terminal (p. ej., "Hyperterminal") ; y cada caracter recibido se muestra en el módulo LCD. ; La idea es hacer una interfaz para equipos que la requieran... ; Como no se usa el TMR0 ni interrupciones, creo que se puede ; adaptar para un PIC OTP y asi hacerla mas barata. ; Desventajas: ; ============ ; 1) Velocidad de transmision = vel. de recepcion = 1200 baudios (fija) ; 8 bits sin paridad, 1 stop-bit. No hay control de flujo. ; 2) No se puede enviar ni recibir el caracter nulo ( 0 ). ; 3) No se prevee ningun control del display (como borrarlo o posicionar el cursor) ; 4) La comunicacion PIC-display es unidireccional, se podria haber ; conectado el pin R/W a tierra y asi liberar RA3 para algun uso. ; 5) Rechaza dos teclas juntas apretadas. ; Futuras mejoras: ; =============== ; 0) Hacer mas legible el codigo (disculpen...) ; 1) Manejar un modulo LCD de 16 caracteres por 2 líneas. ; 2) Permitir que los bytes recibidos que tienen el MSB a "1" ; (o sea, estan fuera del ASCII) provoquen ciertas acciones, como posicionar ; el cursor, escribir una eñe, etc. ; Ideas basicas: ; ============ ; 1) Usé "código isócrono", o sea, tuve que contar cuantos ciclos de máquina ; demoraba cada rutina y además asegurarme que, en caso de saltos, siempre se ; ejecutaran en el mismo tiempo... por eso agrego algunos "nops" ; o "call DEMORA" y cosas asi. ; ; 2) El BUCLE_PRINCIPAL es "perpetuo" y se ejecuta en 277 microsegundos. ; Esto permite muestrear 3 veces cada bit si se usa transmisión/recepción RS232 ; a 1200 baudios. Se decide el estado (0 o 1) del Pin_RX por mayoría. ; ; 3)La lectura del teclado no permite "auto-repeat" de las teclas: hasta que ; el tipo no suelta la tecla, no se envía otra tecla. ; Notas de hardware: ; ================== ; Se usó como display un modulo LCD modelo JM161A. (1 linea x 16 caracteres) ; Página del fabricante: ; http://www.china-lcd.com/english/eindex.html ; RB0 a RB3 se usan tanto para escanear las lineas del teclado como ; para enviar datos (4 bits) al LCD. ; Los primeros 8 caracteres del display estan en la "linea 1" y los ; otros 8 en la "linea 2" (virtuales, diriamos...) ; Los 8 pines del PORTB tienen en serie Rs de 100 Ohm para protegerlos ; de la estatica. ; El MAX232 tiene su pin 11 conectado a RA1 y su pin 12 a RA0. ; RA4 tiene una R de pull-up de 1k. ; El ajuste de contraste del LCD ( V5 ) se hace con un preset multivuelta ; de 5k. Se consiguio buen contraste con 0,5V en el pin V5 del modulo. ; El nibble bajo ( DB0 a DB3 ) de los datos del LCD se conecto a tierra. ; Ah! Me parece que el registro "BANDERAS" al final no lo usé para nada... LIST P=16F84 ; Uso el viejo y querido PIC16F84 INCLUDE "P16F84.INC" ; Archivo estandar de Microchip con la definicion ; de los registros y los bits con el mismo nombre ; de las hojas de datos, p. ej.: Z es el bit ZERO del registro ; STATUS, etc. __CONFIG _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC ; Palabra de configuracion= 0x11, o sea, ; Proteccion de codigo = OFF, Watchdog = No usado, Power On Timer= Usado, ; Tipo de oscilador= Cristal XT ; Cristal del micro: 4 MHz ; Si se usa otro, ajustar retardos. ; ******************************************** ; **** RAM de usuario ("registros")*********** ; ******************************************** PUNTERO_CHAR EQU 0x0C ; Puntero al caracter a enviar REG_PAUSA EQU 0x0D ; Usado para pausa entre mensajes REG_DATO equ 0x0E ; Mantiene el caracter a enviar REG_1mseg EQU 0x0F ; Usado para retardo de 1 mseg aprox. REG_Varios_ms equ 0x10 ; Usado para dar tiempo al display a iniciarse. SHADOWB EQU 0x11 ; Uso esto para "armar" el dato a escribir en PORTB BANDERAS EQU 0x12 ; Agrupa bits que indican condiciones. PROX_LINEA equ 0x13 TECLA equ 0x14 REG_ESCANEO equ 0x15 ESTADO equ 0x16 CONTROL_TX equ 0x17 ; controla maquina de estados de Tx. CONTROL_RX equ 0x18 ; idem RX CONTROL_TECLADO equ 0x19 ; Idem para manejar la lectura del teclado. TX_REG equ 0x1A ; Caracter a enviar. CHAR_RX equ 0x1B ; Caracter recibido. REG_LOOP equ 0x1C SHADOWA equ 0x1D RX_REG equ 0x1E ; registro auxiliar para armar el caracter que se esta recibiendo. CODIGO_SCAN equ 0x1F ; Valor "en bruto" de la lectura del teclado. AUX equ 0x20 RETARDO_TECLADO equ 0x21 ; ayuda a no hacer nada, esperando por "debounces" y cosas asi. LINEA equ 0x22 BARRE_PORTB equ 0x23 ; determina cual linea pongo a cero. CANT_CARACTERES equ 0x24 ; Indica cuantos caracteres se escribieron al LCD. ; *********** Fin de la definicion de la RAM ****** ; ************************************* ; *** Definicion de bits diversos ***** ; ************************************* E EQU 0x04 ;Conectado a pin "Enable" (especie de clock) ! Pines del Puerto A RS EQU 0x02 ; " a pin "Register Select" ! para control del RW EQU 0x03 ; " a pin "Read/Write" ! modulo. Pin_TX EQU 0x01 ; El pin RA1 es el de salida Rs232.(niveles TTL) Pin_RX EQU 0x00 ; RA0 es entrada RS232.(niveles TTL) Nuevo_Char equ 0x03 ; Este bit se pone a "1" cuando se recibio un byte nuevo. ; ********* Fin de la definicion de bits ***** ; Uso los pines RB0 a RB3 para enviar datos al modulo. (DB4 a DB7) ; ************************************* ; ****** PROGRAMA PRINCIPAL *********** ; ************************************* ORG 0x00 ; Vector de reset . goto INICIO ORG 0x04 ; Vector de interrupcion. No usado. nop ;------------------------------------------------------------------ ORG 0x100 INICIO ; Al prender el micro viene aca primero. ; Microchip recomienda no usar TRIS, pero la verdad es que mantienen esta ; instruccion en toda la linea 16XX. Funciona ok. movlw b'00000000' ; Habilito los pull-ups en PORTB OPTION movlw b'00000001' ; PORTA: Todos salidas salvo RA0. TRIS PORTA movlw b'11110000' ; Port B: nibble bajo salidas TRIS PORTB clrf PORTA ; Solo escribire al LCD. Mantengo siempre RW en bajo CLRF PORTB ; (se podria haber conectado a tierra directamente). bsf PORTA, Pin_TX ; Pongo linea RS232 en estado de reposo. ; ----------------------------------------- ; ** Espera de Power ON ; ----------------------------------------- movlw d'60' ; Esperare unos 60 miliseg antes de hacer nada (espero movwf REG_Varios_ms ; por el lento LCD). RETA_INI call RETARDO decfsz REG_Varios_ms, F goto RETA_INI ; -------Fin de la espera de Power-On ------------- ; --------------------------------------------- ;--------- INICIALIZACION DEL DISPLAY --------- ; --------------------------------------------- ; Necesito 5 pasos para inicializarlo. BEGIN ; Paso 1 movlw 0x02 ; Inicializo a 4 bits. call CONTROL call RETARDO call RETARDO ; Paso 2 movlw b'00101000' ; Inicializo a 4 bits y 2 lineas. call CONTROL ; Nombre de la instruccion: call RETARDO ; "FUNCTION SET" ; Paso 3 movlw b'00001111' ; Display On, cursor On, blink on call CONTROL ; Nombre de la instruccion: call RETARDO ; "DISPLAY ON/OFF CONTROL" ; Paso 4 movlw b'00000110' ; Nombre: "ENTRY MODE SET" call CONTROL ; Direccion de movimiento: hacia la derecha call RETARDO ; Desplazamiento de todo el display: no habilitado. ; Paso 5 movlw b'00000001' ; Nombre de la instruccion: call CONTROL ; "CLEAR DISPLAY". Llena la pantalla de espacios. call RETARDO ; Coloca el puntero de la RAM interna del modulo ("DDRAM") call RETARDO ; apuntando a la posicion 0 (equivale a borrar display y ; despues escribir el byte de control 0x80). call RETARDO ; ; Le toma al menos 1,53 mseg hacer esto. movlw 0x80 ; Apunto a la primera posicion de la DRAM del modulo. call CONTROL ; (por las dudas) call RETARDO ;--------- Inicializacion de las variables clave del bucle principal ---- clrf CONTROL_TX clrf CONTROL_RX clrf CONTROL_TECLADO clrf CANT_CARACTERES movlw ">" ; Enviara esto para avisarle al PC que revivió :) movwf TECLA movlw ":" ; Escibirá esto en la pantallita LCD al encenderlo. movwf CHAR_RX ;---------------------------------------------------------------------- BUCLE_PRINCIPAL call RS232 ; Rutina rx/tx : 39 ciclos call LEER_TECLADO ; Duracion: 2 + 6 + 30 + 2 = 40 ciclos call Escribir_Tecla; Duracion: 2 + 151 = 153 ciclos call Enviar_Tecla ; 2 (call) + 12 = 14 ciclos ; 246 ciclos ;----------------- movlw d'08' call DEMORA ; 28 ciclos ;---------------- nop ; 1 ciclo goto BUCLE_PRINCIPAL ; 2 ciclos ; ******************************************************* ; ******************************************************* RETARDO ; Retardo de algo mas de 1 mseg. clrf REG_1mseg DECRE_1 decfsz REG_1mseg, F goto DECRE_1 RET_230 ; Retardo de 234 usec. movlw d'76' movwf REG_1mseg DECRE_2 decfsz REG_1mseg, F goto DECRE_2 return ;-------------------------------------------- Enviar_Tecla ; Demora 12 ciclos aca. movf CONTROL_TX, F ; control=0 ? (o sea, esta libre para tx?) btfsS STATUS, Z goto No_Enviar_Tecla1 movf TECLA, F ; Tecla vale 0? btfsc STATUS, Z goto No_Enviar_Tecla2 incf CONTROL_TX, F movf TECLA, W movwf TX_REG clrf TECLA ; Consumir la tecla :) return ; 12 ciclos No_Enviar_Tecla1 ; 4 ciclos goto $+1 nop No_Enviar_Tecla2 nop goto $+1 return ; 12 ciclos ;-------------------------------------------- Escribir_Tecla ; Dura: 151 ciclos movf CHAR_RX, W btfss STATUS, Z goto Escribir_char_rx GOTO No_Escribir Escribir_char_rx incf CANT_CARACTERES, F ; ciclo 5 Me fijo cuantos caracteres escribi movlw d'09' xorwf CANT_CARACTERES, W ; ¿sera el noveno caracter? btfsc STATUS, Z goto SEGUNDA_LINEA movlw d'18' xorwf CANT_CARACTERES, W ; ¿sera el decimooctavo? btfsc STATUS, Z goto PRIMERA_LINEA ; hacer "wraparound" o como se pronuncie :) Escribe_LCD ; ciclo 13 movf CHAR_RX, W ; ciclo 14 nop clrf CHAR_RX ; ciclo 16 "Consumo" el caracter recien recibido. goto DATO ;16 + 2(goto) + 133(ejecucion incluido return) = 151 ciclos ; aca termina la escritura del caracter, se usa el return ; de la rutina DATO SEGUNDA_LINEA nop ; ciclo 11 goto $+1 goto $+1 ; ciclo 15 movlw 0xC0 ; ciclo 16 goto CONTROL ; El prox. caracter va en la "2a linea" (virtual) ; Uso el RETURN de la rutina CONTROL. PRIMERA_LINEA clrf CANT_CARACTERES ; ciclo 15 movlw 0x80 ; ciclo 16 goto CONTROL ; El prox caracter va en la "1a. linea" No_Escribir ; 5 ciclos ;----------------- movlw d'46' call DEMORA ; 5 + 1 + 142 = 148 ;------------------- nop return ; 151 ciclos ;----------------------------------------------- ; Demora = 2 (call) + 3*n +2 (return) = 3*n + 4 ; n es el valor que previamente se cargo en W . DEMORA movwf REG_LOOP Repite decfsz REG_LOOP, F goto Repite return ;-------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------- CONTROL ; Recibe un byte en W y lo manda al LCD como caracter de control. ; Tiempo de esta subrutina incluido el return: 133 ciclos bcf PORTA, RS ; Indica que enviara un caracter de control (RS=0) goto $+1 goto DATO2 DATO ; Recibe byte en W y lo manda como un caracter a mostrar. ; Tiempo de esta subrutina incluido el return: 133 ciclos bsf PORTA, RS ; Indica al modulo que enviara un DATO (RS=1) goto $+1 goto DATO2 DATO2 bsf PORTA, E ; ciclo 6 Sube E para que el LCD pueda despues capturar el dato. goto $+1 ; Utiliza la interface a 4 bits ; por eso tiene que partir el dato y ; enviar los dos nibbles. movwf REG_DATO ; Conserva el dato en este registro auxiliar. swapf REG_DATO, W ; Escribo nibble alto. movwf PORTB goto $+1 goto $+1 ; Aca doy el pulso en E. El LCD recien captura los datos en bcf PORTA, E ; el flanco de bajada de su entrada E. goto $+1 goto $+1 bsf PORTA, E ; Vuelvo a subir E para el proximo pulso... ; ciclo 21 ;------------------ movlw d'15' call DEMORA ;------------------ ciclo 70 movf REG_DATO, W ; Escribo nibble bajo. movwf PORTB goto $+1 goto $+1 ; Segundo pulso en E bcf PORTA, E ; Lo captura el modulo... goto $+1 ; Fin del segundo pulso goto $+1 bsf PORTA, E ; ciclo 82 ;------------------ movlw d'15' call DEMORA ;----------------- ciclo 131 return ; ciclo 133 Ya escribio el byte entero en el LCD ;-------------- Fin de la rutina que envia datos de control ;-------------- o bien caracteres al modulo. ;----------------------------------- ORG 0x005 RS232 ; TX clrf PCLATH ; ¡Atenti al PCLATH al hacer saltos calculados! movf CONTROL_TX, W addwf PCL, F goto SALIR_TX ; 0 goto ENVIAR_START ; 1 goto PAUSA_TX ; 2 goto PAUSA_TX ; 3 goto ENVIAR_BIT ; 4 bit 0 goto PAUSA_TX ; 5 goto PAUSA_TX ; 6 goto ENVIAR_BIT ; 7 bit 1 goto PAUSA_TX ; 8 goto PAUSA_TX ; 9 goto ENVIAR_BIT ; 10 bit 2 goto PAUSA_TX ; 11 goto PAUSA_TX ; 12 goto ENVIAR_BIT ; 13 bit 3 goto PAUSA_TX ; 14 goto PAUSA_TX ; 15 goto ENVIAR_BIT ; 16 bit 4 goto PAUSA_TX ; 17 goto PAUSA_TX ; 18 goto ENVIAR_BIT ; 19 bit 5 goto PAUSA_TX ; 20 goto PAUSA_TX ; 21 goto ENVIAR_BIT ; 22 bit 6 goto PAUSA_TX ; 23 goto PAUSA_TX ; 24 goto ENVIAR_BIT ; 25 bit 7 goto PAUSA_TX ; 25 goto PAUSA_TX ; 27 goto ENVIAR_BIT ; 28 STOP BIT goto PAUSA_TX ; 29 goto SALIR_TX ; 30 ENVIAR_START goto $+1 goto $+1 goto $+1 bcf PORTA, Pin_TX goto $+1 incf CONTROL_TX, F goto RX ; ciclo 17 ENVIAR_BIT movf PORTA, W ; Primero armo el byte en SHADOWA.. movwf SHADOWA bcf SHADOWA, Pin_TX btfsc TX_REG, 0 bsf SHADOWA, Pin_TX movf SHADOWA, W movwf PORTA ;...y recien aca mando el bit. bsf STATUS, C ; Desplazo el byte a la derecha.. rrf TX_REG, F incf CONTROL_TX, F goto RX ; ciclo17 PAUSA_TX goto $+1 goto $+1 goto $+1 goto $+1 nop incf CONTROL_TX, F goto RX ; ciclo 17 SALIR_TX goto $+1 goto $+1 goto $+1 goto $+1 nop clrf CONTROL_TX goto RX ; ciclo 17 RX clrf SHADOWA ; Muestreo 3 veces el estado del Pin_RX... btfsc PORTA, Pin_RX incf SHADOWA, F btfsc PORTA, Pin_RX incf SHADOWA, F btfsc PORTA, Pin_RX incf SHADOWA, F ; ...para despues decidir por mayoria (el bit1 ; de SHADOWA será "1" solo si dos o mas muestras valieron uno) movf CONTROL_RX, W addwf PCL, F goto VER_START ; 0 goto VER_START ; 1 goto PAUSA_RX ; 2 goto PAUSA_RX ; 3 goto RECIBE_BIT ; 4 bit 0 goto PAUSA_RX ; 5 goto PAUSA_RX ; 6 goto RECIBE_BIT ; 7 bit 1 goto PAUSA_RX ; 8 goto PAUSA_RX ; 9 goto RECIBE_BIT ; 10 bit 2 goto PAUSA_RX ; 11 goto PAUSA_RX ; 12 goto RECIBE_BIT ; 13 bit 3 goto PAUSA_RX ; 14 goto PAUSA_RX ; 15 goto RECIBE_BIT ; 16 bit 4 goto PAUSA_RX ; 17 goto PAUSA_RX ; 18 goto RECIBE_BIT ; 19 bit 5 goto PAUSA_RX ; 20 goto PAUSA_RX ; 21 goto RECIBE_BIT ; 22 bit 6 goto PAUSA_RX ; 23 goto PAUSA_RX ; 24 goto RECIBE_BIT ; 25 bit 7 goto PAUSA_RX ; 26 goto PAUSA_RX ; 27 goto CONFIRMA_STOP ; 28 STOP? VER_START incf CONTROL_RX, F btfsc SHADOWA, 1 ; ¿vale 0? clrf CONTROL_RX goto $+1 goto $+1 goto SALIR_RS ; ciclo 37 PAUSA_RX incf CONTROL_RX, F goto $+1 goto $+1 goto $+1 goto SALIR_RS ; ciclo 37 RECIBE_BIT incf CONTROL_RX, F rrf SHADOWA, F rrf SHADOWA, F rrf RX_REG, F goto $+1 nop goto SALIR_RS ; ciclo 37 CONFIRMA_STOP clrf CONTROL_RX btfsc SHADOWA, 1 goto Rx_Ok goto $+1 goto $+1 goto SALIR_RS ; ciclo 37 Rx_Ok bsf BANDERAS, Nuevo_Char movf RX_REG, W movwf CHAR_RX goto SALIR_RS ; ciclo 37 SALIR_RS RETURN ; ciclo 39 ;----------------------------------------- ORG 0x200 LEER_TECLADO bCf PCLATH,0 bSf PCLATH,1 ; Acomodo PCLATH para esta pagina... _CONVERTIR_TECLA EQU d'13' _ESPERA_QUE_SUELTE EQU d'14' _TIEMPO_DE_GUARDA EQU d'15' movf CONTROL_TECLADO, W addwf PCL, F goto TECLA_APRETADA? ; 0 goto VER_OTRA_LINEA ; 1 goto ESPERAR ; 2 goto HAY_TECLA? ; 3 goto VER_OTRA_LINEA ; 4 goto ESPERAR ; 5 goto HAY_TECLA? ; 6 goto VER_OTRA_LINEA ; 7 goto ESPERAR ; 8 goto HAY_TECLA? ; 9 goto VER_OTRA_LINEA ; 10 goto ESPERAR ; 11 goto HAY_TECLA? ; 12 goto CONVERTIR_TECLA ; 13 goto ESPERA_QUE_SUELTE ; 14 goto TIEMPO_DE_GUARDA ; 15 ;------------------------------------ TECLA_APRETADA? clrf PORTB goto $+1 goto $+1 movf PORTB, W xorlw b'11110000' btfsc STATUS, Z ; Son todos unos? goto Sin_Apretar ; sip, ninguna apretada. movlw 0x01 ; Lo proximo que hace es empezar a escanear las lineas. movwf CONTROL_TECLADO ;------------------- clrf LINEA ; Se prepara para barrer el teclado movlw b'11101111' movwf BARRE_PORTB ; ciclo 14 ;------------------- movlw d'03' ; Agrega 1 + 13 + 2 = 16 ciclos call DEMORA goto $+1 return Sin_Apretar clrf CONTROL_TECLADO ; ciclo 11 ;------------ movlw d'04' ; Agrega 1 + 16 + 2 call DEMORA goto $+1 return ;---------------------------------------- VER_OTRA_LINEA incf LINEA, F ; Escaneare la linea numero.... bsf STATUS, C ; Seleccionar la linea rrf BARRE_PORTB, F ; movf BARRE_PORTB, W movwf PORTB goto $+1 ; Restaurar goto $+1 ; Restaurar ;movlw b'01010101' ; Remover ;movwf TECLA ; Remover ;goto $+1 ; Remover movf PORTB, W ; Capturo tecla movwf CODIGO_SCAN incf CONTROL_TECLADO, F ; Proximo paso: esperar para luego ver si coinciden. movlw d'18' ; Hare una espera de 1 mseg aprox. movwf RETARDO_TECLADO ; ciclo 14 ;----------- movlw d'03' ; Agrega 1 + 13 + 2 = 16 ciclos call DEMORA goto $+1 return ;----------------------------------------- ESPERAR decfsz RETARDO_TECLADO, F GOTO Seguir_Esperando incf CONTROL_TECLADO, F ;ciclo 3 ; Ver que paso despues de ; la espera ;------------- Seguir_Esperando movlw d'07' ; Introduce 1 + 25 + 1 = 27 ciclos de demora. call DEMORA nop return ;----------------------------------------- HAY_TECLA? movf BARRE_PORTB, W ; 1 movwf PORTB ; 2 goto $+1 ; 4 goto $+1 ; 6 movf PORTB, W ; 7 xorwf CODIGO_SCAN, W ; 8 btfss STATUS, Z ; 10 goto No_Coincide1 ; --- Pruebo si hay solo una tecla apretada clrf AUX ; 11 btfss CODIGO_SCAN, 7 ; 13 incf AUX, F btfss CODIGO_SCAN, 6 ; 15 incf AUX, F btfss CODIGO_SCAN, 5 ; 17 incf AUX, F btfss CODIGO_SCAN, 4 ; 18 incf AUX, F ; 19 movlw 0x01 ; 20 xorwf AUX, W ; 21 btfss STATUS, Z ; 23 Tecla aceptable? goto No_Coincide2 movlw _CONVERTIR_TECLA ; 24 movwf CONTROL_TECLADO ; 25 Tecla buena!!! Transformarla a ASCII. ; Es el segmento de codigo mas largo, lleva 25 ciclos. return No_Coincide1 ; Pruebo la proxima linea. incf CONTROL_TECLADO, F btfsc LINEA, 2 ; ¿Ya reviso la cuarta linea? clrf CONTROL_TECLADO ; ciclo 14 ; Empezar de nuevo, no detecto teclas buenas. ;------------------- movlw d'03' call DEMORA ; agrega 1 + 13 + 2 = 16 ciclos goto $+1 return No_Coincide2 ; Pruebo la proxima linea. incf CONTROL_TECLADO, F btfsc LINEA, 2 ; ¿Ya reviso la cuarta linea? clrf CONTROL_TECLADO ; Empezar de nuevo, no detecto teclas buenas. ; Este es el segmento mas largo de la parte del teclado: 30 ciclos goto $+1 nop return ;------------------------------------------------ CONVERTIR_TECLA ; Aca veo que valor ASCII le asigno al codigo de scan. btfss CODIGO_SCAN, 4 movlw 0x00 btfss CODIGO_SCAN, 5 movlw 0x01 btfss CODIGO_SCAN, 6 movlw 0x02 btfss CODIGO_SCAN, 7 movlw 0x03 bcf STATUS, C ; Multiplico LINEA por 4 rlf LINEA, F rlf LINEA, F addwf LINEA, W call TABLA_ASCII ; ciclo 14 MOVWF TECLA ; OBTUVO LA TECLA!! ciclo 20 MOVLW _ESPERA_QUE_SUELTE ; Esperar que suelte la tecla. MOVWF CONTROL_TECLADO ; ciclo 22 ;-------------- MOVLW d'01' ; Demora: 1 + 7 = 8 ciclos CALL DEMORA RETURN ;------------------------------------------------- ESPERA_QUE_SUELTE clrf PORTB goto $+1 goto $+1 movlw 0xF0 xorwf PORTB, W btfss STATUS, Z goto Sigue_Apretada movlw d'18' movwf RETARDO_TECLADO ; Espero 1 mseg despues que la solto. movlw _TIEMPO_DE_GUARDA movwf CONTROL_TECLADO ; ciclo 13 ;-------------- movlw d'04' ; Demora 1 + 16 = 17 call DEMORA return Sigue_Apretada ;-------------- movlw d'05' ; Demora 1 + 19 = 20 call DEMORA return ;------------------------------------------------- TIEMPO_DE_GUARDA decfsz RETARDO_TECLADO, F goto Espera_otro_poco clrf CONTROL_TECLADO ; ciclo 3 ; Pronto para recibir otra tecla. Espera_otro_poco ;------------- movlw d'07' ; Demora 1 + 25 + 1 = 27 call DEMORA nop return ;---------------------------------------------- ; ----------------- Tabla ASCII ------------ ORG 0x300 TABLA_ASCII bsf PCLATH, 0 bsf PCLATH, 1 addwf PCL, F LIN0 ; Si llego aca hay error RETLW "." ; (cuento las lineas a partir de la 1 ) RETLW ";" RETLW "-" RETLW "*" LIN1 ; Primera linea valida retlw "1" retlw "2" retlw "3" retlw "u" ; Flecha para arriba LIN2 retlw "4" retlw "5" retlw "6" retlw "d" ; Flecha para abajo LIN3 retlw "7" retlw "8" retlw "9" retlw "N" ; Tecla marcada en el teclado como "2ND" LIN4 retlw "C" ; Tecla marcada "CANCEL" retlw "0" retlw "H" ; Tecla "HELP" retlw "E" ; Tecla "ENTER" END ;********************************************* ; ********* FIN ******************************** ; ***********************************************
Interested:
Questions:
See also:
Code:
Comments: