;************************************************************************
; LIGHGAME.ASM Rev.4
; Autore: Sasa
; 30/10/2004
; Genera effetti luminosi (sia On-Off che in dissolvenza) su 8 lampadine
; a filamento collegate ai corrispondenti canali.
; Sono disponibili effetti a 4 e a 8 lampade.

; FUNZIONI CIRCUITO
; - Impostazione velocità giochi: Mantenere premuto il pulsante tempo (P_TIME) per variare
;   il tempo di esecuzione degli effetti da un minimo ad un massimo.
;   La velocità impostata del tempo è segnalata dalla velocità di lampeggio del led TIME

; - Cambio gioco: Premere il pulsante gioco (P_GAME) e rilasciarlo.
;   Verranno eseguiti in ordine:
;   - i 33 giochi di tipo on-off (lampade accese o spente)
;   - i 15 giochi di tipo dissolvenza (variazione di luminosità delle lampade)
;   - mix dei giochi di tipo on-off
;   - mix dei giochi di tipo dissolvenza
;   - mix di tutti i giochi
;   Durante l'esecuzione di una miscelazione di giochi si accenderà il led LEDGMIX

; - Salvataggio impostazioni (gioco e velocità) per ripristino all'accensione:
;   Premere il pulsante P_GAME e successivamente P_TIME.
;   Al rilascio di entrambi i pulsanti, le lampade si spegneranno e i due led lampeggeranno
;   per tre volte ad indicare l'avvenuta memorizzazione.
;   Alla riaccensione il circuito eseguirà sempre l'ultimo gioco che è stato memorizzato.

; - Ripristino impostazioni di default (gioco e velocità): Premere il pulsante P_TIME e 
;   successivamente il pulsante RESET (o alimentare il circuito). Rilasciare P_TIME
;   quando i due led lampeggeranno per tre volte ad indicare l'avvenuta memorizzazione.
;   Verrà ripristinato il primo gioco alla massima velocità di esecuzione.

; E'stato utilizzato un quarzo da 4 MHz.

;************************************************************************

        PROCESSOR       16F84                   ;Tipo di processore
        RADIX           DEC                     ;decimali senza notaz.
        INCLUDE         "PIC16F84.INC"          ;inclusione File .inc
        ERRORLEVEL      -302
        __CONFIG        3FF5H                   ;Nessuna protezione codice
                                                ;Watch-dog abilitato
                                                ;Power Up abilitato
                                                ;Oscillatore tipo XT
;************************************************************************
;Dichiarazione costanti utilizzate dal compilatore
LP_1      EQU   0               ;Numero portaA associata Lampada 1
LP_2      EQU   1               ;Numero portaB associata Lampada 2
LP_3      EQU   2               ;Numero portaB associata Lampada 3
LP_4      EQU   3               ;Numero portaB associata Lampada 4
LP_5      EQU   4               ;Numero portaB associata Lampada 5
LP_6      EQU   5               ;Numero portaB associata Lampada 6
LP_7      EQU   6               ;Numero portaB associata Lampada 7
LP_8      EQU   7               ;Numero portaB associata Lampada 8

LEDTIME   EQU   1               ;Numero portaA associata al Led TIME
LEDGMIX   EQU   2               ;Numero portaA associata al Led Mix Giochi
P_TIME    EQU   3               ;Numero portaA associata al pulsante TIME
P_GAME    EQU   4               ;Numero portaA associata al pulsante GAME

MAXGONOFF EQU	32		;Numero giochi di tipo ON-OFF (0..32 = 33 giochi on-off)
MAXGAMES  EQU	47		;Numero di giochi totali      (0..47 = 48 giochi totali)

MINTIME	  EQU	5		;Valore minimo variabile per ritardo (Time)
MAXTIME	  EQU	100		;Valore massimo variabile per ritardo (Time)

ONOFFMIX  EQU   4               ;Numero di ripetizioni del singolo gioco di tipo on-off
                                ;durante il mix giochi

;************************************************************************
;Dichiarazione variabili in area dati (0C=locazione di partenza RAM)
          ORG   0CH
Light1    RES   1               ;Luminosità Uscita LP_1: 0=spenta..127=massima
Light2    RES   1               ;Luminosità Uscita LP_2: 0=spenta..127=massima
Light3    RES   1               ;Luminosità Uscita LP_3: 0=spenta..127=massima
Light4    RES   1               ;Luminosità Uscita LP_4: 0=spenta..127=massima
Light5    RES   1               ;Luminosità Uscita LP_5: 0=spenta..127=massima
Light6    RES   1               ;Luminosità Uscita LP_6: 0=spenta..127=massima
Light7    RES   1               ;Luminosità Uscita LP_7: 0=spenta..127=massima
Light8    RES   1               ;Luminosità Uscita LP_8: 0=spenta..127=massima

CntZero   RES   1	        ;Attesa 100uS in Rbo_Int dal fronte
                                ;positivo di RB0 (Frequenza rete 50x2=100Hz)
Cnt_Lp    RES   1               ;Contatore ritardo conduzione triac. Viene
                                ;decrementata in Tim-Int da 127 a 0

                                ;3 VARIABILI PER IMPOSTAZIONE SETTAGGI
Time	  RES	1		;Impostazione per ritardo effetto
Game	  RES	1		;Numero del gioco selezionato (0..47)
MixGame	  RES	1		;Attivazione Mix Giochi 0=Nessun mix, 1=Mix On-off
				;2=Mix Dissolvenza, 3=Mix tutti giochi

StGame	  RES	1		;Locazione ROM di partenza del gioco
LenGame	  RES	1		;Lunghezza delle sequenze del gioco

SeqOnOff  RES	1		;Singola sequenza del gioco di tipo on-off
CntOnOff  RES   1               ;Contatore per eseguire più volte lo stesso gioco
                                ;di tipo on-off durante il mix giochi on-off

CntLight  RES	1		;Contatore per scrittura var. Light1..Light8

Reg_Up	  RES	1		;Registro UP per giochi dissolvenza
Reg_Dn	  RES	1		;Registro DOWN per giochi dissolvenza

LightUp	  RES	1		;Contatore per luminosità crescente
LightDn	  RES	1		;Contatore per luminosità decrescente

Cnt_Del   RES   3               ;3 Contatori per ritardi

Cnt_Eep   RES   1               ;Contatore per Lettura e scrittura variabili Eeprom

W_Temp    RES   1               ;Salvataggio registro W durante Interrupt
St_Temp   RES   1               ;Salvataggio registro STATUS durante Interrupt

;************************************************************************
;Inizio memoria programma (locazione 00)
        ORG     00H
        goto    start

;*********************************************************************
;Interrupt handler. Possono essere generati due tipi di interrupt:
; -Porta RB0: Generato ogni volta che il segnale di zero-crossing (passaggio
;  sullo zero della tensione sinosoidale ogni 10 mS) passa da 0 a 1.
;  Inizializza il contatore Cnt_Lp e pone a zero l'uscita delle lampade.
; -TIMER: Utilizzato per decrementare ogni 78 uS la variabile Cnt_Lp e per
;  pilotare i triac in ritardo rispetto al passaggio sullo zero quando si
;  verifica la condizione VALORE_LAMPADINA>=Cnt_Lp.
;Alla fine dell'interrupt viene eseguita end_ih.
        ORG     04H
        movwf   W_Temp          ;Salvataggio registro W in W_Temp
        swapf   STATUS,W        ;Salvataggio registro STATUS in St_Temp
        movwf   St_Temp

;       clrwdt                  ;Azzera il watch-dog (spostato in rbo_int, ogni 10mS)
        btfsc   INTCON,INTF     ;Verifica se generato l'Interrupt su RB0
        goto    rb0_int         ;Salta a Rb0 Interrupt se INTF=1
        goto    tim_int         ;Salta a Timer Interrupt se INTF=0

end_ih  swapf   St_Temp,W       ;Riprisino registro STATUS
        movwf   STATUS
        swapf   W_Temp,F        ;Ripristino registro W
        swapf   W_Temp,W
        retfie

;*** Interrupt Timer ***
;Questo interrupt si genera quando il registro TMR0, continuamente incre-
;mentato ogni 2 uS, arriva a 0. E'utilizzata per decrementare da 127 a 0 la
;variabile Cnt_Lp che stabilisce i 'passi' del ritardo di conduzione del
;triac rispetto al passaggio sullo zero della tensione sinosoidale.
;Inoltre pone a 1 le uscite delle lampade quando VALORE_LAMPADA>=Cnt_Lp.
;Il triac rimarrà in conduzione fino al prossimo passaggio sullo zero.
tim_int movlw   224             ;Ricarica TMR0 per far eseguire tim_int
        movwf   TMR0            ;ogni 78 uS (comprese le istruzioni
			        ;precedenti di scelta interrupt).

        movf    Cnt_Lp,w        ;Lampada Uscita 1
        subwf   Light1,w        ;w = Light1 - Cnt_Lp
        btfsc   STATUS,C        ;Se Light1<Cnt_Lp salta prossima istruzione
        bsf     PORTA,LP_1      ;Porta in conduzione il triac che pilota la
                                ;lampadina LP_1 in ritardo rispetto allo 0

        movf    Cnt_Lp,w        ;Lampada Uscita 2
        subwf   Light2,w
        btfsc   STATUS,C
        bsf     PORTB,LP_2

        movf    Cnt_Lp,w        ;Lampada Uscita 3
        subwf   Light3,w
        btfsc   STATUS,C
        bsf     PORTB,LP_3

        movf    Cnt_Lp,w        ;Lampada Uscita 4
        subwf   Light4,w
        btfsc   STATUS,C
        bsf     PORTB,LP_4

        movf    Cnt_Lp,w        ;Lampada Uscita 5
        subwf   Light5,w
        btfsc   STATUS,C
        bsf     PORTB,LP_5

        movf    Cnt_Lp,w        ;Lampada Uscita 6
        subwf   Light6,w
        btfsc   STATUS,C
        bsf     PORTB,LP_6

        movf    Cnt_Lp,w        ;Lampada Uscita 7
        subwf   Light7,w
        btfsc   STATUS,C
        bsf     PORTB,LP_7

        movf    Cnt_Lp,w        ;Lampada Uscita 8
        subwf   Light8,w
        btfsc   STATUS,C
        bsf     PORTB,LP_8

        movf    Cnt_Lp,f        ;Se Cnt_Lp<>0 decrementa Cnt_Lp
        btfss   STATUS,Z        ;Salta prossima se Cnt_Lp=0
        decf    Cnt_Lp,f        ;Decrementa Cnt_Lp

        bcf     INTCON,T0IF     ;Riabilita interrupt su TMR0
        goto    end_ih


;*** Interrupt RB0 ***
;Eseguito ogni 10mS
;Questo interrupt è generato quando l'ingresso RB0 passa da 0 a 1 in presenza
;dello 'zero' della tensione sinosoidale di rete. Serve a porre a 0 le uscite
;degli 8 triac associati alle lampade e a inizializzare la variabile Cnt_Lp.

rb0_int clrwdt                  ;Azzera il watch-dog ogni 10mS (100Hz). Se non si genera
                                ;questo interrupt entro 18mS resetta la cpu.
        bcf     PORTA,LP_1      ;Pone a 0 le uscite dei triac per le 8 Lampade
	movf	PORTB,w         ;RA0, RB1...RB7
	andlw	00000001B
	movwf	PORTB

        movlw   127             ;Inizializza Cnt_Lp a 127
        movwf   Cnt_Lp

  	movlw   66		;Attesa 200uS per non far eseguire tim_int
	movwf   CntZero	  	;(generazione passi) prima che la tensione
w_zero  decfsz  CntZero,f	;sinosoidale arrivi realmente a zero.
	goto    w_zero

        bcf     INTCON,INTF     ;Riabilita interrupt su RB0
        goto    end_ih


;*****************************************************
;Programma PRINCIPALE

;Configurazione porte I/O (0=Out 1=In) e settaggio interrupt e prescaler
start   bsf     STATUS,RP0      ;Banco memoria 1

        movlw   11111000B       ;Configurazione Porta A
        movwf   TRISA           ;RA0: uscita Lampada 1
                                ;RA1: uscita Led Time
                                ;RA2: uscita Led Mix Giochi
                                ;RA3: ingresso pulsante TIME
                                ;RA4: ingresso pulsante GAME
                                ;RA5,RA6,RA7: non presenti

        movlw   00000001B       ;Configurazione Porta B
        movwf   TRISB           ;RB0: ingresso zero crossing tensione rete
                                ;RB1: uscita Lampada 2
                                ;RB2: uscita Lampada 3
                                ;RB3: uscita Lampada 4
                                ;RB4: uscita Lampada 5
                                ;RB5: uscita Lampada 6
                                ;RB6: uscita Lampada 7
                                ;RB7: uscita Lampada 8

        movlw   01000000B       ;bit7: Attiva circuiteria weak-up ingressi
        movwf   OPTION_REG      ;bit6: Attiva interrupt RB0 su fronte salita
                                ;bit5: Ingresso prescaler a fOsc/4 (1 MHz)
                                ;bit3: Ingresso registro TMR0 a Prescaler
                                ;bit2,1,0: Divisione prescaler 2 volte
                                ;Frequenza uscita prescaler = 500000 Hz

        bcf     STATUS,RP0      ;Banco memoria 0

        call    lightled_off    ;Inizializza a 0 i valori luminosità e spegne i due led
        clrf    CntOnOff        ;Inizializza contatore mix on-off

        call    del_05s         ;Attesa 0,5 secondi

        btfsc   PORTA,P_TIME    ;Verifica se premuto PTIME per impostare i valori default
        goto    main2           ;No, salta

main1   movlw   MINTIME         ;Imposta i valori di default: tempo minimo, gioco 1, no mix
        movwf   Time
        clrf    Game
        clrf    MixGame
        goto    main5           ;Salva su Eeprom i valori di default

main2   call    read_eeprom     ;Legge e verifica i valori di impostazione dalla EEprom
        xorlw   0x01            ;restituisce w=0 se corretti, w=1 non corretti
        btfsc   STATUS,Z
        goto    main1           ;Valori errati. Imposta quelli di default

        movlw   10110000B       ;Abilita Interrupt su Timer e su porta RB0
        movwf   INTCON

mainloop                        ;Loop principale eseguito all'inizio di ogni gioco

        call    verify_mixgame  ;Verifica se selezionato Mix Giochi per incremento
                                ;automatico del gioco

	call	getinfogame	;Recupera dalla tabella TBL_INFO le variabili
				;StGame e LenGame relative alle info del gioco selezionato

        movf    Game,w          ;Verifica se il gioco è di tipo On-Off o Dissolvenza
        sublw   MAXGONOFF
        btfss   STATUS,C        ;Salta prossima se MAXGONOFF-Game >= 0 (giochi on-off)
        goto    main3

        call    getonoffgame    ;Genera l'intera sequenza di effetti luminosi di tipo On-Off
        goto    main4           ;relativi ad un unico gioco (stabilito dalla var. Game)
                                ;Ritorna in w tre valori:
                                ;- w=0 Fine gioco. Inizia daccapo dalla prima sequenza
                                ;- w=1 Premuto pulsante P_GAME per prossimo gioco
                                ;- w=2 Premuti pulsanti P_GAME+P_TIME per salvare impostaz.

main3   call    getdissgame     ;Genera l'intera sequenza di effetti luminosi di tipo Dissolvenza
                                ;relativi ad un unico gioco (stabilito dalla var. Game)
                                ;Ritorna in w tre valori:
                                ;- w=0 Fine gioco. Inizia daccapo dalla prima sequenza
                                ;- w=1 Premuto pulsante P_GAME per prossimo gioco
                                ;- w=2 Premuti pulsanti P_GAME+P_TIME per salvare impostaz.

main4   xorlw   0x02            ;Verifica se w=2 (salvataggio impostazioni sulla EEPROM)
	btfss	STATUS,Z
        goto    mainloop        ;No, ritorna al loop principale

                                ;Salva le impostazioni sulla memoria EEPROM
        clrf    INTCON          ;Disabilita tutti gli interrupt
        call    lightled_off    ;Spegne le 8 lampade e i due led di segnalazione

main5   call    write_eeprom    ;Salva le variabili Time, Game e MixGame

        call    del_05s         ;Accende/Spegne i due led di segnalazione ad intervalli
        bcf     PORTA,LEDGMIX   ;di 0,5 secondi per indicare l'avvenuto salvataggio
        bcf     PORTA,LEDTIME
        call    del_01s
        bsf     PORTA,LEDGMIX
        bsf     PORTA,LEDTIME
        call    del_05s
        bcf     PORTA,LEDGMIX
        bcf     PORTA,LEDTIME
        call    del_01s
        bsf     PORTA,LEDGMIX
        bsf     PORTA,LEDTIME
        call    del_05s
        bcf     PORTA,LEDGMIX
        bcf     PORTA,LEDTIME
        call    del_01s
        bsf     PORTA,LEDGMIX
        bsf     PORTA,LEDTIME
        goto    start           ;Salta dall'inizio del programma


;*****************************************************
;Recupera dalla tabella TBL_INFO le variabili:
; - StGame:  Locazione Rom inizio gioco
; - LenGame: Lunghezza (numero byte) del gioco
;In TBL_INFO i valori sono inseriti in successione come dall'esempio:
;	StGame   Gioco1		0
;	LenGame	 Gioco1         1  <-- Offset
;	StGame   Gioco2         2
;	LenGame  Gioco2         3
;	StGame   Gioco3         4
;	LenGame	 Gioco3         5
;	....                    ..

getinfogame
	movlw	0x03  		;Tabella TBL_INFO in pagina 3
	movwf	PCLATH
	bcf	STATUS,C        ;Moltiplica Game*2 per prelevare StGame
	rlf	Game,w
	call	TBL_INFO	;Richiama tabella
	movwf	StGame          ;e preleva valore StGame

	movlw	0x03  		;Tabella TBL_INFO in pagina 3
	movwf	PCLATH
	bcf	STATUS,C        ;Effettua Game*2+1 per prelevare LenGame
	rlf	Game,w
	addlw	0x01
	call	TBL_INFO	;Richiama tabella
	movwf	LenGame         ;e preleva valore LenGame
	return


;*****************************************************
;Giochi di tipo ON-OFF
;Recupera in successione le sequenze (byte) del gioco selezionato
;dalla tabella TBL_ONOFF e carica in Light1..Light8 i valori
;per far accendere/spegnere le luci come nell'esempio.

;SeqOnOff [bit(0..7)]=1 --> Light(1..8)=127
;SeqOnOff [bit(0..7)]=0 --> Light(1..8)=0

;Esegue il ritardo fra due sequenze all'interno del quale la sub pulse_led
;fà lampeggiare il led e controlla la pressione dei pulsanti.
;Eseguendo la sub, le var. StGame e LenGame vengono modificate e quindi al
;termine del gioco devono essere prelevate nuovamente da TBL_INFO (sub getinfogame)

getonoffgame
	movlw	0x02		;Preleva la sequenza del gioco selezionato
	movwf	PCLATH          ;(SeqOnOff) dalla tabella TBL_ONOFF (pagina 2)
	movf	StGame,w
	call	TBL_ONOFF
	movwf	SeqOnOff	;Carica in SeqOnOff la sequenza del gioco On-Off

	movlw	0x08		;8 bit da prelevare in SeqOnOff
	movwf	CntLight
	movlw	Light1		;Carica indirizzo di Light1 nel puntatore
	movwf	FSR
gonof_1	btfss	SeqOnOff,0	;Verifica se il singolo bit di SeqOnOff è 0 o 1
	goto	gonof_2
	movlw	127
	movwf	INDF		;Variabile puntata (Light1..8) = 127
	goto	gonof_3
gonof_2	clrf	INDF		;Variabile puntata (Light1..8) = 0
gonof_3	rrf	SeqOnOff,f	;Ruota SeqOnOff verso destra
	incf	FSR,f		;Incrementa puntatore
	decfsz	CntLight,f	;Decrementa contatore
	goto	gonof_1

        call	delay_ms	;Ritardo fra due sequenze (mS)

	call	pulse_led	;Fà lampeggiare il led TIME e controlla i pulsanti
				;Ritorna in w tre possibili valori:
				;0=Continua, 1=Prossimo gioco, 2=Salva Impostaz.

	movwf	CntLight	;Verifica il valore contenuto in w (0,1,2)
        movf    CntLight,w
        btfsc	STATUS,Z
        goto    gonof_5         ;Prosegue se w=0
        xorlw   0x01
        btfsc   STATUS,Z
        retlw   0x01            ;Se w=1 esce con w=1 (Prossimo gioco)
	retlw	0x02		;Se w=2 esce con w=2 (Salva impostazioni)


gonof_5	incf	StGame,f	;Incrementa locazione per prossima sequenza
	decfsz	LenGame,f	;Decrementa e verifica se ultima sequenza gioco
	goto	getonoffgame	;No, preleva prossima sequenza
	retlw	0x00		;Raggiunta ultima sequenza del gioco. Esce con w=0


;*****************************************************
;Giochi di tipo DISSOLVENZA
;Recupera in successione i valori Reg_Up e Reg_Dn dalla tabella TBL_DISS (relativi al
;gioco selezionato) e, in base alle 4 combinazioni bit-bit genera gli effetti
;Acceso/Spento - Luminosità Crescente/Decrescente caricando in Light1..Light8
;i valori corrispondenti. Questi valori sono contenuti in LightUp (Lum crescente
;0..127) e in LightDn (Lum decrescente 127..0).
;E' mostrato un esempio con le 4 combinazioni bit-bit possibili:

;	Num. Lampada    8  7  6  5  4  3  2  1
;	Reg_Up bit	0  0  1  1  0  0  1  1
;	Reg_Dn bit	0  1  0  1  0  1  0  1
;                       |  |  |  |
;                       |  |  |  ---- 11 : Lampada sempre accesa  (Light=127)
;                       |  |  ------- 10 : Luminosità crescente   (Light=0..127)
;                       |  ---------- 01 : Luminosità decrescente (Light=127..0)
;                       ------------- 00 : Lampada sempre spenta  (Light=0)

;Esegue un ritardo mS ridotto per incrementare LightUp e decrementare LightDn.
;Il tempo degli effetti in dissolvenza può essere variato da un minimo ad un massimo.
;La sub pulse_led fà lampeggiare il led e controlla la pressione dei pulsanti.
;Eseguendo questa sub, le var. StGame e LenGame vengono modificate e quindi al
;termine del gioco devono essere prelevate nuovamente da TBL_INFO (sub getinfogame)

getdissgame
	clrf	LightUp		;Inizializza Light_Up=0 (Crescente)
	movlw	127
	movwf	LightDn		;Inizializza Light_Dn=0 (Decrescente)

gdis_00	movlw	0x03		;Preleva il valore Reg_Up del gioco selezionato
	movwf	PCLATH          ;dalla tabella TBL_DISS (pagina 3)
	movf	StGame,w
	call	TBL_DISS
	movwf	Reg_Up

	movlw	0x03		;Preleva il valore Reg_Dn del gioco selezionato
	movwf	PCLATH          ;dalla tabella TBL_DISS (pagina 3)
	movf	StGame,w
	addlw   0x01
        call	TBL_DISS
	movwf	Reg_Dn

;Carica le variabili Light1..Light8 con 0, 127, Light_Up, Light_Dn secondo la
;combinazione bit-bit associata contenuta in Reg_Up e Reg_Dn.
	movlw	0x08		;8 bit da prelevare in Reg_Up, Reg_Dn
	movwf	CntLight
	movlw	Light1		;Carica indirizzo di Light1 nel puntatore
	movwf	FSR
gdis_0	btfsc	Reg_Up,0	;Verifica il bit di Reg_Up
	goto	gdis_2
	btfsc	Reg_Dn,0	;Verifica il bit di Reg_Dn
	goto	gdis_1
	clrw			;bit Reg_Up=0, bit Reg_Dn=0 - Lampada spenta
	goto	gdis_4
gdis_1	movf	LightDn,w	;bit Reg_Up=0, bit Reg_Dn=1 - Lumin. crescente
	goto	gdis_4
gdis_2	btfsc	Reg_Dn,0        ;Verifica il bit di Reg_Dn
	goto	gdis_3
	movf	LightUp,w       ;bit Reg_Up=1, bit Reg_Dn=0 - Lumin. decrescente
	goto	gdis_4
gdis_3	movlw	127		;bit Reg_Up=1, bit Reg_Dn=1 - Lampada accesa
gdis_4	movwf	INDF		;Carica su Light1...Light8

	rrf	Reg_Up,f	;Ruota a destra Reg_Up e Reg_Dn per prossimo bit
	rrf	Reg_Dn,f

	incf	FSR,f		;Prossima variabile Light_
	decfsz	CntLight,f	;Decrementa contatore
	goto	gdis_0

	call	delay_ms	;Ritardo mS per tempistica effetti

	call	pulse_led	;Fà lampeggiare il led e controlla i pulsanti
				;Ritorna in w tre possibili valori:
				;0=Continua, 1=Prossimo gioco, 2=Salva Impostaz.

	movwf	CntLight	;Verifica il valore contenuto in w (0,1,2)
	movf    CntLight,w
	btfsc	STATUS,Z
	goto	gdis_5		;Salta se w=0 (Continua)
	xorlw	0x01
	btfsc	STATUS,Z
	retlw	0x01		;Se w=1 esce con w=1 (Prossimo gioco)
	retlw	0x02		;Se w=2 esce con w=2 (Salva Impostazioni)

gdis_5	incf	LightUp,f	;Incrementa LightUp (luminosità crescente)
	decf	LightDn,f	;Decrementa LightDn (luminosità decrescente)

	btfss	LightUp,7	;Verifica se LightUp=128 (fine dissolvenza)
	goto	gdis_00		;Se LightUp<128 salta

	incf	StGame,f	;Prossimo effetto dissolvenza (sequenza)
	incf    StGame,f
        decfsz	LenGame,f	;Decrementa numero effetti del gioco
	goto	getdissgame	;Se LenGame<>0 salta
	retlw	0x00            ;Raggiunta ultima sequenza del gioco. Esce con w=0


;*****************************************************
;Modifica la variabile Game (che individua il gioco di luci) se selezionato
;MIX giochi (MixGame<>0). MixGame può assumere 4 diversi valori:
; - MixGame=0             Nessun mix di giochi
; - MixGame=1             Mix di giochi di tipo On-Off
; - MixGame=2             Mix di giochi di tipo dissolvenza
; - MixGame=3             Mix di giochi di tipo On-Off e Dissolvenza

;Il singolo gioco di tipo On-Off viene ripetuto ONOFFMIX volte durante il mix giochi
;Il mix giochi viene segnalato con l'accensione del relativo led

verify_mixgame
        movf    MixGame,w       ;Verifica se MixGame=0. No mix, esce
        btfss   STATUS,Z
        goto    vmix_1
        bsf     PORTA,LEDGMIX   ;Spegne led segnalazione mix giochi
        clrf    CntOnOff        ;Azzera il contatore ripetizioni giochi On-Off
        return

vmix_1  bcf     PORTA,LEDGMIX   ;Accende led segnalazione mix giochi
        movf    MixGame,w       ;Verifica se mix di giochi di tipo On-Off (MixGame=1)
        xorlw   0x01
        btfss   STATUS,Z
        goto    vmix_4
        movf    CntOnOff,w      ;Ripete ONOFFMIX volte lo stesso gioco di tipo On-Off
        xorlw   ONOFFMIX
        btfsc   STATUS,Z
        goto    v_mix2
        incf    CntOnOff,f
        return

v_mix2  clrf    CntOnOff
        movf    Game,w          ;Incrementa Game per mix di giochi On-Off
        xorlw   MAXGONOFF       ;(da 0 ... MAXGONOFF) ed esce
        btfss   STATUS,Z
        goto    vmix_3
        clrf    Game
        return
vmix_3  incf    Game,f
        return

vmix_4  movf    MixGame,w       ;Verifica se mix di giochi Dissolvenza (MixGame=2)
        xorlw   0x02
        btfss   STATUS,Z
        goto    vmix_6
        clrf    CntOnOff
        movf    Game,w          ;Incrementa Game per mix Giochi Dissolvenza
        xorlw   MAXGAMES        ;(da MAXGONOFF+1 ... MAXGAMES) ed esce
        btfss   STATUS,Z
        goto    vmix_5
        movlw   MAXGONOFF+1
        movwf   Game
        return
vmix_5  incf    Game,f
        return

vmix_6  movf    Game,w          ;MixGame=3 Verifica se gioco On-Off o Dissolvenza
        sublw   MAXGONOFF       ;w=MAXGONOFF-Game
        btfss   STATUS,C        ;Salta se w>=0
        goto    v_mix7
        movf    CntOnOff,w      ;Verifica se eseguite MAXGONOFF ripetizioni gioco on-off
        xorlw   ONOFFMIX
        btfsc   STATUS,Z
        goto    v_mix7
        incf    CntOnOff,f
        return
v_mix7  clrf    CntOnOff
        movf    Game,w
        xorlw   MAXGAMES
        btfss   STATUS,Z
        goto    vmix_8
        clrf    Game            ;Incrementa Game per mix giochi completo
        return                  ;(da 0 ... MAXGAMES) ed esce
vmix_8  incf    Game,f
        return


;*****************************************************
;Fa lampeggiare il led TIME che indica la velocità del gioco.

;Controlla lo stato dei due pulsanti P_GAME e PTIME e restituisce:
;  w=0	Il gioco luci precedente non è stato cambiato.
;       Nessun pulsante premuto o premuto PTIME (tempo).
;  w=1  E' stato selezionato un gioco luci diverso premendo P_GAME
;  w=2  E' stato richiesto il salvataggio delle impostazioni (gioco e tempo
;	correnti) premendo per prima (e mantenendo premuto) P_GAME e
;	successivamente premendo PTIME.
;Premendo P_GAME si attivano dapprima i singoli giochi di luce (0..MAXGAMES).
;Successivamente si accede al mix giochi di tipo:
; - On-Off      (MixGame=1, Game=0 .. MAXGONOFF)
; - Dissolvenza (MixGame=2, Game=MAXGONOFF+1 .. MAXGAMES)
; - Completo    (MixGame=3, Game=0 .. MAXGAMES)

;La pressione di P_GAME (scelta del gioco) influisce sulle variabili Game e MixGame
;e sull'uscita dalla subroutine (w)
;La pressione di P_TIME (scelta del tempo) influisce solo sulla variabile Time.

pulse_led
	btfss	PORTA,LEDTIME	;Accende/Spegne il led LEDTIME
	goto	pled_1
	bcf	PORTA,LEDTIME
	goto	pled_2
pled_1	bsf	PORTA,LEDTIME

pled_2	btfsc	PORTA,P_TIME	;Verifica se premuto pulsante P_TIME
	goto	pled_4
	movf	Time,w		;Incrementa Time da MINTIME a MAXTIME
	xorlw	MAXTIME
	btfss	STATUS,Z
	goto	pled_3
	movlw	MINTIME
	movwf	Time
	retlw	0x00		;Esce con W=0. Premuto P_TIME
pled_3	incf	Time,f
	retlw	0x00		;Esce con W=0. Premuto P_TIME

pled_4	btfsc	PORTA,P_GAME	;Verifica se premuto pulsante P_GAME
	retlw	0x00		;Esce con W=0. Nessun pulsante premuto

pled_5	btfsc	PORTA,P_GAME	;Attesa rilascio P_GAME
	goto	pled_6
	btfsc	PORTA,P_TIME	;Verifica se premuto anche P_TIME
	goto	pled_5		;P_TIME non premuto. attesa rilascio
	retlw	0x02            ;Esce con W=2. Premuti P_GAME e P_TIME

pled_6  movf    MixGame,w       ;Verifica se mix giochi attivato (MixGame<>0)
        btfss   STATUS,Z
        goto    pled_8

        movf    Game,w          ;Se raggiunto ultimo gioco (Game=MAXGAMES)
        xorlw   MAXGAMES        ;imposta mix giochi on-off a partire dal primo gioco on-off
        btfss   STATUS,Z        ;(MixGame=1 e Game=0)
        goto    pled_7
        movlw   0x01
        movwf   MixGame
        clrf    Game
        retlw   0x01            ;Esce con W=1. Premuto P_GAME
pled_7  incf    Game,f          ;Se non raggiunto ultimo gioco, incrementa Game
        retlw   0x01            ;Esce con W=1. Premuto P_GAME

pled_8  xorlw   0x01            ;Se MixGame=1 (mix di giochi di tipo On-Off)
        btfss   STATUS,Z        ;imposta mix giochi dissolvenza a partire dal primo gioco
        goto    pled_9          ;(MixGame=2 e Game=MAXGONOFF+1)
        movlw   0x02
        movwf   MixGame
        movlw   MAXGONOFF+1
        movwf   Game
        retlw   0x01            ;Esce con W=1. Premuto P_GAME

pled_9  movf    MixGame,w       ;Se MixGame=2 (mix di giochi di tipo dissolvenza)
        xorlw   0x02            ;imposta mix giochi completo a partire dal primo gioco
        btfss   STATUS,Z        ;(MixGame=3 e Game=0)
        goto    pled_10
        movlw   0x03
        movwf   MixGame
        clrf    Game
        retlw   0x01            ;Esce con W=1. Premuto P_GAME

pled_10 clrf    MixGame         ;Se MixGame=3 (mix di tutti i giochi), imposta nessun mix
        clrf    Game            ;(MixGame=0 e Game=0)
        retlw   0x01            ;Esce con W=1. Premuto P_GAME


;*****************************************************
;Spegne tutte le luci ponendo le corrispondenti uscite a zero
;Spegne i due led di segnalazione
lightled_off
        bcf     PORTA,LP_1      ;Pone a 0 le uscite dei triac per le 8 Lampade
	movf	PORTB,w         ;RA0, RB1...RB7
	andlw	00000001B
	movwf	PORTB

        bsf     PORTA,LEDTIME   ;Spegne i due led di segnalazione
        bsf     PORTA,LEDGMIX
        return

;*****************************************************
;Ritardo per pausa fra gli effetti luminosi
;Nei giochi ON-OFF serve per il prelevamento della singola sequenza. E' raddoppiato.
;Nei giochi DISSOLVENZA serve per incrementare i 127 passi di luminosità che
;compongono la singola sequenza
;Giochi ON-OFF          var.Time=1 --> Delay=2,5mS  var.Time=255-->Delay=637mS
;Giochi DISSOLVENZA     var.Time=1 --> Delay=1mS    var.Time=255-->Delay=255mS
;La variabile Time determina il tempo di ritardo
delay_ms
	movf	Time,w          ;Copia Time in Cnt_Del
	movwf	Cnt_Del

del_ms0 clrf    Cnt_Del+1
del_ms1 nop                     ;Ciclo ritardo 1 mS (sempre eseguito)
        decfsz  Cnt_Del+1,f
        goto    del_ms1

        movf    Game,w          ;Verifica se il gioco è di tipo On-Off o Dissolvenza
        sublw   MAXGONOFF       ;per raddoppiare il ritardo
        btfss   STATUS,C        ;Salta prossima se MAXGONOFF-Game >= 0 (giochi on-off)
        goto    del_ms3

        clrf    Cnt_Del+1
del_ms2 nop                     ;Ciclo ritardo 1,5 mS (solo per giochi ON-OFF)
        nop
        nop
        decfsz  Cnt_Del+1,f
        goto    del_ms2

del_ms3 decfsz  Cnt_Del,f       ;Decrementa contatore Cnt_Del (=Time)
	goto	del_ms0
	return


;*****************************************************
;Effettua ritardi da 0,1 - 0,5 - 1 secondi (senza routine di Interrupt)

del_1s  movlw   10              ;Ritardo 1 secondi (10 * 100 mS)
        goto    delay
del_05s movlw   5               ;Ritardo 0,5 secondi (5 * 100 mS)
        goto    delay
del_01s movlw   1               ;Ritardo 0,1 secondi (1 * 100 mS)

delay   movwf   Cnt_Del+2
        movlw   100             ;Ritardo 100mS
        movwf   Cnt_Del+1
        clrf    Cnt_Del
delloop decfsz  Cnt_Del,f       ;Ciclo 1
        goto    delloop
        clrwdt
        decfsz  Cnt_Del+1,f     ;Ciclo 2
        goto    delloop

        decfsz  Cnt_Del+2,f     ;Ciclo 3
        goto    delloop
        return

;*****************************************************
;Lettura delle impostazioni dalla memoria EEPROM
;Verifica se ciascuno dei tre valori è valido. Restituisce w=0(ok) oppure w=1(errore)
;Se MixGame<>0 (mix giochi) carica il primo gioco (Game) del mix (tipo on-off, diss, tutti)
; - Time        MINTIME..MAXTIME        Cnt_Eep=0
; - Game        0..MAXGAME              Cnt_Eep=1
; - MixGame     0..3                    Cnt_Eep=2

read_eeprom
        clrf    Cnt_Eep         ;Azzera contatore e indirizzo memoria
        movlw   Time            ;Carica nel puntatore la locazione di Time
        movwf   FSR

r_eep1  movf    Cnt_Eep,w       ;Carica in EEADR l'indirizzo della variabile da prelevare
        movwf   EEADR
        bsf     STATUS,RP0
        bsf     EECON1,RD       ;Inizio fase di lettura
        bcf     STATUS,RP0
        movf    EEDATA,w        ;Salva valore sulla variabile puntata da INDF
        movwf   INDF

        incf    FSR,f           ;Incrementa puntatore
        incf    Cnt_Eep,f
        movf    Cnt_Eep,w       ;Contatore=3 (prelevate 3 variabili 0,1,2 ?)
        xorlw   0x03
        btfss   STATUS,Z
        goto    r_eep1          ;Lettura prossimo valore

        movlw   MINTIME         ;Controlla se valore Time compreso tra MINTIME e MAXTIME
        subwf   Time,w          ;w=Time-MINTIME
        btfss   STATUS,C
        retlw   0x01            ;Valore Time non valido. Esce con w=1
        movf    Time,w
        sublw   MAXTIME         ;w=MAXTIME-Time
        btfss   STATUS,C
        retlw   0x01            ;Valore Time non valido. Esce con w=1

        movf    Game,w          ;Controlla se valore Game < MAXGAMES
        sublw   MAXGAMES        ;w=MAXGAMES-Game
        btfss   STATUS,C
        retlw   0x01            ;Valore Game non valido. Esce con w=1

        movf    MixGame,w       ;Controlla se valore MixGame < 3
        sublw   0x03            ;w=3-MixGame
        btfss   STATUS,C
        retlw   0x01            ;Valore MixGame non valido. Esce con w=1

                                ;Valori Time, Game, MixGame validi
        movf    MixGame,w       ;Se MixGame=0 (no mix giochi) esce
        btfsc   STATUS,Z
        retlw   0x00            ;MixGame=0. Esce con w=0

        clrf    Game            ;Inizializza al primo gioco

        movf    MixGame,w       ;Se MixGame=2 (mix giochi dissolvenza) pone Game
        xorlw   0x02            ;al primo gioco dissolvenza
        btfss   STATUS,Z
        retlw   0x00            ;MixGame=1,3. Esce con w=0

        movlw   MAXGONOFF+1     ;MixGame=2. Carica in Game il primo gioco dissolvenza
        movwf   Game
        retlw   0x00            ;Esce con w=0


;*****************************************************
;Scrittura delle impostazioni sulla memoria EEPROM
; - Time        MINTIME..MAXTIME        Cnt_Eep=0
; - Game        0..MAXGAME              Cnt_Eep=1
; - MixGame     0..3                    Cnt_Eep=2

write_eeprom
        clrwdt                  ;Azzera watchdog (sono stati disabilitati gli interrupt
                                ;dove viene normalmente effettuata questa operazione)
        clrf    Cnt_Eep         ;Azzera contatore e indirizzo memoria
        movlw   Time            ;Carica nel puntatore la locazione di Time
        movwf   FSR

w_eep1  movf    Cnt_Eep,w       ;Carica in EEADR l'indirizzo di scrittura
        movwf   EEADR
        movf    INDF,w          ;Carica in EEDATA la variabile da scrivere
        movwf   EEDATA

        bsf     STATUS,RP0      ;Memoria banco 1
        bsf     EECON1,WREN     ;Abilitazione scrittura
        movlw   85              ;Sequenza obbligatoria
        movwf   EECON2
        movlw   170
        movwf   EECON2
        bsf     EECON1,WR       ;Partenza scrittura
w_eep2  btfsc   EECON1,WR       ;Aspetta fine scrittura
        goto    w_eep2
        bcf     EECON1,WREN     ;Disabilita scrittura EEPROM
        bcf     STATUS,RP0      ;Memoria banco 0

        incf    FSR,f           ;Incrementa puntatore
        incf    Cnt_Eep,f
        movf    Cnt_Eep,w       ;Contatore=3 (scritte 3 variabili 0,1,2 ?)
        xorlw   0x03
        btfss   STATUS,Z
        goto    w_eep1          ;Scrittura prossimo valore
        return


;*****************************************************
;Inclusione Tabelle Rom
        INCLUDE         "T_ONOFF.INC"          ;Tabella giochi di luce ON-OFF
	INCLUDE         "T_DISS.INC"           ;Tabella giochi di luce DISSOLVENZA
	INCLUDE         "T_INFO.INC"           ;Tabella informazioni giochi di luce

        END                       ;Fine programma

