Programació en mpasm del PIC 16F690

Referència Trucs Perifèrics   Recursos CITCEA
Tutorial Exemples Projectes   Inici

Exemple PM - Mitjana de dades

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.

 

 

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