PROCESSOR 16F883 ; RADIX DEC INCLUDE "P16F883.INC" ; Imosta i bit di configurazione ;__CONFIG _CONFIG1, _DEBUG_ON & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_ON & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_OFF & _WDT_OFF & _INTOSCIO ;__CONFIG _CONFIG2, _BOR21V & _WRT_OFF __CONFIG _CONFIG1, _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOR_ON & _IESO_OFF & _FCMEN_OFF & _LVP_OFF __CONFIG _CONFIG2, _BOR40V & _WRT_OFF ; costanti #define _C STATUS,0 #define _Z STATUS,2 #define IR1 PORTC,6 #define IR2 PORTC,1 #define IR3 PORTB,3 #define Rsotto PORTC,3 #define Gsotto PORTC,4 #define Bsotto PORTC,5 #define MassaVir PORTB,4 #Define Pulsante PORTC,2 #define LedBluCentrale PORTA,4 #define LedRossoIr2Meno PORTC,7 #define LedVerdeIr2Meno PORTC,0 #define LedRossoIr3Piu PORTA,5 #define LedVerdeIr3Piu PORTB,2 #define LedPixelDat PORTB,0 #define LedPixelClock PORTB,1 ; ; Decrement 16 bit value, sets Z on exit ; ; Operation: DST-- ; DEC16 MACRO DST DECF (DST),F ; Decrement low byte INCFSZ (DST),W ; Check for underflow INCF (DST)+1,F ; Update DECF (DST)+1,F ; Fixup MOVF (DST),W IORWF (DST)+1,W ; Set Z bit ENDM ; ; Increment 16 bit value, sets Z on exit. ; ; Operation: DST++ ; INC16 MACRO DST INCFSZ (DST),W ; Add one to low byte DECF (DST)+1,F ; No carry (negates next step) INCF (DST)+1,F ; Add one to high byte MOVWF (DST) ; Store updated low byte back. IORWF (DST)+1,W ; Set Z flag ENDM ; ; 16 bit unsigned addition with carry out. ; Operation: DST = DST + SRC ; ; DST is replaced, SRC is preserved, Carry is set correctly ; ADD16 MACRO DST,SRC MOVF (SRC),W ; Get low byte ADDWF (DST),F ; Add to destination MOVF (SRC)+1,W ; Get high byte BTFSC _C ; Check for carry INCF (SRC)+1,W ; Add one for carry ADDWF (DST)+1,F ; Add high byte into DST ENDM ; 16 bit unsigned subtraction with carry out. ; Word format is little endian (LSB at lower address) ; Operation is DST = DST - SRC ; ; (This from the "tips and tricks" seminar handout) ; ; DST is replaced, SRC is preserved, Carry is set correctly ; ; SUB16 MACRO DST, SRC MOVF (SRC),W ; Get low byte of subtrahend SUBWF (DST),F ; Subtract DST(low) - SRC(low) MOVF (SRC)+1,W ; Now get high byte of subtrahend BTFSS STATUS,C ; If there was a borrow, rather than INCF (SRC)+1,W ; decrement high byte of dst we inc src SUBWF (DST)+1,F ; Subtract the high byte and we're done ENDM SUBI16 MACRO DST, SB MOVLW LOW (SB) SUBWF (DST), F MOVLW HIGH (SB) BTFSS STATUS, C MOVLW (HIGH (SB))+1 SUBWF (DST)+1,F ENDM ; Copia 16 bit variabile COPY16 MACRO DST,SRC movf SRC,w movwf DST movf SRC+1,w movwf DST+1 ENDM ; ; Initialize a 16 bit value ; INIT16 MACRO VAR, CONST MOVLW low CONST MOVWF VAR MOVLW high CONST MOVWF VAR+1 ENDM ; ; Initialize a 16 bit value to zero ; CLR16 MACRO VAR CLRF VAR CLRF VAR+1 ENDM ; ; Macro to do a logical shift right on a 16 bit value ; (0 is shifted into the MSB) ; LSR16 MACRO VAR16 BCF STATUS, C ; Clear carry RRF (VAR16)+1,F ; Rotate high byte right RRF (VAR16),F ; Rotate low byte right ENDM LSL16 MACRO VAR16 BCF STATUS, C ; Clear carry RLF (VAR16),F ; Rotate low byte left RLF (VAR16)+1,F ; Rotate upper byte left ENDM SogliaIRsaturo equ 200*4 ; valore oltre il quale l'ingresso IR viene considerato saturo e quindi viene considerato il campionamento precedente SogliaMinIR equ 200 ; Soglia che determina la sensibilita' minima del sensore IR IsteresiMinIR equ 5 ; valore di isteresi che viene aggiunto alla SogliaMinIR per evitare glitch SogliaBotIR equ 50 ; Soglia che determina quando un pulsante IR viene premuto IsteresiBotIR equ 5 ; valore di isteresi che viene aggiunto o tolto alla SogliaBot per evitare glitch IsteresiScalaIr equ 3 ; 2 valore utilizzato nella rutine ScalaIr che converte il valore 0 - (200 circa) in un valore 0-25 FattoreScalaIR equ 5 ; rapporto per convertire IR1diff in un valore compreso tra 0 e 25 ;DimMax equ 15 ; quanto viene diminuito MaxAudio ad ogni campionamento MaxAudioMinimo equ 10 ; prima 2200 700 valore minimo che puo' raggiungere MaxAudio ;SogliaAudio equ 60 ; vengono considerati solo i segnali maggiori di questa soglia ;SogliaAudioMin equ 5 ; valore che viene sottratto a Audio per evitare il rumore di forndo PatternMax equ 5 ; numero di pattern memorizzati ModoMax equ 3 ; numero di modi PassaAudio equ 240 ; Determina quanto tempo quando passa prima di passare all'ingresso Audio quando l'ingresso IR1 rimane a zero StroboOn equ 1 ; tempo On luci strobo StroboOff equ 100 ; tempo Off luci strobo ; Riserva spazio per le variabili del programma udata 32 ; zona di memoria "general purpose register" (nel banco di memoria 0) pwm res 2 ; variabile che incrementa il valore con cui vengono modulati le uscite pwm nella rutine di interrupt attesatime res 1 ; variabile che viene confrontata con pwm. quando coincide fa partire la conversione AD att res 1 ; contatore che conteggia il ciclo di campionamento del sensore IR mentre il LEd IR e' acceso Modo res 1 ; modalita' corrente Pattern res 1 ; indica la paletta di colori da usare faseint res 1 ; indica in quale fase e' la rutine di interrupt che viene chiamata piu volte Audio res 2 ; valore del segnale audio istantaneo AudioScal res 1 ; valore scalato compreso tra 0 e 25 ;MaxAudio res 2 ; Valore della massima intesista' del segnale audio ;MaxAudioNew res 2 ;ContMaxAudio res 2 ;MinAudio res 2 ; valore minimo dell'intensita' audio ValoreVu res 1 ; altezza della barra Vu nel modo 0 Finestra res 2 ; qui vengono sommati i valore audio FinestraOld res 2 ; Finestra precedente Media res 4 ; Filtro che calcola la media delle finestre M res 2 ; variabili usate nella rutine Scala V res 2 ; possono essere usate come variabili temporaneee da altre funzioni Ma res 2 Va res 2 flag res 1 ; bit 0 = se settato e' stata completata una nuova finestra ; bit 1 = stato pulsante premuto meno (Ir2) ; bit 3 = stato pulsante premuto piu (Ir3) ; bit 4 = se settato, la rutine nel mainloop calcola LinearizzaIr perche' questa rutine richiede troppo tempo se fatta negli interrupt ; bit 5 = modo cambia colore (si tiene la mano(1) sul piu o sul meno e si cambia il colore con l'altra(2)) quando poi la mano(1) viene rilasciata non deve cambiare il mode ; bit 6 = indica se l'ingresso IRon (1,2 o 3) e' gia' arrivato a saturazione ; bit 7 = nuovo valore di stato (IR 2 o 3) usato temporaneamente della rutine di interrupt #define IR2stato flag,1 #define IngressoAudioMano flag,2 #define IR3stato flag,3 #define NuovoIrMisurato flag,4 #define ModoCambiaModo flag,5 #define IRsaturo flag,6 #define IRNewStato flag,7 IRoff res 2 IRon res 2 IRdiff res 2 ; differenza tra il valore quando acceso e quando spento IR1diff res 1 ; valore compreso tra 0-255 IR1scalato res 1 ; valore compreso tra 0 e 25 IR1diffPrec res 1 ; valore precedente di Ir1diff usato per l'isteresi IR2diff res 1 IR3diff res 1 ; variabili usate negli INTERRUPT iint res 1 ; contatore usato nella rutine di interrupt vint res 2 ; variabile temporanea usata nell rutine di interrupt (16 bit) ; variabili usate nel MAINLOOP l res 1 ; variabile usata per passare dati alle funzioni nel main loop i res 1 ; contatore usato nel mainloop x res 1 ; contatore usato nel mainloop (rutine di comunicazione con la ledstrip,rutine tabella pattern) y res 1 ; usato nella rutine tabella pattern z1 res 1 ; nel modo 0 conta il tempo che il segnale Ir1 rimane a zero, se rimane a zero per piu di un certo tempo utilizza come ingresso il segnale audio VelMano res 1 ; Velocita' della mano PosMano res 1 ; Posizione della mano VelPalla res 1 ; Velocita' della palla PosPalla res 1 ; posizione della palla PallaPrecedente res 1 ManoPrecedente res 1 IndiceColore res 2 rgb res 3 ; contiene il valore colore (24 bit) RgbSotto res 3 ; colore del led sotto (modulato in pwm) t res 2 ; variabile temporanea usata nel mainloop (rutine tabellaPattern) CBLOCK H'70' ; zona di memoria comune ai 4 banchi di memoria ; spazio di 16 byte W_TEMP STATUS_TEMP PCLATH_TEMP ENDC ORG 0000h ; reset vector goto Inizio ;8888888 888 888 ; 888 888 888 ; 888 888 888 ; 888 88888b. 888888 .d88b. 888d888 888d888 888 888 88888b. 888888 ; 888 888 "88b 888 d8P Y8b 888P" 888P" 888 888 888 "88b 888 ; 888 888 888 888 88888888 888 888 888 888 888 888 888 ; 888 888 888 Y88b. Y8b. 888 888 Y88b 888 888 d88P Y88b. ;8888888 888 888 "Y888 "Y8888 888 888 "Y88888 88888P" "Y888 ; 888 ; 888 ; 888 ; ; faseint = 1 ; quando la conversione e' completa ; accende il LED IR 1 ; salta ad eseguire il gruppo di istruzioni IRoffSub ; memorizza il valore dell'AD in IRoff ; incrementa faseint ; att = 1 ; IRsaturo = 0 ; imposta tempo di attesa: attesatime = 1 ; Va a ImpAudio ; faseint = 2 ; quando la conversione e' completa chiama la rutine IRon: ; memorizza il valore dell'AD in IRon ; +-- SI -- att = 1 ; | | NO ; | att = 16 -- SI -- incrementa faseint, spegne LED IR, ritorna dalla chiamata di funzione ; | | NO ; | IRsaturo = 0 --- NO -------------+ ; | | SI | ; | IRon < SogliaIRsaturo -- NO -- spegne LED IR (tutti) ; | | SI IRdiff = IRdiff x 2 ; | | IRsaturo = 1 ; +---------> IRdiff= IRon - IRoff | ; +---------------------------+ ; | ; attesatime = att ; att = att x 2 ; ritorna dalla chiamata di funzione ; faseint = 3 ; giunge a questa fase direttamente dalla fase precedente (senza uscire e poi rientrare dalla rutine di interrupt) ; NuovoIrMisurato = 1 ; incrementa faseint ; attesatime = 115 ; Va a ImpAudio ; faseint = 4 ; quando la conversione e' completa ; accende il LED IR 2 ; salta ad eseguire il gruppo di istruzioni IRoffSub ; faseint = 5 ; quando la conversione e' completa chiama la rutine IRon ; faseint = 6 ; giunge a questa fase direttamente dalla fase precedente (senza uscire e poi rientrare dalla rutine di interrupt) ; NuovoIrMisurato = 1 ; incrementa faseint ; attesatime = 115 ; Va a ImpAudio ; faseint = 7 ; quando la conversione e' completa ; accende il LED IR 3 ; salta ad eseguire il gruppo di istruzioni IRoffSub ; faseint = 8 ; quando la conversione e' completa chiama la rutine IRon ; faseint = 9 ; giunge a questa fase direttamente dalla fase precedente (senza uscire e poi rientrare dalla rutine di interrupt) ; NuovoIrMisurato = 1 ; faseint = 1 ; attesatime = 115 ; Va a ImpAudio ORG 0004h ; interrupt vector MOVWF W_TEMP ;Copy W to TEMP register SWAPF STATUS,W ;Swap status to be saved into W ; bcf STATUS,IRP ;Swaps are used because they do not affect the status bits MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register movf PCLATH,W movwf PCLATH_TEMP clrf PCLATH BANKSEL PIR1 btfss PIR1,ADIF ; verifica se e' stato il termine della conversione AD a causare l'interrupt goto NoADInterrupt bcf PIR1,ADIF ; resetta l'interrupt su AD ; Verifica se l'AD ha letto l'ingresso audio o un altro ingresso BANKSEL ADCON0 ; bank 0 movf ADCON0,w andlw B'00111100' XORlw B'00001000' btfss _Z goto LettoAltroIngresso LettoIngressoAudio: ; memorizzare qui il sengale audio e fare i conti "finestra"... eccetera BANKSEL ADRESL ; VINT = valore audio misurato movf ADRESL,w ; banco di memoria 1 BANKSEL vint ; bank 0 movwf VINT+0 movf ADRESH,w movwf vint+1 btfss vint+1,1 ; se il valore e' maggiore o uguale a 512 ; allora calcola valore - 512 goto SottEinversa ; altrimenti fa la sottrazione inversa : 512 - valore bcf vint+1,1 bcf MassaVir ; adatta la massa virtuale dell'amplificatore operazionale alla meta' del conv AD goto DopoSotte SottEinversa: movlw 255 xorwf vint+0,f movlw 1 XORWF vint+1,f bsf MassaVir ; adatta la massa virtuale dell'amplificatore operazionale alla meta' del conv AD DopoSotte: ADD16 Finestra,vint ; Finestra = finestra + vint btfss _C ; Se l'addizione ha dato overflow porta Finestra al valore massimo goto NoOverflowFinestra movlw 255 movwf Finestra+0 movwf Finestra+1 ; movlw 5 ; subwf lFinestra,f ; diminuisce lFinestra di 5 (non pu' andare sotto zero perche' 5 volte un nuomero a 10 bit non puo' fare overflow di una variabile a 16 bit) NoOverflowFinestra: decfsz AttesaTime,f goto EsceDaInterrupt ; Impostare il convertitore AD a seconda della fase e fare partire la conversione movf faseint,w xorlw 1 btfsc _Z goto ImpIr1 movf faseint,w xorlw 2 btfsc _Z goto ImpIr1 movf faseint,w xorlw 4 btfsc _Z goto ImpIr2 movf faseint,w xorlw 5 btfsc _Z goto ImpIr2 movf faseint,w xorlw 7 btfsc _Z goto ImpIr3 movf faseint,w xorlw 8 btfsc _Z goto ImpIr3 movlw 1 ; nel caso il valore non corrisponda lo riporta a 1 movwf faseint goto EsceDaInterrupt ImpIr1: BANKSEL ADCON1 ; bank 1 bcf ADCON1,VCFG0 ; voltalge reference positivo al + bcf ADCON1,VCFG1 ; voltalge reference negativo al - bsf ADCON1,ADFM ; giustificato a DESTRA BANKSEL ADCON0 ; bank 0 bcf ADCON0,CHS3 bcf ADCON0,CHS2 ; imposta il convertitore su ingresso Ir 1 / AN3 / Ra3 bsf ADCON0,CHS1 bsf ADCON0,CHS0 goto FaPartireAcqu ImpIr2: ; bank 0 bcf ADCON0,CHS2 ; imposta il convertitore su ingresso Ir 2 / AN1 / Ra1 bcf ADCON0,CHS1 bsf ADCON0,CHS0 goto FaPartireAcqu ImpIr3: bcf ADCON0,CHS2 ; imposta il convertitore su ingresso Ir 3 / AN0 / Ra0 bcf ADCON0,CHS1 bcf ADCON0,CHS0 FaPartireAcqu: call DelayAcq ; ritardo acquisizione bsf ADCON0,GO ; fa partire la conversione AD (bank 0) goto EsceDaInterrupt LettoAltroIngresso: ; faseint = 1 ; quando la conversione e' completa ; accende il LED IR 1 ; salta ad eseguire il gruppo di istruzioni IRoffSub movf faseint,w xorlw 1 btfss _Z goto NoFase1 Fase1: BANKSEL PORTA ; bank 0 bsf IR1 ; accende il led IR1 goto IRoffSub NoFase1: ; faseint = 2 ; quando la conversione e' completa chiama la rutine IRonSub movf faseint,w xorlw 2 btfss _Z goto NoFase2 Fase2: call IRonSub NoFase2: ; faseint = 3 ; giunge a questa fase direttamente dalla fase precedente (senza uscire e poi rientrare dalla rutine di interrupt) ; NuovoIrMisurato = 1 ; incrementa faseint ; attesatime = 115 ; Va a ImpAudio movf faseint,w xorlw 3 btfss _Z goto NoFase3 Fase3: IncFaseAttesaEsce: bsf NuovoIrMisurato LSR16 Finestra ; rotate right Finestra = Finestra / 2 COPY16 Audio,Finestra ADD16 Audio,FinestraOld COPY16 FinestraOld,Finestra ; ; movlw 100 ; movwf Media+0 ; movlw 255 ; movwf Media+1 ; movlw 255 ; movwf Media+2 ; movlw 0 ; movwf Media+3 ; ; Spostare i byte in Media a SX di una posizione ==> media = media * 256 movf Media+2,w movwf Media+3 movwf Finestra+1 ; Usa Finestra per memorizzare i 2 bytes piu alti movf Media+1,w movwf Media+2 movwf Finestra+0 movf Media+0,w movwf Media+1 clrf Media+0 ; Sottrarre il vecchio valore di meda al contenuto attuale di media ==> media = media * 256 - media = media * 255 movf Media+1,w subwf Media+0,f movf Finestra+0,w btfss _C incfsz Finestra+0,w subwf Media+1,f movf Finestra+1,w btfss _C incfsz Finestra+1,w subwf Media+2,f btfss _C decf Media+3,f ; Aggiungere FinestraOld MOVF FinestraOld,W ADDWF Media+1,F MOVF FinestraOld+1,W BTFSC _C INCF FinestraOld+1,W ADDWF Media+2,F btfsc _C incf Media+3,f ; Sposta i byte in Media a destra di una posizione movf Media+1,w movwf Media+0 movf Media+2,w movwf Media+1 movf Media+3,w movwf Media+2 clrf Media+3 ; movf Finestra+0,W ;Add low bytes ; addwf Media+1,F ; ; movf NUM2M,W Finestra+1 ;Add mid bytes ; skpnc ;No carry_in, so just add ; incfsz NUM2M,W Finestra+1 ;Add carry_in to NUM2 ; addwf NUM1M,F Media+2 ;Add and propagate carry_out CLR16 Finestra ; Azzera la finestra incf faseint,f ; incrementa faseint movlw 115 movwf AttesaTime goto ImpAudio NoFase3: ; faseint = 4 ; quando la conversione e' completa ; accende il LED IR 2 ; salta ad eseguire il gruppo di istruzioni IRoffSub movf faseint,w xorlw 4 btfss _Z goto NoFase4 Fase4: BANKSEL PORTA ; bank 0 bsf IR2 ; accende il led IR2 goto IRoffSub NoFase4: ; faseint = 5 ; quando la conversione e' completa chiama la rutine IRonSub movf faseint,w xorlw 5 btfss _Z goto NoFase5 Fase5: call IRonSub NoFase5: ; faseint = 6 ; giunge a questa fase direttamente dalla fase precedente (senza uscire e poi rientrare dalla rutine di interrupt) ; NuovoIrMisurato = 1 ; incrementa faseint ; attesatime = 115 ; Va a ImpAudio movf faseint,w xorlw 6 btfss _Z goto NoFase6 Fase6: goto IncFaseAttesaEsce NoFase6: ; faseint = 7 ; quando la conversione e' completa ; accende il LED IR 3 ; salta ad eseguire il gruppo di istruzioni IRoffSub movf faseint,w xorlw 7 btfss _Z goto NoFase7 Fase7: BANKSEL PORTA ; bank 0 bsf IR3 ; accende il led IR3 goto IRoffSub NoFase7: ; faseint = 8 ; quando la conversione e' completa chiama la rutine IRon movf faseint,w xorlw 8 btfss _Z goto NoFase8 Fase8: call IRonSub NoFase8: ; faseint = 9 ; giunge a questa fase direttamente dalla fase precedente (senza uscire e poi rientrare dalla rutine di interrupt) ; NuovoIrMisurato = 1 ; AZZERA faseint ; attesatime = 115 ; Va a ImpAudio movf faseint,w xorlw 9 btfss _Z goto NoFase9 Fase9: clrf faseint ; porta FaseInt a zero goto IncFaseAttesaEsce ; poi qui viene incrementata di 1 NoFase9: ; imposta AD per segnale audio ImpAudio: ; bank 0 bcf ADCON0,CHS2 ; imposta il convertitore su ingresso AN2 (audio) bsf ADCON0,CHS1 bcf ADCON0,CHS0 goto EsceDaInterrupt NoADInterrupt: BANKSEL INTCON btfss INTCON,T0IF ; verifica se e' stato il timer0 a causare l'interrupt goto NoTimer0Interrupt bcf INTCON,T0IF ; resetta l'interrupt su timer 0 INC16 pwm ; incrementa la variabile pwm ; in questa parte vengono modulate tutte le luci PWM bcf LedBluCentrale bcf LedRossoIr2Meno bcf LedVerdeIr2Meno bcf LedRossoIr3Piu bcf LedVerdeIr3Piu movf IR1DIFF,w subwf PWM,w btfss _C bsf LedBluCentrale movf IR2DIFF,w subwf PWM,w btfsc _C goto Led2Spento btfsc ModoCambiaModo goto Led2ModoCambiaModo btfsc IR2stato goto Led2Rosso goto Led2Verde Led2ModoCambiaModo: btfsc IR2stato goto Led2Verde goto Led2Rosso Led2Rosso: bsf LedRossoIr2Meno goto Led2Spento Led2Verde: bsf LedVerdeIr2Meno Led2Spento: movf IR3DIFF,w subwf PWM,w btfsc _C goto Led3Spento btfsc ModoCambiaModo goto Led3ModoCambiaModo btfsc IR3stato goto Led3Rosso goto Led3Verde Led3ModoCambiaModo: btfsc IR3stato goto Led3Verde goto Led3Rosso Led3Rosso: bsf LedRossoIr3Piu goto Led3Spento Led3Verde: bsf LedVerdeIr3Piu Led3Spento: bcf Rsotto bcf Gsotto bcf Bsotto movf RGBsotto+0,w subwf PWM,w btfss _C bsf Rsotto movf RGBsotto+1,w subwf PWM,w btfss _C bsf Gsotto movf RGBsotto+2,w subwf PWM,w btfss _C bsf Bsotto BANKSEL PORTA BANKSEL ADCON0 bsf ADCON0,GO ; fa partire la conversione AD NoTimer0Interrupt: EsceDaInterrupt: ; Esce dagli interrupt movf PCLATH_TEMP,W movwf PCLATH SWAPF STATUS_TEMP,W ;Swap STATUS_TEMP register into W ;(sets bank to original state) MOVWF STATUS ;Move W into STATUS register SWAPF W_TEMP,F ;Swap W_TEMP SWAPF W_TEMP,W ;Swap W_TEMP into W retfie ;8888888 d8b d8b ; 888 Y8P Y8P ; 888 ; 888 88888b. 888 88888888 888 .d88b. ; 888 888 "88b 888 d88P 888 d88""88b ; 888 888 888 888 d88P 888 888 888 ; 888 888 888 888 d88P 888 Y88..88P ;8888888 888 888 888 88888888 888 "Y88P" Inizio: ; Imposta il registro dell'oscillatore BANKSEL OSCCON ; il registro e' nel banco di memoria 1 movlw B'01111110' ; imposta oscillatore movwf OSCCON ; Imposta la porta A BANKSEL PORTA CLRF PORTA ; Init PORTA BANKSEL TRISA ; movlw B'11001111' ; RA0 - AN0 input IR 3 piu 1 ; RA1 - AN1 input IR 2 meno 1 ; RA2 - AN2 input segnale audio 1 ; RA3 - AN3 input IR 1 centralr 1 ; RA4 - output LED blu centrale 0 ; Ra5 - output LED 0 ; RA6 - occupato dal quarzo 1 ; RA7 - occupato dal quarzo 1 MOVWF TRISA BANKSEL ANSEL movlw B'00001111' ; canale 0 1 2 3 in analogico movwf ANSEL clrf ANSELH ; Imposta i bit generici del convertitore AD che non comprendono quelli che verranno poi modificati nella rutine di interrupt per cambiare canale BANKSEL ADCON0 bsf ADCON0,ADCS1 ; frequenza clock/32 bcf ADCON0,ADCS0 bsf ADCON0,ADON ; attiva il converitore AD bcf ADCON0,VCFG1 ; per gli ingressi usati (0,1,2,3) questo bit rimane sempre a zero BANKSEL ADCON1 bcf ADCON1,ADFM ; seleziona giustificato a sinistra (un byte contiene la parte piu significativa) bcf ADCON1,VCFG1 ; voltalge reference negativo a massa ; Imposta la porta C BANKSEL PORTC CLRF PORTC BANKSEL TRISC MOVLW B'00000100' ; All output ; rc0 = 0 out LED ; rc1 = 0 out LED IR 2 meno ; rc2 = 1 inp pulsante ; rc3 = 0 out Red sotto ; rc4 = 0 out Green sotto ; rc5 = 0 out Blue sooto ; rc6 = 0 out LED IR 1 centrale ; rc7 = 0 out LED MOVWF TRISC ; Imposta la porta B BANKSEL PORTB CLRF PORTB BANKSEL TRISB MOVLW B'00000000' ; All output RB0 input MOVWF TRISB ; Imposta il timer0 e gli interrupt BANKSEL OPTION_REG bcf OPTION_REG,T0CS ;il timer 0 viene incrementato usando il clock interno bsf OPTION_REG,PSA ; il prescaler e' assegnato al watchdog e timer0 non ha prescaler ; bcf OPTION_REG,PS0 ; prescaler 1 : 2 ; bcf OPTION_REG,PS1 ; bcf OPTION_REG,PS2 BANKSEL TMR0 clrf TMR0 ; azzera il timer 0 BANKSEL PIE1 bsf PIE1,ADIE ; abilita l'interrupt generato dal vonvertitore AD BANKSEL INTCON bsf INTCON,PEIE ; attiva gli interrupt delle periferiche bsf INTCON,T0IE ; attiva l'interrupt per il timer 0 bsf INTCON,GIE ; Attiva gli interrupt ; Inizializza le variabili BANKSEL flag clrf flag clrf faseint clrf pattern movlw 0 movwf pattern movlw 0 movwf modo ; INIT16 MaxAudio,MaxAudioMinimo ; MaxAudioMinimo = minimo CLRF PallaPrecedente CLRF ManoPrecedente ;; PROVA ;PROVA: ; BSF portc,6 ; BSF portc,1 ; BSF PORTC,7 ; ; BSF PORTC,0 ; BSF PORTA,5 ; BSF PORTB,2 ; BSF PORTA,4 ; BSF PORTB,3 ; ; ; GOTO PROVA ; per test ;pertest: ; banksel PORTB ; movlw 255 ; movwf PORTB ; goto pertest ;888b d888 d8b 888 ;8888b d8888 Y8P 888 ;88888b.d88888 888 ;888Y88888P888 8888b. 888 88888b. 888 .d88b. .d88b. 88888b. ;888 Y888P 888 "88b 888 888 "88b 888 d88""88b d88""88b 888 "88b ;888 Y8P 888 .d888888 888 888 888 888 888 888 888 888 888 888 ;888 " 888 888 888 888 888 888 888 Y88..88P Y88..88P 888 d88P ;888 888 "Y888888 888 888 888 88888888 "Y88P" "Y88P" 88888P" ; 888 ; 888 ; 888 BANKSEL PORTC ;DiNuovo: ; ;; porta a livello zero il clock per 500 us ; movlw 190 ; x=190 ; movwf x ; ;CicloAttendeReset: ; bcf PORTC,7 ; 1 ciclo ; incfsz x,f ; 1 ciclo ; goto CicloAttendeReset ; 2 cicli ; ; bsf PORTC,6 ; bsf PORTC,7 ; ; clrf x ;CicloProva: ; bcf PORTC,7 ; bsf PORTC,7 ; bcf PORTC,7 ; bsf PORTC,7 ; bcf PORTC,7 ; bsf PORTC,7 ; bcf PORTC,7 ; bsf PORTC,7 ; ; ; ; bcf PORTC,7 ; bsf PORTC,7 ; incfsz x,f ; goto CicloProva ; ; goto DiNuovo MainLoop: btfss Pulsante goto OnOff btfss NuovoIrMisurato goto MainLoop bcf NuovoIrMisurato movf faseint,w xorlw 1 btfsc _Z goto CalcolaIr3 movf faseint,w xorlw 4 btfsc _Z goto CalcolaIr1 movf faseint,w xorlw 7 btfsc _Z goto CalcolaIr2 goto MainLoop CalcolaIr2: movf IR2diff,f ; se il valore di Ir2diff precedente NON e' zero btfsc _Z goto NonAggiungeIsteresi2 movlw ISTERESIMINIR ; aggiunge IsteresiMinIr a IRdiff addwf IRDIFF,f btfsc _C incf IRDIFF+1,f NonAggiungeIsteresi2: call LinearizzaIR movwf IR2DIFF movlw IsteresiBotIR btfsc IR2stato ; stato precedente del "pulsante" Ir2 meno addwf IR2diff,f bcf IRNewStato ; confronta IR2diff con soglia e salva il risultato in IRNewStato movlw SogliaBotIR subwf IR2diff,w btfsc _C bsf IRNewStato btfss IR2stato ; il pulsante puo' essere rilasciato solo se lo stato precedente e' 1 goto IR2NoCambiaColore btfsc IRNewStato ; il pulsante puo' essere rilasciato solo se lo stato attuale e' 0 goto IR2NoCambiaColore btfsc ModoCambiaModo ; Se ModoCambiaModo=0 allora cambia il colore goto IR2NoCambiaColore btfsc IR3stato ; Il Ir3 deve essere a zero per cambiare il colore goto IR2NoCambiaColore ; colore - movlw 1 subwf Pattern,f ; descrementa pattern movlw PatternMax btfss _C ; se Pattern <0 allora pattern = Matternmax movwf Pattern IR2NoCambiaColore: btfsc IR2stato ; il pulsante puo' essere premuto solo se lo stato precedente e' 0 goto IR2NoCambiaModo btfss IRNewStato ; il pulsante puo' essere premuto solo se lo stato attuale e' 1 goto IR2NoCambiaModo btfss ModoCambiaModo ; Se ModoCambiaModo=1 allora cambia il Modo goto IR2NoCambiaModo btfss IR3stato ; Il Ir3 deve essere a 1 per cambiare il Modo goto IR2NoCambiaModo ; modo - movlw 1 subwf Modo,f ; descrementa Modo movlw ModoMax btfss _C ; se Modo <0 allora Modo = ModoMax movwf Modo IR2NoCambiaModo: btfsc IRNewStato ; copia il valore di IRNewStato in IR2stato goto IR2stato1 ; se IR3stato = IR2stato allora modifica ModoCambiaModo IR2stato0: bcf IR2stato btfss IR3stato bcf ModoCambiaModo goto DopoIR2stato IR2stato1: bsf IR2stato btfsc IR3stato bsf ModoCambiaModo DopoIR2stato: goto MainLoop CalcolaIr3: movf IR3diff,f ; se il valore di Ir3diff precedente NON e' zero btfsc _Z goto NonAggiungeIsteresi3 movlw ISTERESIMINIR ; aggiunge IsteresiMinIr a IRdiff addwf IRDIFF,f btfsc _C incf IRDIFF+1,f NonAggiungeIsteresi3: call LinearizzaIR movwf IR3DIFF movlw IsteresiBotIR btfsc IR3stato ; stato precedente del "pulsante" Ir3 piu addwf IR3diff,f bcf IRNewStato ; confronta IR3diff con soglia e salva il risultato in IRNewStato movlw SogliaBotIR subwf IR3diff,w btfsc _C bsf IRNewStato btfss IR3stato ; il pulsante puo' essere rilasciato solo se lo stato precedente e' 1 goto IR3NoCambiaColore btfsc IRNewStato ; il pulsante puo' essere rilasciato solo se lo stato attuale e' 0 goto IR3NoCambiaColore btfsc ModoCambiaModo ; Se ModoCambiaModo=0 allora cambia il colore goto IR3NoCambiaColore btfsc IR2stato ; Il Ir2 deve essere a zero per cambiare il colore goto IR3NoCambiaColore ; colore + incf Pattern,f ; incrementa pattern movf Pattern,w sublw PatternMax ; se Pattern > Matternmax allora pattern = 0 btfss _C clrf Pattern IR3NoCambiaColore: btfsc IR3stato ; il pulsante puo' essere premuto solo se lo stato precedente e' 0 goto IR3NoCambiaModo btfss IRNewStato ; il pulsante puo' essere premuto solo se lo stato attuale e' 1 goto IR3NoCambiaModo btfss ModoCambiaModo ; Se ModoCambiaModo=1 allora cambia il Modo goto IR3NoCambiaModo btfss IR2stato ; Il Ir3 deve essere a 1 per cambiare il Modo goto IR3NoCambiaModo ; modo + incf Modo,f ; incrementa Modo movf Modo,w sublw ModoMax ; se Modo > ModoMax allora Modo = 0 btfss _C clrf Modo IR3NoCambiaModo: btfsc IRNewStato ; copia il valore di IRNewStato in IR3stato goto IR3stato1 ; se IR3stato = IR2stato allora modifica ModoCambiaModo IR3stato0: bcf IR3stato btfss IR2stato bcf ModoCambiaModo goto DopoIR3stato IR3stato1: bsf IR3stato btfsc IR2stato bsf ModoCambiaModo DopoIR3stato: goto MainLoop CalcolaIr1: movf IR1diff,f ; se il valore di Ir1diff precedente NON e' zero btfsc _Z goto NonAggiungeIsteresi1 movlw ISTERESIMINIR ; aggiunge IsteresiMinIr a IRdiff addwf IRDIFF,f btfsc _C incf IRDIFF+1,f NonAggiungeIsteresi1: call LinearizzaIR movwf IR1DIFF ;- Se arriva a questo punto l'ingresso audio (accumulato in Finestra) e l'Ir contengono un nuovo valore ;CalcolaAudio: ; ; LSR16 Finestra ; rotate right Finestra = Finestra / 2 ; ; ; LSR16 Audio ; anche Audio precedente ; ; ADD16 Audio,Finestra ; Audio nuovo = (Finestra/2) + (Audio precedente/2) ; ; CLR16 Finestra ; Azzera la finestra ;- COPY16 Audio,Finestra ;- CLR16 Finestra ;- Decrementa MaxAudio, se MaxAudio e' minore della soglia minima, lo riporta alla soglia minima ;- SUBI16 MaxAudio,DimMax ; Se Audio > MaxAudioNew allora MaxAudioNew=Audio ; COPY16 t,MaxAudioNew ; t = MaxAudio ; SUB16 t,Audio ; t = t - Audio ; btfsc _C ; goto NonAggiornaMaxAudioNew ; COPY16 MaxAudioNew,Audio ; MaxAudioNew = Audio ;NonAggiornaMaxAudioNew: ; incfsz ContMaxAudio,f ; goto NoArrivatoContMaxAudio ; COPY16 MaxAudio,MaxAudioNew ; ; CLR16 MaxAudioNew ;NoArrivatoContMaxAudio: ; COPY16 t,MaxAudio ; t = MaxAudio ; SUBI16 t,MaxAudioMinimo ; t = t - MaxAudioMinimo ; btfsc _C ; goto NonResettaMaxAudio ; INIT16 MaxAudio,MaxAudioMinimo ;NonResettaMaxAudio: ;; Se Audio > MaxAudio allora MaxAudio=Audio ; COPY16 t,MaxAudio ; t = MaxAudio ; SUB16 t,Audio ; t = t - Audio ; btfsc _C ; goto NonAggiornaMaxAudio ; COPY16 MaxAudio,Audio ; MaxAudio = Audio ;NonAggiornaMaxAudio: ; Scala il valore di Audio con MaxAudio call ScalaAudio ; Scala il valore di IR1diff che e' compreso tra 0 e circa 200 in un valore compreso tra 0 e 25 tulizzando IsteresiScalaIR movf Ir1diff,w ; esegue la differenza tra Ir1diff e quello precedente subwf Ir1diffPrec,w ; questa e' la velocita' della mano! movwf VelMano btfss _C xorlw B'11111111' ; se il valore e' negativo lo complementa e ottiene il valore positivo sublw IsteresiScalaIR ; confronta con l'isteresi btfsc _C goto IR1isteresiNonSuperata clrf IR1scalato ; iR1SCALATO = 0 movf Ir1diff,w ; Ir1diffPrec = IR1diff movwf Ir1diffPrec CicloDivideScalaIr1: movlw FattoreScalaIR subwf Ir1diffPrec,f btfss _C goto EsceCicloDivideScalaIr1 incf IR1scalato,f ; Incrementa IR1scalato goto CicloDivideScalaIr1 EsceCicloDivideScalaIr1: movf Ir1diff,w ; Copia il valore nuovo in Ir1diffPrec movwf Ir1diffPrec IR1isteresiNonSuperata: ; Con due mani l'utente seleziona il modo ; Disegna una scala con delle tacche e un indice indica la posizione del modo btfss ModoCambiaModo goto NoCambiaModo CambiaModo: call Scurisce clrf RGBsotto+0 clrf RGBsotto+1 clrf RGBsotto+2 clrf i clrf V movlw (25/(ModoMax+1))-1 movwf M ; 25 / numero di modi movf Pattern,w ; In questa modalita' usa il pattern 0 movwf IndiceColore ; Memorizza il valore del Pattern nella variabile IndiceColore clrf Pattern CicloDisegnaCambiaModo: movf V,w xorwf Modo,w btfss _Z goto NoIndice Indice: movf i,w movwf y movlw HIGH 0800h ; indirizza il program memory alla pagina 1 movwf PCLATH call LeggePattern call ScriveVideo NoIndice: movf i,w xorwf M,w btfss _Z goto NoTacca Tacca: movlw (25/(ModoMax+1)) ; Incrementa di una lunghezza di tacca addwf M,f incf V,f NoTacca: incf i,f movlw 25 subwf i,w btfss _C goto CicloDisegnaCambiaModo movf IndiceColore,w ; Copia il valore memorizzato temporaneamente back in Pattern movwf Pattern goto TrasmetteVideoTornaMainloop NoCambiaModo: ; MODO 0 (normale) e 1(sfumato) ; Se il sensore Ir1 > 0 allora come ingresso utilizza questo come input, altrimenti utilizza il segnale audio (prima di passare all'ingresso audio il sensore IR deve restare a zero per un certo tempo) ; Piu l'input aumente, piu luci vengono accese (partendo dalla parte alta) ; il colore delle luci viene determinato dalla tabella che memorizza la sequenza di colori rainbow ; il primo colore in alto viene determinato dall'indice, il secondo colore del livello sottostante e' una posizione in piu rispetto al'indice e cosi' via... ; l'indice viene incrementato l'input aumenta e rimane invariato quando diminuisce movf Modo,w xorlw 0 ; Modo 0 btfsc _Z goto Modo0 movf Modo,w xorlw 1 ; Modo 1 btfsc _Z goto Modo0 goto NoModo0 Modo0: ; call MinMaxAudio ; converte in un numero compreso tra 0 e 25 AudioScal ; movf IR1diff,w ; l = IR1diff ; movwf l ; per prova metto in l il segnale audio ; movlw 255 ; subwf audio,w ; movwf l Call CalcolaValoreVu btfss IngressoAudioMano goto Modo0IndiceSecondoMano Modo0IndiceSecondoAudio: movf ManoPrecedente,w ; confronta ValoreVu con il precedente subwf ValoreVu,w btfss _C subwf IndiceColore,f ; Se e' aumentato incrementa IndiceColore che indica l'indice da cui partire per il pattern di colori goto Modo0DopoIndice Modo0IndiceSecondoMano: movlw 25 ; Se e' maggiore di 25 fa effetto scrollevole subwf ValoreVu,w btfss _C goto Modo0NoEffettoScorrevoleManoB movwf ManoPrecedente bcf _C rrf ManoPrecedente,f bcf _C rrf ManoPrecedente,f incf ManoPrecedente,w subwf IndiceColore,f goto Modo0DopoIndice Modo0NoEffettoScorrevoleManoB: movf ManoPrecedente,w ; confronta ValoreVu con il precedente subwf ValoreVu,w btfsc _C subwf IndiceColore,f ; Se e' aumentato incrementa IndiceColore che indica l'indice da cui partire per il pattern di colori Modo0DopoIndice: movf ValoreVu,w movwf ManoPrecedente movf Modo,w xorlw 0 ; Modo 0 btfsc _Z call CancellaVideo movf Modo,w xorlw 1 ; Modo 1 btfss _Z goto Modo0NonScurisce call Scurisce call Scurisce Modo0NonScurisce: clrf i ; azzera contatore i CicloModo0: movf ValoreVu,w subwf i,w ; confronta ValoreVu con i btfss _C goto Mode0Acceso Mode0Spento: clrf rgb+0 clrf rgb+1 clrf rgb+2 goto Mode0DopoAccesoSpento Mode0Acceso: movf i,w ; y = i addwf IndiceColore,w ; aggiunge l'offset movwf y Modo0ControllaIndicey: movlw 25 ; Se y e' maggiore o uguale a 25 allora sottrae 25 subwf y,w btfss _C goto Modo0NoSottrae25IndiceY movwf y goto Modo0ControllaIndicey Modo0NoSottrae25IndiceY: movlw HIGH 0800h ; indirizza il program memory alla pagina 1 movwf PCLATH call LeggePattern movf i,w movwf y call ScriveVideo Mode0DopoAccesoSpento: incf i,f ; incrementa i movf i,w xorlw 25 ; confronta i con 25 btfss _Z goto CicloModo0 call Copia24Sotto NoModo0: ; MODO 2 ; Palla che rimbalza movf Modo,w xorlw 2 ; Modo 2 btfss _Z goto NoModo2 Modo2: Call CalcolaValoreVu btfsS IngressoAudioMano goto Modo2NoAudio movf ValoreVu,w movwf PosMano sublw 255 movwf VelMano ; ; sublw 15 ; btfsc _C ; goto Modo2NoAudio ; movlw 15 ; movwf VelPalla goto Modo2NoMano Modo2NoAudio: ; Calcola la posizione della mano che e' IR1scalato * FattoreScalaIR clrf PosMano movlw FattoreScalaIR movwf i CicloPosMano: movf IR1scalato,w addwf PosMano,f decfsz i,f goto CicloPosMano Modo2NoMano: ; PosPalla = PosPalla + VelPalla ; se il bit 7 di VelPalla = 0 allora aggiunge ; se = 1 allora toglie btfsc VelPalla,7 goto VelocitaNeg VelocitaPos: movf VelPalla,w addwf PosPalla,f movlw 255 btfsc _C movwf PosPalla goto DopoVelocita VelocitaNeg: movf VelPalla,w addwf PosPalla,f movlw 0 btfss _C movwf PosPalla DopoVelocita: decfsz l,f goto NonDiminuisceVeloCitaPalla movlw 10 movwf l decf VelPalla,f ; VelPalla = VelPalla - 1 NonDiminuisceVeloCitaPalla: movf PosMano,w ; Se PosPalla <= (PosMano + FattoreScalaIr) addlw FattoreScalaIR subwf PosPalla,w btfsc _C goto PallaNonSuperatoMano goto PallaSuperatoMano PallaSuperatoMano: movf PosMano,w ; PosPalla = PosMano + FattoreScalaIR addlw FattoreScalaIR movwf PosPalla BCF _C BTFSC VELPALLA,7 BSF _C rRf VelPalla,f ; VelPalla = -VelPalla / 2 COMF VELPALLA,F movf VelMano,w ; VelPalla = VelPalla - VelMano (cosi funziona) subwf VelPalla,f ; movf VelMano,w ; VelPalla = VelPalla + VelMano (cosi va al contrario) ; addwf VelPalla,f movf VelPalla,w ; soglia minima di velocita' per non fare rimbalzare la palla all'infinito sublw 4 btfsc _C clrf VelPalla PallaNonSuperatoMano: movlw 124 ; Se PosizionePalla > 124 subwf PosPalla,w btfss _C goto PallaNonSuperatoLimiteMassimo movlw 124 ; PosizionePalla = 124 movwf PosPalla rRf VelPalla,f ; VelPalla = -VelPalla / 2 bcf VelPalla,7 comf VelPalla,f PallaNonSuperatoLimiteMassimo: movlw 124 ; Se PosizioneMano > 124 subwf PosMano,w btfss _C goto ManoNonSuperatoLimiteMassimo movlw 124 ; PosizioneMano = 124 movwf PosMano ManoNonSuperatoLimiteMassimo: call Scurisce call Scurisce call Scurisce movlw 255 movwf ValoreVu movf PosPalla,w CicloCalcolaVu: incf ValoreVu,f addlw (256-FattoreScalaIR) btfsc _C goto CicloCalcolaVu incf IndiceColore+1,f btfss IndiceColore+1,3 goto IndiceColoreNonIncrementato clrf IndiceColore+1 incf IndiceColore,w movwf IndiceColore sublw 24 btfss _C clrf IndiceColore IndiceColoreNonIncrementato: movlw HIGH 0800h ; indirizza il program memory alla pagina 1 movwf PCLATH call LeggePassoPattern ; se e' zero allora non deve incrementare l'indice colore e lo riporta a zero movf y,f btfsc _Z clrf IndiceColore CicloColoraPalla: movf IndiceColore,w movwf y movlw HIGH 0800h ; indirizza il program memory alla pagina 1 movwf PCLATH call LeggePattern movf PallaPrecedente,w movwf y call ScriveVideo movf PallaPrecedente,w subwf ValoreVu,w btfsc _Z goto EsceCicloPalla btfss _C goto DecrementaPallaPrecedente IncrementaPallaPrecedente: incf PallaPrecedente,f goto CicloColoraPalla DecrementaPallaPrecedente: decf PallaPrecedente,f goto CicloColoraPalla EsceCicloPalla: movlw HIGH 0800h ; indirizza il program memory alla pagina 1 movwf PCLATH call LeggePassoPattern ; se e' zero allora allora usa come colore della mano quello all'opposto (24) movf y,w btfsc _Z movlw 24 addwf IndiceColore,f movlw 25 subwf IndiceColore,w btfsc _C movwf IndiceColore movlw 255 movwf ValoreVu movf PosMano,w CicloCalcolaVuMano: incf ValoreVu,f addlw (256-FattoreScalaIR) btfsc _C goto CicloCalcolaVuMano CicloColoraMano: movf IndiceColore,w movwf y movlw HIGH 0800h ; indirizza il program memory alla pagina 1 movwf PCLATH call LeggePattern movf ManoPrecedente,w movwf y call ScriveVideo movf ManoPrecedente,w subwf ValoreVu,w btfsc _Z goto EsceCicloMano btfss _C goto DecrementaManoPrecedente IncrementaManoPrecedente: incf ManoPrecedente,f goto CicloColoraMano DecrementaManoPrecedente: decf ManoPrecedente,f goto CicloColoraMano EsceCicloMano: ; riporta il colore a quello precedente movlw HIGH 0800h ; indirizza il program memory alla pagina 1 movwf PCLATH call LeggePassoPattern ; se e' zero allora allora usa come colore della mano quello all'opposto (24) movf y,w btfsc _Z movlw 24 sublw 25 addwf IndiceColore,f movlw 25 subwf IndiceColore,w btfsc _C movwf IndiceColore call Copia24Sotto NoModo2: ; MODO 3 ; Luce modulata in intensita' che va dal basso verso l'alto movf Modo,w xorlw 3 ; Modo 3 btfss _Z goto NoModo3 Modo3: call CalcolaValoreVu movf ValoreVu,w movwf y sublw 24 movlw 24 btfss _C movwf y ; clrf y movlw HIGH 0800h ; indirizza il program memory alla pagina 1 movwf PCLATH call LeggePattern call ScalaRgb movf rgb+0,w movwf RGBsotto+0 movf rgb+1,w movwf RGBsotto+1 movf rgb+2,w movwf RGBsotto+2 movlw 24 movwf y call ScriveVideo call SpostaInAlto NoModo3: ; MODO 4 ; Modalita' strobo light movf Modo,w xorlw 4 ; Modo 4 btfss _Z goto NoModo4 Modo4: clrf rgb+0 ; azzera la variabile RGB clrf rgb+1 clrf rgb+2 incf PosMano,f movf PosMano,w ; PosMano e' il contatore che determina quando le luci strobo sono accese o spente sublw (StroboOn+StroboOff) btfss _C clrf PosMano ; riporta a zero se il valore ha superato StroboOn+StroboOff call CalcolaValoreVu movf ValoreVu,w subwf ManoPrecedente,f btfsC _Z goto Modo4NonAccedeStrobo btfsc _C goto Modo4NonAccedeStrobo ; movf PosMano,w ; sublw StroboOn ; btfss _C ; goto Modo4StroboSpento movf Pattern,w xorlw 3 btfss _Z goto Modo4NonSostituisceBianco movlw 255 movwf rgb+0 movwf rgb+1 movwf rgb+2 goto Modo4NonAccedeStrobo Modo4NonSostituisceBianco: incf IndiceColore,w movwf IndiceColore sublw 24 btfss _C clrf IndiceColore movf IndiceColore,w movwf y movlw HIGH 0800h ; indirizza il program memory alla pagina 1 movwf PCLATH call LeggePattern Modo4NonAccedeStrobo: movf ValoreVu,w addlw 1 btfsc IngressoAudioMano addlw 2 movwf ManoPrecedente clrf i Modo4CicloI: movf i,w movwf y call ScriveVideo incf i,f movf i,w xorlw 25 btfss _Z goto Modo4CicloI call Copia24Sotto NoModo4: TrasmetteVideoTornaMainloop: call TrasmetteVideo goto MainLoop ; Cacola ValoreVu combinando gli ingressi Ir1 e Audio CalcolaValoreVu: movf z1,f btfss _Z ; verifica se z1 non e' zero decf z1,f ; se non e' zero decrementa bcf IngressoAudioMano movf IR1scalato,f btfss _Z goto Modo0Ir1NonZero Modo0Ir1Zero: ; Se l'ingresso IR1 e' zero bsf IngressoAudioMano movlw 1 ; decrementa valorevu, se fa il rollover porta a zero subwf ValoreVu,f btfsc _C goto Modo0NoVuZero clrf ValoreVu Modo0NoVuZero: movf AudioScal,w ; Se il valore corrente e' maggiore del valore vu allora ... subwf ValoreVu,w movf AudioScal,w btfss _C movwf ValoreVu ; ... valorevu =AudioScal movf z1,w ; w = z1 /8 movwf y bcf _C rrf y,f bcf _C rrf y,f bcf _C rrf y,w subwf ValoreVu,f ; ValoreVu=ValoreVu - z1 btfss _C clrf ValoreVu ; se e' negativo porta a zero return Modo0Ir1NonZero: ; se l'ingresso Ir1 non e' zero movlw PassaAudio ; resetta la variabile z1 movwf z1 movf IR1scalato,w ; il valore Vu = ingresso Ir1 movwf ValoreVu Modo0Ir1DopoZero: ; movwf ValoreVu return Copia24Sotto: movlw 24 movwf y call LeggeVideo movf rgb+0,w movwf RGBsotto+0 movf rgb+1,w movwf RGBsotto+1 movf rgb+2,w movwf RGBsotto+2 return ; Scurisce ; Ingresso un colore nella variabile RGB ; Uscita lo stesso colore RGB scurito e memorizzato sempre nella variabile RGB ; utilizza la variabile y ;Scurisce: ; bcf _C ; red 1/2 ; rrf rgb+0,w ; movwf rgb+0 ; movwf y ; ; bcf _C ; red aggiunge 1/4 ; rrf y,w ; movwf y ; addwf rgb+0 ; ; bcf _C ; green 1/2 ; rrf rgb+1,w ; movwf rgb+1 ; movwf y ; ; bcf _C ; green aggiunge 1/4 ; rrf y,w ; movwf y ; addwf rgb+1 ; ; ; bcf _C ; blue 1/2 ; rrf rgb+2,w ; movwf rgb+2 ; movwf y ; ; bcf _C ; blue aggiunge 1/4 ; rrf y,w ; movwf y ; addwf rgb+2 ; ; return ; ; gruppo di istruzioni IRoffSub: ; memorizza il valore dell'AD in IRoff ; incrementa faseint ; att = 1 ; IRsaturo = 0 ; imposta tempo di attesa: attesatime = 1 ; va a ImpAudio IRoffSub: BANKSEL ADRESL ; BANK 1 movf ADRESL,w BANKSEL ADRESH ; Banco di memoria 0 movwf IRoff ; copia byte L movf ADRESH,w movwf IRoff+1 ; byte H incf faseint,f ; incrementa faseint movlw 1 movwf att ; att = 1 bcf IRsaturo ; IRsaturo = 0 movlw 1 movwf attesatime ; attesatime = 1 goto ImpAudio ; funzione IRonSub ; memorizza il valore dell'AD in IRon ; +-- SI -- att = 1 ; | | NO ; | att = 16 -- SI -- incrementa faseint, spegne led IR, ritorna dalla chiamata di funzione ; | | NO ; | IRsaturo = 0 --- NO -------------+ ; | | SI | ; | IRon < SogliaIRsaturo -- NO -- spegne LED IR (tutti) ; | | SI IRdiff = IRdiff x 2 ; | | IRsaturo = 1 ; +---------> IRdiff= IRon - IRoff | ; +---------------------------+ ; | ; attesatime = att ; att = att x 2 ; ritorna dalla chiamata di funzione IRonSub: BANKSEL ADRESL ; BANK 1 movf ADRESL,w BANKSEL ADRESH ; Banco di memoria 0 movwf IRon ; copia byte L movf ADRESH,w movwf IRon+1 ; byte H btfsc att,0 ; testa bit 0 goto IRonDiff ; se att = 1 allora va a IRonDiff btfsc att,4 ; testa bit 4 goto IRonIncrementaRitorna ; se att = 16 allora va a IRonIncrementaRitorna btfsc IRsaturo ; se e' gia saturo allora spegne i LED IR goto IRonSpegneLED movlw low SogliaIRsaturo ; vint = SogliaIRsaturo movwf vint movlw high SogliaIRsaturo movwf vint+1 movf IRon,w ; vint=vint-IRon subwf vint,f movf IRon+1,w btfss _C incfsz IRon+1,w subwf vint+1,f btfsc _C ; se e' negativo il carry = 0 e quindi salta l'istruzione successiva e spegne il led IR goto IRonDiff ; altrimenti calcola la differenza IRonSpegneLED: bcf IR1 ; spegne tutti i led IR bcf IR2 bcf IR3 ; bcf _C ; azzera il carry ; rlf IRdiff,f ; IRdiff = IRdiff x 2 ; rlf IRdiff+1,f movf IRdiff,w ; IRdiff = IRdiff + (3/4 x IRdiff) movwf vint movf IRdiff+1,w movwf vint+1 bcf _C rrf vint+1,f rrf vint,f ADD16 IRdiff,vint bcf _C rrf vint+1,f rrf vint,f ADD16 IRdiff,vint bsf IRsaturo ; IRsaturo = 1 goto IRonAttesatime IRonDiff: ; IRdiff = IRon - IRoff movf IRon,w ; IRdiff = IRon movwf IRdiff movf IRon+1,w movwf IRdiff+1 movf IRoff,w ; IRdiff=IRdiff-IRoff subwf IRdiff,f movf IRoff+1,w btfss _C incfsz IRoff+1,w subwf IRdiff+1,f btfsc _C ; se il risultato e' negativo goto IRonAttesatime clrf IRdiff ; azzera IRdiff clrf IRdiff+1 IRonAttesatime: movf att,w movwf attesatime ; attesatime = att bcf _C ; azzera il carry rlf att,f ; att = att x 2 return ; ritorna dalla chiamata IRonIncrementaRitorna: incf faseint,f ; incrementa faseint bcf IR1 ; spegne tutti i led IR bcf IR2 bcf IR3 return ; ritorna dalla chiamata ; rutine di delay per attendere l'acquisition time dell'AD (durata 27 op, bastano 25 operazioni, 5us, 1 op = 0.2 us) DelayAcq: ; call 2 op movlw 7 ; 1 op movwf iint ; 1 op decfsz iint ; 1 x 7 goto $-1 ; 2 x 7 return ; 2 op ; Rutine per resettare la comunicazione con la LED strip, portando a livello zero il clock per 500 us ResettaLed: movlw 200 ; x=200 movwf x CicloAttendeReset: bcf LedPixelDat ; azzera anche la linea dati bcf LedPixelClock ; azzera la linea clock decfsz x,f ; 1 ciclo goto CicloAttendeReset ; 2 cicli return ; Invia il valore di colore in rgb alla LED strip ; variabile rgb (3 bytes) indica il colore InviaLed: movlw 24 movwf x rlf rgb+0,w CicloInviaDatoRgb: bcf LedPixelClock ; porta clock a livello basso btfss rgb+0,7 ; considera solo il bit piu significativo bcf LedPixelDat ; la linea dati della led strip viene cambiata di conseguenza btfsc rgb+0,7 bsf LedPixelDat rlf rgb+2,f ; sposta a sinistra i bytes nella variabile rgb rlf rgb+1,f rlf rgb+0,f bsf LedPixelClock ; viene dato un impulso di clock decfsz x,f ; viene decrementato x goto CicloInviaDatoRgb return ; Calcola MinAudio e lo incrementa e MaxAudio e lo decrementa ;MinMaxAudio: ; movlw DimMax ; Decrementa MaxAudio di DimMax ; subwf MaxAudio+0,f ; btfss _C ; decf MaxAudio+1,f ; ; movf MaxAudio+1,f ; verifica se il byte alto e' zero ; btfss _Z ; goto NoByteHMaxAudio0 ; se si allora verica che il byte L e' maggiore del minimo ; INIT16 MaxAudio,MaxAudioMinimo ; movlw MaxAudioMinimo ; w = valore minimo ; subwf MaxAudio+0,w ; movlw MaxAudioMinimo ; btfss _C ; movwf MaxAudio+0 ; se MaxAudio Max ; movf V+0,w ; Ma = Ma - V = Max - V ; subwf Ma+0,f ; movf V+1,w ; btfss _C ; incf V+1,w ; subwf Ma+1,f ; btfsc _C ; goto NonAggiornaMax ;AggiornaMax: ; movf V+0,w ; se e' negativo (vol > max) allora aggiorna max ; movwf MaxAudio+0 ; movwf M+0 ; movf V+1,w ; movwf MaxAudio+1 ; movwf M+1 ;NonAggiornaMax: ; goto Moltiplica2 ; salta alla rutine ScalaAudio saltando la prima parte che copia i valori nelle variabili (le variabili sono gia impostate) ; Rutine che scala il valore rgb ; rgb = colore in ingresso da scalare ; ValoreVu = 0-24 (se maggiore di 24 considera come valore massimo) ; utilizza le variabili V M Ma t ScalaRgb: clrf V+1 clrf M+1 clrf Ma+1 clrf V+0 clrf M+0 clrf Ma+0 movf ValoreVu,w BTFSC _z GOTO ScalaRgbZero movwf t sublw 24 ; se t > 24 riporta a 24 movlw 24 btfss _C movwf t CicloMoltiplicaScalaRgb: movf rgb+0,w addwf V,f btfsc _C incf V+1,f movf rgb+1,w addwf M,f btfsc _C incf M+1,f movf rgb+2,w addwf Ma,f btfsc _C incf Ma+1,f decfsz t,f goto CicloMoltiplicaScalaRgb LSL16 V ; moltiplica 8 LSL16 V LSL16 V copy16 t,V ; COPIA LSR16 V ; divide 4 LSR16 V add16 t,v ; aggiunge LSR16 V ; divide 4 LSR16 V add16 t,v ; aggiunge LSR16 V ; divide 4 LSR16 V add16 t,v ; aggiunge LSR16 V ; divide 2 add16 t,v ; aggiunge movf t+1,w movwf rgb+0 LSL16 M ; moltiplica 8 LSL16 M LSL16 M copy16 t,M ; COPIA LSR16 M ; divide 4 LSR16 M add16 t,M ; aggiunge LSR16 M ; divide 4 LSR16 M add16 t,M ; aggiunge LSR16 M ; divide 4 LSR16 M add16 t,M ; aggiunge LSR16 M ; divide 2 add16 t,M ; aggiunge movf t+1,w movwf rgb+1 LSL16 Ma ; moltiplica 8 LSL16 Ma LSL16 Ma copy16 t,Ma ; COPIA LSR16 Ma ; divide 4 LSR16 Ma add16 t,Ma ; aggiunge LSR16 Ma ; divide 4 LSR16 Ma add16 t,Ma ; aggiunge LSR16 Ma ; divide 4 LSR16 Ma add16 t,Ma ; aggiunge LSR16 Ma ; divide 2 add16 t,Ma ; aggiunge movf t+1,w movwf rgb+2 return ScalaRgbZero: clrf rgb+0 clrf rgb+1 clrf rgb+2 return ; Rutine che scala il valore del segnale audio ; audio (2 bytes) = indica l'intensita' del segnale audio ; MaxAudio (2 bytes) = Massimo valore del segnale audio ; AudioScal = valore scalato compreso tra 0-25 ScalaAudio: movf audio,w ; V = audio movwf V movf audio+1,w movwf V+1 ; ; V = V - MinAudio ; movf MinAudio+0,w ; subwf V+0,f ; movf MinAudio+1,w ; btfss _C ; incf MinAudio+1,w ; subwf V+1,f ; btfsc _C ; goto NonAzzeraV1 ; clrf V+0 ; se e' negativo allora V=0 ; clrf V+1 ;NonAzzeraV1: ; PRIMA USAVA COME RIFERIMENTO IL MAX AUDIO ; movf MaxAudio,w ; M = MaxAudio ; movwf M ; movf MaxAudio+1,w ; movwf M+1 ; ADESSO USA LA MEDIA movf Media+0,w movwf t movf Media+1,w movwf M+0 movf Media+2,w movwf M+1 bcf _c ; M = Media * 4 rlf t,f rlf M+0,f rlf M+1,f bcf _c rlf t,f rlf M+0,f rlf M+1,f ; COPY16 T,V ; SUBI16 t,SogliaAudio ; btfsc _C ; goto NonAzzeraAudio ; clr16 V ;NonAzzeraAudio: COPY16 T,M SUBI16 t,MaxAudioMinimo btfsc _C goto NonSettaMaxAudio INIT16 M,MaxAudioMinimo NonSettaMaxAudio: Moltiplica2: ; moltiplica per due bsf _C ; M = M x 2 ; prima era cosi: ; bcf _C ; M = M x 2 rlf M+0,f rlf M+1,f bcf _C ; V = V x 2 rlf V+0,f rlf V+1,f ; confronta M con 1024 x 26 = 26624 (H=104,L=0) movf M+1,w sublw 104 btfsc _Z ; se il byte alto e' 104 allora esce dal ciclo goto MMaggiore25600 btfsc _C goto Moltiplica2 ; se non e' negativo moltiplica ancora per due MMaggiore25600: ; in questo caso M e' maggiore di 26624 bcf _C ; M = M /2 rrf M+1,f rrf M+0,f bcf _C ; V = V /2 rrf V+1,f rrf V+0,f movf M+0,w ; Ma = M movwf Ma+0 movf M+1,w movwf Ma+1 movf V+0,w ; Va = V movwf Va+0 movf V+1,w movwf Va+1 bcf _C ; Ma = Ma /2 rrf Ma+1,f rrf Ma+0,f bcf _C ; Va = Va /2 rrf Va+1,f rrf Va+0,f goto SommaScala SommaScala: movf M+0,w ; se il byte L e' zero allora verifica il byte H e' 104 btfsc _Z goto ByteLZeroConfrontaByteH ConfrontaByteH: ; verifica se il byte H e' minore o maggiore di 104 movf M+1,w sublw 104 btfsc _Z ; se il byte alto e' 104 e il byte L e' diverso da zero allora M > 26624 e deve decrementare goto ToglieScala btfsc _C goto AggiungeScala ; 100-M e' positivo e quindi M puo' essere ancora incrementato ToglieScala: movf Ma+0,w ; M = M - Ma subwf M+0,f movf Ma+1,w btfss _C incfsz Ma+1,w subwf M+1,f movf Va+0,w ; V = V - Va subwf V+0,f movf Va+1,w btfss _C incfsz Va+1,w subwf V+1,f bcf _C ; Ma = Ma /2 rrf Ma+1,f rrf Ma+0,f bcf _C ; Va = Va /2 rrf Va+1,f rrf Va+0,f AggiungeScala: movf Ma+0,w ; M = M + Ma addwf M+0,f btfsc _C incf M+1,f movf Ma+1,w addwf M+1,f movf Va+0,w ; V = V + Va addwf V+0,f btfsc _C incf V+1,f movf Va+1,w addwf V+1,f goto SommaScala ByteLZeroConfrontaByteH: movf M+1,w ; se il byte H e' 104 allora esce dal ciclo xorlw 104 btfss _Z goto ConfrontaByteH ; altrimenti confronta il byte H per vedere se e' maggiore o minore di 104 FineScala: bcf _C ; divide V (byte H) per 4 rrf V+1,f bcf _C rrf V+1,f movf V+1,w ; confronta V (byte H) con 25 sublw 25 movf V+1,w btfss _C ; se e' maggiore di 25 allora w=25 movlw 25 movwf AudioScal ; copia il valore convertito in AudioScal return ; Funzione che linearizza la risposta esponenziale dei sensori Ir ; Ingresso Irdiff (16 bit) ; torna risultato in z 0-255 LinearizzaIr: clrf i ; i = 0 movlw SogliaMinIr ; IRdiff(16bit) = IRdiff - SogliaMinIr subwf IRdiff,f btfss _C decf IRdiff+1,f incfsz IRdiff+1,w ; se il byte H di IRdiff ha fatto il rollover allora torna con zero goto CicloLinearizza goto LinearizzaEsci CicloLinearizza: incf i,f ; i = i +1 BTFSS i,7 goto NoRolloverLinearizza RolloverLinearizza: ; nel caso i sia arrivato a 128 lo porta a 255 ed esce con questo valore movlw 255 ; poi il valore di iint andrebbe moltiplicato per 2 movwf i goto LinearizzaEsci NoRolloverLinearizza: movf i,w ; IRdiff(16bit) = IRdiff - i(8bit) subwf IRdiff,f btfss _C decf IRdiff+1,f incfsz IRdiff+1,w ; se il byte H di IRdiff ha fatto il rollover allora esce dal ciclo goto CicloLinearizza bcf _C ; moltiplica per 2 rlf i,f btfsc _C ; se c'e' il riporto porta i a 255 ed esce goto RolloverLinearizza LinearizzaEsci: movf i,w ; w = i return ; per prova qunado viene premuto il pulsante resetta l'audiomax ;PulsantePremuto: ; INIT16 MaxAudio,MaxAudioMinimo ; ; return OnOff: movlw 50 movwf i CicloSpegneLuci: btfss NuovoIrMisurato goto CicloSpegneLuci bcf NuovoIrMisurato call Scurisce call Copia24Sotto call TrasmetteVideo clrf IR1Diff clrf IR2Diff clrf IR3Diff decfsz i,f goto CicloSpegneLuci CicloOff: bcf INTCON,GIE bcf IR1 bcf IR2 bcf IR3 btfss Pulsante goto CicloOff bsf INTCON,GIE CicloOn: btfss NuovoIrMisurato goto CicloOn bcf NuovoIrMisurato goto MainLoop ; Legge la memoria video ; y = posizione (0-24) ; rgb = valore letto LeggeVideo: call IndirizzaVideo movf INDF,w ; copia 3 bytes della memoria in rgb movwf rgb+0 incf FSR,f movf INDF,w movwf rgb+1 incf FSR,f movf INDF,w movwf rgb+2 return ; Scrive la memoria video ; y = posizione (0-24) ; rgb = valore da scrivere ScriveVideo: call IndirizzaVideo movf rgb+0,w ; copia rgb nella memoria video movwf INDF incf FSR,f movf rgb+1,w movwf INDF incf FSR,f movf rgb+2,w movwf INDF return ; Indirizza il puntatore FSR alla locazione di memoria video secondi la variabile y (0-24) ; funzione chiamata da LeggeVideo e ScriveVideo IndirizzaVideo: movf y,w movwf FSR ; FSR = y x 3 addwf FSR,f addwf FSR,f bsf STATUS,IRP ; setta il bit IRP per indirizzare nel BANK 2 movlw 32 addwf FSR,f ; aggiunge offset prima locazione di memoria return ; Cancella memoria video CancellaVideo: clrf y call IndirizzaVideo movlw 75 ; t+1 = 75 movwf t+1 CicloCancellaPagina: clrf INDF incf FSR,f decfsz t+1,f ; se t+1 e' arrivato a zero esce dal ciclo goto CicloCancellaPagina return ; Trasmette memoria video TrasmetteVideo: call ResettaLed clrf V CicloTrasmette: movf V,w ; y incrementa fino a 24 poi torna indietro movwf y movlw 25 subwf V,w btfss _C goto NoSuperato25 sublw 24 movwf y NoSuperato25: call IndirizzaVideo movlw 3 ; t+1 = 3 movwf t+1 CicloTrasmetteTreByte: movf INDF,w movwf t movlw 8 movwf x CicloTrasmetteUnByte: bcf LedPixelClock ; porta clock a livello basso btfss t,7 ; considera solo il bit piu significativo bcf LedPixelDat ; la linea dati della led strip viene cambiata di conseguenza btfsc t,7 bsf LedPixelDat rlf t,f ; sposta a sinistra i bytes nella variabile bsf LedPixelClock ; viene dato un impulso di clock decfsz x,f ; viene decrementato x goto CicloTrasmetteUnByte incf FSR,f decfsz t+1,f ; se t+1 e' arrivato a zero esce dal ciclo goto CicloTrasmetteTreByte incf V,f ; incrementa V fino a 49, quando supera 49 esce dal ciclo movf V,w sublw 49 btfsc _C goto CicloTrasmette return ; Sposta verso l'alto il contenuto della memoria video SpostaInAlto: movlw 1 movwf y call IndirizzaVideo movlw 72 ; t+1 = 72 (24 *3) movwf t+1 CicloSpostaInAlto: movf INDF,w movwf t movlw 3 subwf FSR,f movf t,w movwf INDF movlw 4 addwf FSR,f decfsz t+1,f ; se t+1 e' arrivato a zero esce dal ciclo goto CicloSpostaInAlto return ; Scurisce il contenuto della memoria video Scurisce: clrf y call IndirizzaVideo movlw 75 ; t+1 = 75 movwf t+1 CicloScurisce: bcf _C ; INDF = INDF / 2 rrf INDF,w movwf t movwf INDF bcf _C ; INDF = INDF + 1/4 INDF rrf t,w movwf t addwf INDF,f bcf _C ; INDF = INDF + 1/8 INDF rrf t,w addwf INDF,f incf FSR,f decfsz t+1,f ; se t+1 e' arrivato a zero esce dal ciclo goto CicloScurisce return ; Pagina 1 del program memory org 0800h RitornaDaPagina1: movlw HIGH 0005h ; imposta il program counter latch H sulla pagina 0 prima di tornare dalla chiamata movwf PCLATH return ; Fare una LOOK up table da 25 posizioni (0-24) per dei pattern di colori ; pattern = indica quale pattern usare ; y = posizione nel pattern (0-25) ; torna con il valore nella variabile rgb (3 bytes) LeggePattern: movlw LOW InizioTabellaPattern ; t = indirizzo tabella pattern movwf t+0 movlw HIGH InizioTabellaPattern movwf t+1 movf Pattern,w ; verifica se Pattern=0 movwf x ; x = Pattern btfsc _Z goto PatternZero CicloSommaOffPattern: movlw 75 ; t = t + 75 addwf t+0,f btfsc _C incf t+1 decfsz x,f ; decrementa x, esce dal ciclo se zero goto CicloSommaOffPattern PatternZero: movf y,w ; verifica se y=0 movwf x ; x = Y btfsc _Z goto YZero CicloSommaY: movlw 3 ; t = t + 3 addwf t+0,f btfsc _C incf t+1 decfsz x,f ; decrementa x, esce dal ciclo se zero goto CicloSommaY YZero: call LeggeTabellaPattern ; legge red movwf rgb+0 incf t+0 ; incrementa t btfsc _Z incf t+1 call LeggeTabellaPattern ; legge green movwf rgb+1 incf t+0 ; incrementa t btfsc _Z incf t+1 call LeggeTabellaPattern ; legge blue movwf rgb+2 goto RitornaDaPagina1 LeggeTabellaPattern: movf t+1,w movwf PCLATH movf t+0,w movwf PCL InizioTabellaPattern: INCLUDE "pattern.txt" ; Look up table che torna un valore che indica come combinare i colori nel Pattern ; pattern = indica quale pattern usare ; torna con il valore nella variabile y LeggePassoPattern: movlw LOW InizioTabellaPassoPattern ; t = indirizzo tabella Passo pattern addwf Pattern,w movwf t+0 movlw HIGH InizioTabellaPassoPattern movwf t+1 btfsc _C incf t+1 call LeggeTabellaPattern movwf y goto RitornaDaPagina1 InizioTabellaPassoPattern: INCLUDE "PassoPattern.txt" END