; 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 ******************************** ; ***********************************************
See
file: /Techref/microchip/lcdrs232-al.htm, 55KB, , updated: 2010/10/5 02:28, local time: 2024/12/25 16:28,
3.145.55.25:LOG IN
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://massmind.org/techref/microchip/lcdrs232-al.htm"> PIC Dumb Terminal PIC16F84 + LCD module + Keyboard + RS232 comm</A> |
Did you find what you needed? |
Welcome to massmind.org! |
Welcome to massmind.org! |
.