; 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: