Programació en mpasm del PIC 16F690

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

Monitor d'energia elèctrica

Programa del grup 2

Aquest grup va decidir fer els càlculs a partir del valor mig rectificat del corrent i mostrar una pantalla de l'estil següent:

IN: X,XX A  
POT: XXXX VA

Per fer el càlcul de la potència, el valor promig de tots els llegits (comptats tots positius) l'hem de dividir per 37,85 (factor del sensor de corrent) per tenir el valor mig rectificat del corrent. Aquest resultat el multiplicarem per π i el dividirem per dos i per arrel de dos per tenir-ne el valor eficaç. El valor eficaç del corrent s'haurà de multiplicar per 230 V per tenir la potència. Així doncs:

Càlcul de la potència

Amb aquest microcontrolador no és senzill fer multiplicacions si els nombres no són enters, per tant, el que podem fer és aproximar el 6,75 per una fracció de nombres enters. Com tampoc és senzill dividir per un nombre que no sigui potència de dos, intentarem trobar una fracció que tingui un denominador potència de dos; per exemple:

Càlcul de la potència

Un cop restats els 512, el valor màxim d'una lectura pot ser entre 0 i 189. Si el multipliquem per 275 estarà entre 0 i 51975 que cap en dos bytes.

De manera que multiplicarem el valor promig de les lectures per 27 (sumant-lo 27 cops). Per dividir per 4 només cal fer rodar els bits dos cops cap a la dreta.

Es volia mostrar el corrent però com el seu valor és petit (entre 0 i 5 A) es va decidir calcular-lo en cA però mostrar-lo en A posant una coma davant de la penúltima xifra. Així doncs, calia fer també el càlcul:

Càlcul de la potència

Aquest grup també va implementar que un LED s'encengués si la potència supera els 3 A; això es produeix quan el valor promig de tots els llegits supera 102.

El programa d'aquest grup és el següent:

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
	cblock 0x20
Lectura:.64		; Lectures
Comptador		; Comptador d'iteracions programa principal
Temp			; Variable temporal
Valor:2			; Valor d'entrada (16 bits)
Resul:5			; Valor de sortida
Control			; Bits de control (port B)
Caracter		; Caràcter o codi a enviar (port C)
Retard1			; Variables per als cicles de retard
Retard2
Retard3
Indir
Compt
Suma:2 			; Variable on guardarem la suma de tots els valors
Lec:2			; Variables on copiarem el valor mig de les lectures
Leds			; Variable de Leds
	endc
	org 0
Inici
	bsf 		STATUS,RP0	; Tria el banc 1
	movlw		b'10000001'	; Configuració de Timer0
					; Com a temporitzador basat en rellotge
					; 001 - Factor d'escala de 4
 					; I resistències de pull-up desactivades (valor per defecte)
	movwf		OPTION_REG	; Ho guarda al registre de configuració del Timer0
	movlw		0xFF		; Posa l'acumulador a FFh (tot uns)
	movwf		TRISA		; Posa tots els bits del port A com a entrada
	clrf		TRISB		; Tot el port B és de sortida
	clrf		TRISC		; Tot el port C és de sortida
	movlw		b'00010000'	; Posa el conversor a 1/8 de la freqüència
	movwf		ADCON1		; Copia W a la configuració del conversor A/D
	bcf 		STATUS,RP0
	bsf 		STATUS,RP1	; Tria el banc 2
	movlw		b'00000101'
	movwf		ANSEL		; Configura port AN0 i AN2 com entrades analògiques
	bcf 		STATUS,RP0
	bcf 		STATUS,RP1	; Tria el banc 0
 	movlw		b'10001001'	; activa el conversor A/D connectat a AN2
	movwf		ADCON0		; amb el resultat justificat per la dreta
 	clrf		Leds
 	call		IniPant		; Inicialització del mode de funcionament de la pantalla
	call		ConfPant	; Configuració de la pantalla
Programa
	movlw		.100		; Presselecció de 100, que són 156 iteracions (amb un factor 4 dona 624)
	movwf		TMR0		; Ho posa com a preselecció del temporitzador
	movlw		.32		; Volem 32 iteracions (32 lectures)
	movwf		Comptador	; Comptador d'iteracions
	movlw		Lectura		; Agafa l'adreça de la memòria de lectures
	movwf		FSR		; Adreçament indirecte
Bucle
	movlw		.100		; Presselecció de 100, que són 156 iteracions (amb un factor 4 dona 624)
	btfss		INTCON,T0IF	; Mira si Timer0 ha arribat a zero
					; Si hi ha arribat, no fa la instrucció següent
	goto		$-1		; Si no hi ha arribat, repeteix la instrucció
	bcf 		INTCON,T0IF	; Si ha arribat, desactivem el bit
	movwf		TMR0		; Ho posa com a preselecció del temporitzador
	nop				; espera un microsegon
	nop				; espera un microsegon
	nop				; espera un microsegon
	nop				; espera un microsegon
	nop				; espera un microsegon, en total 5
	bsf 		ADCON0,GO	; Inicia la conversió
	btfsc		ADCON0,GO	; Quan el bit sigui 0 la conversió haurà acabat
	goto		$-1		; repetim la línia fins que deixi de ser 1
	bsf 		STATUS,RP0	; Tria el banc 1
	movf		ADRESL,w	; Llegim byte inferior del resultat
	bcf 		STATUS,RP0	; Tria el banc 0
	movwf		INDF		; El guardem
	incf		FSR,f		; Incrementem punter
	movf		ADRESH,w	; Llegim byte superior del resultat
	movwf		INDF		; El guardem
	incf		FSR,f		; Incrementem punter
	decfsz		Comptador,f	; Decrementem el comptador
	goto		Bucle		; Repetim-ho...
	movlw		Lectura		; Agafa l'adreça de la memòria de lectures
	movwf		FSR 		; Adreçament indirecte
	clrf		Suma		; Posem la variabe Valor a 0
	clrf		Suma+1
	movlw		.32		; Fem 32 iteracions
	movwf		Comptador	; Comptador d'iteracions
BucleSuma 				; Llegeix Lectura i canvia el signe
	movf 		INDF,w
	movwf 		Valor
	incf 		FSR,f
	movf 		INDF,w
	movwf 		Valor+1
	incf 		FSR,f
	btfsc 		Valor+1,1	; mirem si el bit 1 de valor+1 és 0 ->negatiu
	goto 		positiu		; (si es 1 -> positiu salta)
	comf 		Valor,f		; fem el complementari de valor
	incf 		Valor,f		; sumem 1 a Valor
positiu					; ara ja tenim la lecutra en positiu
	movf 		Valor,w		; Llegim a W la variable que hem de sumar
	addwf 		Suma,f		; L'afegim al byte de la dreta
	btfsc		STATUS,C	; Mirem si s'activa C
	incf		Suma+1,f	; Si s'activa, incrementem el byte superior
	decfsz 		Comptador,f	; Decrementem el comptador
	goto 		BucleSuma 	; Repetim...
	movlw 		.5
	movwf 		Comptador
BucLEDividir 				; Aquest es el bucle que divideix per 2^5
	bcf 		STATUS,C	; Posem C a zero
	rrf 		Suma+1,f	; Fem rodar el byte de l'esquerra de la suma
					; i ho posem a f
	rrf 		Suma,f		; Ara fem rodar el byte de la dreta de la suma
					; aprofitant el bit que teníem a C
	decfsz 		Comptador,f
	goto 		BucLEDividir 	; Ja tenim el valor mig de la lectura a Suma:2
	movf 		Suma,w 		; Copiem Suma a Lec
	movwf 		Lec
	movf 		Suma+1,w 	; Copiem Suma+1 a Lec+1
	movwf 		Lec+1 		; Tenim una copia de la lectura mitja a Lec:2
					; Comparem el valor de la Lectura amb un Valor Limit
					; i si es mes gran encenem els Leds
	movlw 		.102
	subwf 		Lec,w
	btfss 		STATUS,C
	goto 		Petit
	bsf 		Leds,0
	goto 		PBucleSum
Petit
	clrf 		Leds
PBucleSum
	clrf 		Valor
	clrf 		Valor+1
					; Ara calculem i mostrem la Ieficaç
	movlw 		.47 		;(Aixi podrem tenir comes)
	movwf 		Comptador
BucleSum 				; Aquest es per multiplicar per 47
	movf 		Suma,w
	addwf 		Valor,f
	btfsc 		STATUS,C
	incf 		Valor+1,f
	decfsz 		Comptador,f
	goto 		BucleSum 	; A Valor+1,Valor tenim el numero multiplicat per 47
	movlw 		.4
	movwf 		Comptador
BucleDividir 				; Aquest es el bucle que divideix per 2^4
	bcf 		STATUS,C	; Posem C a zero
	rrf 		Valor+1,f	; Fem rodar el byte de l'esquerra de la suma
					; i ho posem a f
	rrf 		Valor,f		; Ara fem rodar el byte de la dreta de la suma
					; aprofitant el bit que teníem a C
	decfsz 		Comptador,f
	goto 		BucleDividir 	; Ja tenim el valor Ieficaç a Valor:2
	call 		BCD5 		; Ens converteix la Ieficaç
	call 		Separa 		; Tenim la Intensitat a Resul:5
					; Els enviem a la pantalla. Enviem l'adreça i els valors
	movlw		0x00		; Adreça DDRAM (Filera 1 - Posició 1)
	iorlw		b'10000000'	; Posa el bit de DDRAM a 1
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaC		; Ho envia
	movlw		'I' 		; Lletra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		'N' 		; Lletra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		':' 		; Dos punts
	movwf		Caracter 	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		' ' 		; Espai
	movwf		Caracter 	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf 		Resul+2,w 	; Unitats
	movwf		Caracter 	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		',' 		; Coma
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf 		Resul+1,w 	; Primers decimals
	movwf		Caracter 	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf 		Resul,w 	; Segons decimals
	movwf		Caracter 	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		' ' 		; Lletra
	movwf		Caracter 	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		'A' 		; Lletra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
 					; Ara calculem i mostrem la Potencia
	clrf 		Valor
	clrf 		Valor+1
	movlw 		.27
	movwf 		Comptador
BucleSuma2 				; Aquest es per multiplicar per 27
	movf 		Lec,w
	addwf 		Valor,f
	btfsc 		STATUS,C
	incf 		Valor+1,f
	decfsz 		Comptador,f
	goto 		BucleSuma2 	; A Valor+1,Valor tenim el numero multiplicat per 27
	movlw 		.2
	movwf 		Comptador
BucleDividir2 				; Aquest es el bucle que divideix per 2^2
	bcf 		STATUS,C	; Posem C a zero
	rrf 		Valor+1,f	; Fem rodar el byte de l'esquerra de la suma
					; i ho posem a f
	rrf 		Valor,f		; Ara fem rodar el byte de la dreta de la suma
					; aprofitant el bit que teníem a C
	decfsz 		Comptador,f
	goto 		BucleDividir2	; Ja tenim la Potencia a Valor:2
	call 		BCD5 		; Ens converteix la Potencia
	call 		Separa 		; Tenim la Potencia a Resul:5
	call		Neteja		; Ens neteja els 0 a l'esquerra.
					; Els enviem a la pantalla. Enviem l'adreça i els valors
	movlw		0x40		; Adreça DDRAM (2 - 1)
	iorlw		b'10000000'	; Posa el bit de DDRAM a 1
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaC		; Ho envia
	movlw		'P' 		; Lletra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		'O' 		; Lletra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		'T' 		; Lletra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		':' 		; Dos punts
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		' ' 		; Espai
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf 		Resul+3,w 	; Milers
	movwf		Caracter 	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf 		Resul+2,w 	; Centenes
	movwf		Caracter 	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf 		Resul+1,w 	; Decimals
	movwf		Caracter 	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf 		Resul,w 	; Unitats
	movwf		Caracter 	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		' ' 		; Espai
	movwf		Caracter 	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		'V' 		; Lletra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		'A' 		; Lletra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
Ret 					; Fem un bucle de Retard
	movlw 		.10 		; 20*0,2 són 4 segons de retard
	call 		Rets
	goto 		Programa
					; Aquí comencen les Subfuncions
BCD5					; Converteix a BCD
	movf		FSR,w		; Llegim el valor de FSR
	movwf		Indir		; I el guardem
	bcf		STATUS,C	; Posa a zero C per entrar zeros a les rotacions
	movlw		.16		; Nombre d'iteracions
	movwf		Compt		; Comptador d'iteracions
	clrf		Resul+2		; Desenes de miler
	clrf		Resul+1		; Unitats de miler i centenes
	clrf		Resul		; Desenes i unitats
BucleBCD
	rlf		Valor,f		; Girem bits a l'esquerra a valor
	rlf		Valor+1,f	; Cap a valor+1
	rlf		Resul,f		; I cap als resultats
	rlf		Resul+1,f
	rlf		Resul+2,f
	decfsz		Compt,f		; Decrementa Compt
	goto		ajust		; Si no és zero, ajustem el resultat
	movf		Indir,w		; Recuperem el valor de FSR
	movwf		FSR		; I el guardem al seu lloc
	retlw		0		; Si és zero ja estem; tornem un 0 a W
ajust					; funció d'ajust dels resultats
	movlw		Resul		; Agafem l'adreça del byte de menys pes
	movwf		FSR		; La posa a l'adreçament indirecte
	call		ajustBCD	; Ajusta el byte de més a la dreta
	movlw		Resul+1		; Agafem l'adreça del byte del mig
	movwf		FSR		; La posa a l'adreçament indirecte
	call		ajustBCD	; Ajusta el byte del mig
	movlw		Resul+2		; Agafem l'adreça del byte de més pes
	movwf		FSR		; La posa a l'adreçament indirecte
	call		ajustBCD	; Ajusta el byte de més a l'esquerra
	goto		BucleBCD	; Torna a repetir el bucle (fins a 16 cops)
ajustBCD				; funció d'ajust d'un byte, primer el nibble de la dreta,
					; després l'altre
	movlw		0x03		; Agafa el valor 03h
	addwf		INDF,w		; El suma al byte que ajustem
	movwf		Temp		; Ho guarda a Temp
	btfsc		Temp,3		; És més gran que 07h (s'ha activat el bit 3)?
	movwf		INDF		; Si és cert, sobreposa el resultat
	movlw		0x30		; Agafa el valor 30h
	addwf		INDF,w		; El suma al byte que ajustem
	movwf		Temp		; Ho guarda a Temp
	btfsc		Temp,7		; És més gran que 70h (s'ha activat el bit 7)?
	movwf		INDF		; Si és cert, sobreposa el resultat
	retlw		0		; Retorna amb un zero a W
Separa					; Separa els digits i els converteix a ASCII
	movf		FSR,w		; Llegim el valor de FSR
	movwf		Indir		; I el guardem
	movf		Resul+2,w	; Agafa les desenes de miler
	movwf		Resul+4		; Les posa al seu lloc
	swapf		Resul+1,w	; Llegeix les unitats de miler i les centenes i les guarda,
					; permutades, a w
	andlw		0x0F		; Es queda amb les unitats de miler
	movwf		Resul+3		; Les posa al seu lloc
	movf		Resul+1,w	; Llegeix les unitats de miler i les centenes i les guarda a w
	andlw		0x0F		; Es queda amb les centenes
	movwf		Resul+2		; Les posa al seu lloc
	swapf		Resul,w		; Llegeix les desenes i les unitats i les guarda, permutades, a w
	andlw		0x0F		; Es queda amb les desenes
	movwf		Resul+1		; Les posa al seu lloc
	movf		Resul,w		; Llegeix les desenes i les unitats i les guarda a w
	andlw		0x0F		; Es queda amb les unitats
	movwf		Resul		; Les posa al seu lloc
	movlw		.5		; Cal fer-ho 5 cops
	movwf		Compt		; Ho posem al comptador
	movlw		Resul+4		; Adreça de la darrera xifra
	movwf		FSR		; Adreçament indirecte
	movlw		'0'		; Carrega el codi ASCII del número 0
					; Sumant-li la xifra tindrem el codi ASCII
Bucle1
	addwf		INDF,f		; Ho afegeix al dígit
	decf		FSR,f		; Decrementa FSR
	decfsz		Compt,f		; Decrementa el comptador
	goto		Bucle1		; Si no és zero, repetim
Final
	movf		Indir,w		; Recuperem el valor de FSR
	movwf		FSR		; I el guardem al seu lloc
	retlw		0		; Retorna amb un 0 a W
Neteja					; Neteja els digits de 0s
	movf		FSR,w		; Llegim el valor de FSR
	movwf		Indir		; I el guardem
	movlw		.4		; Cal fer-ho 4 cops
	movwf		Compt		; Ho posem al comptador
	movlw		Resul+4		; Adreça de la darrera xifra
	movwf		FSR		; Adreçament indirecte
Bucle2
	movf		INDF,w		; Llegeix el dígit
	xorlw		'0'		; Compara amb 0
	btfss		STATUS,Z	; Si Z està activat eren iguals
	goto		Final2		; Si no eren iguals, ja estem
	movlw		' '		; Carrega un espai en blanc
	movwf		INDF		; Substitueix el 0 per l'espai
	decf		FSR,f		; Decrementa FSR
	decfsz		Compt,f		; Decrementa el comptador
	goto		Bucle2		; Si no és zero, repetim
Final2
	movf		Indir,w		; Recuperem el valor de FSR
	movwf		FSR		; I el guardem al seu lloc
	retlw		0		; Retorna amb un 0 a W
IniPant					; Inicialització del mode de funcionament de la pantalla
	movlw		0		; Comença un cicle de durada fixa (0,2 s)
					; Temps que cal esperar després d'un reset
	call		Retard		; Crida a la funció Retard, el paràmetre està a W
	movlw		b'00100000'	; Function set - Configuració inicial 0010 al nibble de l'esquerra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaI		; Envia els 4 bits superiors
					; Ara enviem la configuració 2 línea, 5x8 píxels 0010 1000
	call		EnviaI		; Enviem la part esquerra (ja ho teníem a Caracter)
	movlw		b'10000000'	; I ara la part dreta (però posada a l'esquerra)
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaI		; Envia els 4 bits superiors
	return				; Fi de la inicialització del mode de funcionament
ConfPant				; Configuració de la pantalla
	movlw		b'00001111'	; Display ON/OFF control - Activa la pantalla amb cursor intermitent
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaC		; Ho envia
	movlw		b'00000001'	; Clear display - Buida la pantalla i inicialitza
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaC		; Ho envia
	movlw		.5		; El punt indica que es un valor decimal
					; Comença un cicle de durada fixa (3,9 ms)
	call		Retard		; Crida a la funció Retard, el paràmetre està a W
	movlw		b'00000110'	; Entry mode - Buida la pantalla, sentit dreta i despl. automàtic
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaC		; Ho envia
	return				; Fi de la configuració de la pantalla
EnviaC					; Enviem caràcters de control
	bcf 		Control,7	; Desactiva E
	bcf 		Control,5	; Desactiva RS
	goto		Envia
EnviaL					; Enviem caràcters a visualitzar
	bcf 		Control,7	; Desactiva E
	bsf 		Control,5	; Activa RS
Envia
	call		EnviaN		; Envia els 4 bits més alts
	swapf		Caracter,f	; Permuta els nibbles
	call		EnviaN		; Envia els 4 bits més alts
	swapf		Caracter,f	; Torna a deixar els nibbles com estaven
	return				; Tornem al lloc des d'on hem vingut
EnviaI					; Enviem nibbles de caràcters de control
	bcf 		Control,7	; Desactiva E
	bcf 		Control,5	; Desactiva RS
EnviaN					; Enviem nibbles
	decfsz		Retard1,f	; Funció de retard de 0,8 ms
	goto		EnviaN
	movf		Control,w	; Copia Control a l'acumulador
	movwf		PORTB		; I ho posa al PORTB
	nop				; Espera 1 us
	nop				; Espera 1 us
	nop				; Espera 1 us
	movf		Caracter,w	; Llegeix el caràcter
	andlw		0xF0		; Agafa els 4 bits més alts
	iorwf 		Leds,w 
	movwf		PORTC		; Envia el byte
	bsf 		Control,7	; Activa E
	movf		Control,w	; Copia Control a l'acumulador
	movwf		PORTB		; I ho posa al PORTB
	nop				; Espera 1 us
	nop				; Espera 1 us
	nop				; Espera 1 us
	nop				; Espera 1 us
	nop				; Espera 1 us
	bcf 		Control,7	; Desactiva E
	movf		Control,w	; Copia Control a l'acumulador
	movwf		PORTB		; I ho posa al PORTB
	return				; Tornem al lloc des d'on hem vingut
Retard					; Funció Retard, W conté el nombre de cicles de 771 us que cal fer
	movwf		Retard2		; Ho copia a la variable Retard2
BucRet
	decfsz		Retard1,f	; Decrementa la variable 1
					; si dona zero, no es fa la instrucció següent
	goto		BucRet		; Salta, excepte si el resultat ha estat zero
	decfsz		Retard2,f	; Decrementa la variable 2
	goto		BucRet		; Salta, excepte si el resultat ha estat zero
	return				; Tornem al lloc des d'on hem vingut
Rets					; Funció de retard de 0,2 W s
	movwf		Retard3
Bucles
	decfsz		Retard1,f
	goto		Bucles
	decfsz		Retard2,f
	goto		Bucles
	decfsz		Retard3,f
	goto		Bucles
	return
	end

 

 

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