please dont rip this site

PIC Microcontoller Input / Ouput Method

PIC Dumb Terminal PIC16F84 + LCD module + Keyboard + RS232 comm

; 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/28 08:59,
TOP NEW HELP FIND: 
18.225.92.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?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://sxlist.com/Techref/microchip/lcdrs232-al.htm"> PIC Dumb Terminal PIC16F84 + LCD module + Keyboard + RS232 comm</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.


Link? Put it here: 
if you want a response, please enter your email address: 
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?

 

Welcome to sxlist.com!


Site supported by
sales, advertizing,
& kind contributors
just like you!

Please don't rip/copy
(here's why

Copies of the site on CD
are available at minimal cost.
 

Welcome to sxlist.com!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  .