En aquest programa guardarem les vuit darreres lectures del potenciòmetre (només els vuit bits més significatius) 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.
PROCESSOR 16F690 #include <xc.inc> config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF
Visualit EQU 0x20 ; Definim una variable on guardem el que mostren els LED Vector EQU 0x21 ; Registre de 8 bytes on guardem les darreres 8 lectures (8 bytes) Retard EQU 0x29 ; Definim un registre de 2 bytes per fer els retards (2 bytes) Suma EQU 0x2B ; Suma (16 bits, 2 bytes) de les darreres lectures (2 bytes) Arrodon EQU 0x2D ; Mitjana (suma/8) arrodonida (16 bits, 2 bytes) temp EQU 0x2F ; Variable d'emmagatzematge temporal
PSECT code, class=CODE, delta=2, abs
main:
bsf 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
movlw 0xF0 ; Posa les potes dels LED com a sortida
movwf TRISC ; i la resta del PORT C com a entrada
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 RP0
bsf RP1 ; Tria el banc 2
movlw 0xFF ; Posa l'acumulador a FFh (tot uns)
movwf ANSEL ; Configura AN0-AN7 com entrades analògiques
bcf RP0
bcf 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 GO_DONE ; Inicia la conversió
btfss GO_DONE ; 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 ZERO ; 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 CARRY ; 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 CARRY ; 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 ZERO ; 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 CARRY ; 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 CARRY ; Posem C a zero
rrf Arrodon+1,f ; Dividim per 2 altre cop
rrf Arrodon,f ; Per tant, ja hem dividit per 4
bcf CARRY ; 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 CARRY ; 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 main
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.