; 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 03:28, local time: 2025/10/28 15:47,
216.73.216.22,10-3-83-201:LOG IN
|
| ©2025 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://www.piclist.com/Techref/microchip/lcdrs232-al.htm"> PIC Dumb Terminal PIC16F84 + LCD module + Keyboard + RS232 comm</A> |
| Did you find what you needed? |
|
o List host: MIT, Site host massmind.org, Top posters @none found - Page Editors: James Newton, David Cary, and YOU! * Roman Black of Black Robotics donates from sales of Linistep stepper controller kits. * Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters. * Monthly Subscribers: Gregg Rew. on-going support is MOST appreciated! * Contributors: Richard Seriani, Sr. |
|
The Backwoods Guide to Computer Lingo |
.