En aquest programa guardarem les vuit darreres lectures del potenciòmetre i en farem la mitjana. Ens caldrà utilitzar un registre on guardar les vuit darreres lectures. Per fer la mitjana haurem de sumar i el resultat pot passar de 8 bits; així que caldrà treballar amb un registre de dos bytes. Treballar amb vuit lectures (8 és 23) és molt pràctic ja que per dividir per potències de dos només cal rodar els bits.
En lloc de sumar cada vegada els vuit elements del registre, el que fem és restar de la suma el valor més antic i quan posem el nou valor al registre el sumem a la suma. D'aquesta manera estalviem operacions.
En aquest exemple farem servir adreçament indirecte, variables de més d'un byte i operacions matemàtiques de més de 8 bits. També fem comparacions.
#include <p16F690.inc> __config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
cblock 0x20 Visualit ; Definim una variable on guardem el que mostren els LED Vector:8 ; Registre de 8 bytes on guardem les darreres 8 lectures Retard:2 ; Definim un registre de 2 bytes per fer els retards Suma:2 ; Suma (16 bits, 2 bytes) de les darreres lectures Arrodon:2 ; Mitjana (suma/8) arrodonida (16 bits, 2 bytes) temp ; Variable d'emmagatzematge temporal endc
Inici bsf STATUS,RP0 ; Tria el banc 1 movlw 0xFF ; Posa l'acumulador a FFh (tot uns) movwf TRISA ; Posa tots els bits del port A com a entrada clrf TRISC ; Posa tots els bits del port C com a sortida movlw 0x10 ; Posa el valor 10h (0001 0000) al registre W movwf ADCON1 ; Copia W a la configuració del conversor A/D ; Posa el conversor a 1/8 de la freqüència bcf STATUS,RP0 bsf STATUS,RP1 ; Tria el banc 2 movlw 0xFF ; Posa l'acumulador a FFh (tot uns) movwf ANSEL ; Configura AN0-AN7 com entrades analògiques bcf STATUS,RP0 bcf STATUS,RP1 ; Tria el banc 0 movlw 0x01 ; Posa el valor 01h (0000 0001) al registre W movwf ADCON0 ; activa el conversor A/D connectat a AN0 ; amb el resultat justificat per l'esquerra call Inicialit ; Inicialització del filtre Bucle call Retarda ; Funció de retard de 0,2 s bsf ADCON0,GO ; Inicia la conversió btfss ADCON0,GO ; Quan el bit sigui 0 la conversió haurà acabat goto $-1 ; repetim la línia fins que deixi de ser 0 movf ADRESH,w ; Copia els bits superiors a l'acumulador call Filtre ; Envia la lectura a la funció filtre movwf Visualit ; Guarda el resultat filtrat a Visualit swapf Visualit,w ; Permuta els nibbles i ho guarda a W movwf PORTC ; Copia el resultat sobre els LED goto Bucle ; Repetim-ho...
; ; Funció d'inicialització del filtre ; Inicialit clrf Suma ; Esborrem el primer byte de la suma clrf Suma+1 ; i també el segon movlw Vector ; Copia a W l'adreça del primer byte de Vector movwf FSR ; Ho guarda al registre d'adreçament indirecte Zero clrf INDF ; Esborrem tots els bytes de Vector incf FSR,f ; Incrementem el punter ; Cal comprovar que no sortim fora del registre movf FSR,w ; Copiem el punter a l'acumulador xorlw Vector+8 ; Estem a la posició 8? ; XOR dona zero (activa Z) si coincideixen btfss STATUS,Z ; Comprovem si la XOR ha donat zero ; si no era zero (Z = 0) no fem la següent goto Zero ; Si era zero, posem el punter a la primera posició movlw Vector ; Copia a W l'adreça del primer byte de Vector movwf FSR ; Ho guarda al registre d'adreçament indirecte return ; Fi de la funció ; ; Funció de filtre ; Filtre ; W té el darrer valor llegit al conversor movwf temp ; Ho guarda a una variable temporal movf INDF,w ; Copia el valor assenyalat per FSR a W subwf Suma,f ; El resta de la suma total btfss STATUS,C ; S'ha activat C? ; Si no s'ha activat vol dir que en portem decf Suma+1,f ; Decrementem el byte superior movf temp,w ; Tornem a posar la lectura del conversor a W movwf INDF ; la guardem a la taula addwf Suma,f ; i l'afegim a la suma btfsc STATUS,C ; Mirem si s'activa C incf Suma+1,f ; Si s'activa, incrementem el byte superior incf FSR,f ; Incrementem el punter ; Cal comprovar que no sortim fora del registre movf FSR,w ; Copiem el punter a l'acumulador xorlw Vector+8 ; Estem a la posició 8? ; XOR dona zero (activa Z) si coincideixen movlw Vector ; Per si cal, carreguem la primera posició a W ; Aquesta funció no afecta als bits d'estat btfsc STATUS,Z ; Comprovem si la XOR havia donat zero ; si no era zero (Z = 0) no fem la següent movwf FSR ; Si era zero, posem el punter a la primera posició bcf STATUS,C ; Posem C a zero rrf Suma+1,w ; Fem rodar el byte de l'esquerra de la suma ; i ho posem a W ; Rodar a la dreta equival a dividir per dos movwf Arrodon+1 ; Posa el resultat al byte de l'esquerra de Round rrf Suma,w ; Ara fem rodar el byte de la dreta de la suma ; aprofitant el bit que teníem a C movwf Arrodon ; i ho guardem al byte de la dreta d'Arrodon bcf STATUS,C ; Posem C a zero rrf Arrodon+1,f ; Dividim per 2 altre cop rrf Arrodon,f ; Per tant, ja hem dividit per 4 bcf STATUS,C ; Posem C a zero rrf Arrodon+1,f ; Dividim per 2 altre cop rrf Arrodon,f ; Per tant, ja hem dividit per 8 ; Ens falta arrodonir btfsc STATUS,C ; Mirem si C és 0 o 1 incf Arrodon,f ; Si és 0, incrementem un (arrodonim per excés) movf Arrodon,w ; Copiem el resultat a W per sortir return ; Fi de la funció de filtre ; ; Funció de retard de 0,2 s ; Retarda decfsz Retard,f ; És igual a les funcions de retard de programes goto $-1 ; anteriors però fent servir un registre de dos decfsz Retard+1,f ; bytes en lloc de dues variables goto $-3 return end
Observem que en haver definit el registre Retard com de dos bytes, no cal que totes les variables tinguin nom. Ens adrecem al primer byte posant Retard i al segon posant Retard+1.
Normalment quan feiem servir instruccions com movlw hi posàvem com a paràmetre un valor que era el que es carregava a l'acumulador. Si ens fixem en el començament de la funció d'inicialització veiem que el paràmetre és Vector; això fa que es carregui a l'acumulador l'adreça de la variable. Si volguéssim carregar el valor de la variable, faríem servir movf.
Quan proveu el programa, intenteu fer canvis bruscos a la posició del potenciòmetre. Veureu que el valor llegit als LED no canvia de cop sinó que el valor va augmentant o disminuïnt progressivament fins arribar a la nova lectura.

Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.