;=====================================================================
;       DOPPIO CONVERTITORE BCD 8421 -> DECIMALE 
;       CON DISPLAY 2 + 2 CIFRE CON USCITE CONDIVISE 
;       versione per PIC16F876
;
;	    di Walter Giocoso
;	    http://digilander.iol.it/wgiocoso
;
;	    compilato con MPLAB IDE 6.20
;
;===================================================================


;   IL TRUCCO DEL DOPPIO DISPLAY SULLE STESSE LINEE DI USCITA
;   
;   I due display vengono attivati alternativamente, numerose volte al 
;   secondo.
;   Il tempo di accensione di ciascuno, dipende dal tempo di esecuzione 
;   delle istruzioni di ricerca nella EEPROM. Poichè in questo esempio 
;   la EEPROM viene letta sequenzialmente, la ricerca della cifra 15
;   impiega molto più tempo della ricerca della cifra 0.
;   In simulazione è stato calcolato che nel peggiore dei casi una cifra
;   rimane accesa circa 80us (microsecondi) e spenta per i successivi 720
;
;     ____                    ____
;    |    |                  |    |
;    |    |__________________|    |____________________
;
;   >|-80-|<------720------->|
;    |<-------800----------->|
;
;   si accende quindi per 1250 volte in un secondo (= 10^6 / 800), per un 
;   tempo totale di 1/10 di secondo (= 80*1250).
;   Poichè il tempo di permanenza dell'immagine nella retina è 
;   approssimativamente 1/16 di secondo, essendo 1/10 > 1/16 l'occhio non
;   dovrebbe notare la manovra
;   I tempi sono stati calcolati nel caso peggiore di clock a 4 MHz
;   sebbene questo valore possa essere innalzato a 20 MHz; occorre precisare,
;   tuttavia, che i tempi di accensione e spegnimento dei display sono 
;   determinati essenzialmente dal numero di accessi in lettura alla EEPROM,
;   e solo in piccola parte dall'esecuzione delle altre istruzioni.




;   PORTE RB0-RB7:  uscite dati del display 7 segmenti
;   PORTA RA0:      abilitazione display 0 e 1 (con negazione per display 0)
;   PORTE RC4-RC7:  ingresso tasti per display 0
;                       pesi: RC7=>8, RC6=>4, RC5=>2, RC4=>1
;   PORTE RC0-RC3:  ingresso tasti per display 1
;                       pesi: RC0=>8, RC1=>4, RC2=>2, RC3=>1   

;
;
;                               PORTB ->76543210                        76543210
;
;                               0 ->    abcdef..    OxFC        10->    abcdef.h    0xFD
;     _____       _____         1 ->    .bc.....    0x60        11->    .bc....h    0x61
;    |     |h   f|  a  |b       2 ->    ab.de.g.    0xDA        12->    ab.de.gh    0xDB
;    |     |     |     |        3 ->    abcd..g.    0xF2        13->    abcd..gh    0xF3
;     -----       -----         4 ->    .bc..fg.    0x66        14->    .bc..fgh    0x67
;    |     |h   e|  g  |c       5 ->    a.cd.fg.    0xB6        15->    a.cd.fgh    0xB7
;    |     |     |     |        6 ->    a.cdefg.    0xBE        
;     -----       -----         7 ->    abc.....    0xE0        NUL->   ........    0x00
;                   d           8 ->    abcdefg.    0xFE
;                               9 ->    abcd.fg.    0xF6
;



        PROCESSOR   16F876
	    __CONFIG    3FF1H
	    RADIX 	    DEC
	    INCLUDE     "P16F876.INC"
	    ERRORLEVEL  -302
	
	
	
        ORG	        110H		            ;prima locazione registri per uso generico
                                            ;nel banco 2
                                            ;   ---------
                                            
                                            ;associazioni tra i pesi e i piedini del PIC
;   A8      EQU         7
;   A4      EQU         6
;   A2      EQU         5
;   A1      EQU         4

;   B8      EQU         0
;   B4      EQU         1
;   B2      EQU         2
;   B1      EQU         3

INGRESSO  RES       1        
INGRESSO0 RES       1    
INGRESSO1 RES       1
CONT    RES         1                   ;variabile di conteggio
DATO    RES         1
DISPLAY RES         1                   ;seleziona display 0 o 1




        ORG         00H                 ;prima locazione area programma
  
        CALL        BANCO1
        MOVLW       00000000B           ;porte B in uscita
        MOVWF       TRISB
        MOVWF       TRISA               ;RA0 in uscita
        MOVLW       11111111B           ;porte C in ingresso
        MOVWF       TRISC  
        GOTO        MAIN  
                            ;NOTA IMPORTANTE
                            ;---------------
                            ;Le seguenti definizioni dei banchi facilita notevolmente 
                            ;sia la programmazione che la leggibilità del sorgente, 
                            ;ma ha alcuni inconvenienti:
                            ;1) esecuzione più lenta: si eseguono sempre 4 istruzioni
                            ;   (CALL-RP1-RP0-RETURN) al posto di 1 o 2
                            ;2) codice eseguibile meno compatto e ridondante:
                            ;   se si passa dal banco 0 (RP1=0, RP0=0) al banco1
                            ;   (RP1=0, RP0=1) è totalmente inutile effettuare il CLEAR
                            ;   di RP1
                            ;Una volta testato il programma, sarebbe quindi opportuno
                            ;sostituire le CALL con le relative istruzioni ed eliminare
                            ;le ridondanze 
BANCO0        
        BCF         STATUS, RP1
        BCF         STATUS, RP0
        RETURN
        
BANCO1
        BCF         STATUS, RP1
        BSF         STATUS, RP0
        RETURN
        
BANCO2
        BSF         STATUS, RP1
        BCF         STATUS, RP0
        RETURN
        
BANCO3
        BSF         STATUS, RP1
        BSF         STATUS, RP0
        RETURN                        


        


;######################################################################################
MAIN
        CALL        TABELLA             ;creazione tabella di conversione nella EEPROM
NUOVO        
        CALL        LEGGI0              ;leggi ingresso per display 0
        CALL        AZZERA              ;azzera contatore        
        CALL        CERCA               ;cerca corrispondenza in tabella
        MOVLW       0
        MOVWF       DISPLAY             ;seleziona display 0 in uscita
        CALL        STAMPA              ;stampa cifra sul display 0
        CALL        LEGGI1              ;leggi ingresso per display 1
        CALL        AZZERA              ;azzera contatore        
        CALL        CERCA               ;cerca corrispondenza in tabella
        MOVLW       1
        MOVWF       DISPLAY             ;seleziona display 1 in uscita
        CALL        STAMPA              ;stampa cifra sul display 1
        GOTO        NUOVO

;######################################################################################




;-------------------------------------------------------------------------------------
STAMPA
                                        ;in questo istante la variabile CONT contiene
                                        ;il numero della posizione della tabella
                                        ;in cui è stato trovato il dato.
                                        ;CONT+16 conterrà la corrispondente codifica
                                        ;del display
        CALL        BANCO2
        MOVLW       16
        ADDWF       CONT,   1           ;CONT := CONT+16                                        
        CALL        LEGGI_EE            ;leggi contenuto della EEPROM all'indirizzo CONT
                                        ;   il risultato si troverà nel registro W
        MOVWF       DATO
                                        ;azzeramento dei display per evitare cifre
        MOVLW       00H                 ;di transizione
        CALL        BANCO0
        MOVWF       PORTB
        
        CALL        BANCO2        
        MOVF        DISPLAY,0        
        CALL        BANCO0
        MOVWF       PORTA
        CALL        BANCO2
        MOVF        DATO,   0
        CALL        BANCO0
        MOVWF       PORTB

        RETURN




;-------------------------------------------------------------------------------------
CERCA
        CALL        LEGGI_EE            ;restituisce il contenuto della cella in "DATO"
                                        ;banco selezionato: 2
        MOVF        DATO,   0           ;copia DATO in W
        SUBWF       INGRESSO,0          ;confronta combinazione di ingresso con DATO tabella
        BTFSS       STATUS, Z           ;se DATO==INGRESSO termina ricerca
        GOTO        PROSEGUI            ;altrimenti prosegui
        GOTO        FINE_RICERCA
PROSEGUI
        INCF        CONT,   1
        GOTO        CERCA

FINE_RICERCA        
        RETURN
                
        
        
;----------------------------------------------------------------------------------
AZZERA                                   
        MOVLW       0
        MOVWF       CONT                ;cont:=0

        RETURN




;----------------------------------------------------------------------------------        
LEGGI_EE
        CALL        BANCO2
        MOVF        CONT,   0           ;W:=CONT        
        MOVWF       EEADR
        CALL        BANCO3
        BCF         EECON1, EEPGD       ;punta all'area dati della EEPROM 
        BSF         EECON1, RD          ;abilita lettura
TEST_RD                                 ;attendi completamento lettura
        BTFSC       EECON1, RD
        GOTO        TEST_RD        

        CALL        BANCO2
        MOVF        EEDATA, 0           ;il dato è adesso in W
        MOVWF       DATO                ;dato:=W
        
        RETURN       






;----------------------------------------------------------------------------------------
LEGGI0
        CALL        BANCO0
        MOVF        PORTC,  0           ;copia PORTC su W
        CALL        BANCO2
        MOVWF       INGRESSO0
                                        ;partendo da        INGRESSO0=dddd????
                                        ;vogliamo ottenere  INGRESSO0=0000dddd

        SWAPF       INGRESSO0,0         ;W = ????dddd
        ANDLW       00001111B           ;W = 0000dddd
        MOVWF       INGRESSO            ;INGRESSO := W
        RETURN






;----------------------------------------------------------------------------------------
LEGGI1
        CALL        BANCO2
        MOVLW       00H
        MOVWF       INGRESSO1
        CALL        BANCO0
        MOVF        PORTC,  0           ;copia PORTC su W
        CALL        BANCO2
        MOVWF       DATO                ;DATO è attualmente inutilizzata
                                        ;partendo da        DATO = ????abcd
                                        ;vogliamo ottenere  INGRESSO=0000dcba

;INVERTI                                ;DATO = ????abcd
        BTFSC       DATO,   0
        BSF         INGRESSO1,3         ;INGRESSO1 = 0000d000
        BTFSC       DATO,   1
        BSF         INGRESSO1,2         ;INGRESSO1 = 0000dc00
        BTFSC       DATO,   2
        BSF         INGRESSO1,1         ;INGRESSO1 = 0000dcb0
        BTFSC       DATO,   3
        BSF         INGRESSO1,0         ;INGRESSO1 = 0000dcba
        MOVF        INGRESSO1,0         ;W := INGRESSO1
        MOVWF       INGRESSO            ;INGRESSO := W
        RETURN





;----------------------------------------------------------------------------------------
TABELLA                                 ;scrittura della tabella di conversione su EEPROM
                                        ;negli indirizzi da 0 a 15 sono contenuti 
                                        ;i valori in BCD 8421 delle cifre decimali
                                        ;corrispondenti agli indirizzi stessi
                                        ;all'indirizzo n+16 troviamo i segmenti del display
                                        ;che si devono illuminare in corrispondenza del 
                                        ;decimale n


                                        ;verifica dell'esistenza della tabella nella EEPROM
                                        ;   tramite controllo di due locazioni di memoria
                                        ;--------------------------------------------------

        CALL        BANCO2
        MOVLW       5
        MOVWF       CONT
        CALL        LEGGI_EE            ;il dato viene restituito in DATO; banco attivo: 2
        MOVLW       5
        SUBWF       DATO,   0
        BTFSS       STATUS, Z
        GOTO        COMPILA_TAB         ;ricompila tabella se i dati sono diversi (Z==0)
        MOVLW       30
        MOVWF       CONT
        CALL        LEGGI_EE            
        MOVLW       01100111B
        SUBWF       DATO,   0
        BTFSC       STATUS, Z
        GOTO        FINE_TAB            ;non ricompilare tabella se i due confronti sono 
                                        ;corretti (Z==1)
                                        
COMPILA_TAB        
        MOVLW       0                   ;codifica BCD 8421 del decimale 0
        MOVWF       EEADR
        MOVLW       0000B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE           ;scrive sulla EEPROM e restituisce banco 2
        MOVLW       1                   ;codifica BCD 8421 del decimale 1
        MOVWF       EEADR
        MOVLW       0001B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       2                   ;codifica BCD 8421 del decimale 2
        MOVWF       EEADR
        MOVLW       0010B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       3                   ; . . .
        MOVWF       EEADR
        MOVLW       0011B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       4
        MOVWF       EEADR
        MOVLW       0100B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       5
        MOVWF       EEADR
        MOVLW       0101B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       6
        MOVWF       EEADR
        MOVLW       0110B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       7
        MOVWF       EEADR
        MOVLW       0111B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       8
        MOVWF       EEADR
        MOVLW       1000B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       9
        MOVWF       EEADR
        MOVLW       1001B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       10
        MOVWF       EEADR
        MOVLW       1010B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       11
        MOVWF       EEADR
        MOVLW       1011B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       12
        MOVWF       EEADR
        MOVLW       1100B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       13
        MOVWF       EEADR
        MOVLW       1101B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       14
        MOVWF       EEADR
        MOVLW       1110B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       15
        MOVWF       EEADR
        MOVLW       1111B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        

        MOVLW       16                      ;codifica cifra 0 (=16-16)
        MOVWF       EEADR
        MOVLW       11111100B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       17                      ;codifica cifra 1 (=17-16)
        MOVWF       EEADR
        MOVLW       01100000B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       18                      ;codifica cifra 2 (=18-16)
        MOVWF       EEADR
        MOVLW       11011010B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       19                      ; . . .
        MOVWF       EEADR
        MOVLW       11110010B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       20
        MOVWF       EEADR
        MOVLW       01100110B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       21
        MOVWF       EEADR
        MOVLW       10110110B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       22
        MOVWF       EEADR
        MOVLW       10111110B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       23
        MOVWF       EEADR
        MOVLW       11100000B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       24
        MOVWF       EEADR
        MOVLW       11111110B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       25
        MOVWF       EEADR
        MOVLW       11110110B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       26
        MOVWF       EEADR
        MOVLW       11111101B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       27
        MOVWF       EEADR
        MOVLW       01100001B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       28
        MOVWF       EEADR
        MOVLW       11011011B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       29
        MOVWF       EEADR
        MOVLW       11110011B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       30
        MOVWF       EEADR
        MOVLW       01100111B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE
        MOVLW       31
        MOVWF       EEADR
        MOVLW       10110111B
        MOVWF       EEDATA 
        CALL        SCRIVI_EE

        CALL        BANCO3        BCF         EECON1, WREN        ;disabilita accesso in scrittura sulla EEPROM
FINE_TAB
;           CALL        BANCO0
;     	    MOVLW       00000010B
;	        MOVWF       PORTB               ;pronto a ricevere ingresso
	                                        ;utile nella simulazione per indicare il 
	                                        ;completamento della scrittura tabella
        RETURN






;------------------------------------------------------------------------
SCRIVI_EE
        CALL        BANCO3
        BSF         EECON1, WREN        ;abilita scrittura su EEPROM
        MOVLW       55H                 ;elimina  protezione in scrittura
        MOVWF       EECON2
        MOVLW       0xAA
        MOVWF       EECON2
        BSF         EECON1, WR          ;scrivi    
TEST_WR                                 ;attendi avvenuta scrittura
        BTFSC       EECON1, WR
        GOTO        TEST_WR      
        BCF         EECON1, EEIF        ;azzera FLAG di conferma scrittura
        CALL        BANCO2
        
        RETURN
;------------------------------------------------------------------------               




        
        END
        
        
