Programació en mpasm del PIC 16F690

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

Monitor cardíac

En aquest projecte volem fer un sistema per monitoritzar el ritme cardíac. Per fer-ho disposarem d'un sensor que ens dona un senyal analògic amb una forma aproximada del pols cardíac. Aquest sensor el tindrem connectat a l'entrada analògica AN8 de la placa amb una matriu de vuit per vuit LED tricolor que incorpora una pantalla sèrie, un brunzidor i cinc polsadors.

sensor

El sensor incorpora un LED i un sensor de llum, a part d'altres elements electrònics. Es coloca sobre el dit (amb una cinta que l'aguanta) o al lòbul de l'orella (amb una pinça). El sensor de llum rep més o menys llum provinent del LED segons el moment del cicle cardíac. El senyal de sortida del sensor és similar al que es mostra a la figura següent. Els valors concrets poden ser diferents segons el ritme cardíac, la tensió d'alimentació i la forma com està col·locat el sensor.

senyal

Veiem que, fonamentalment, el senyal té una zona vall i un pols. Ens interessen els polsos. Seguint les recomanacions del fabricant, considerarem que es passa de pols a vall en el centre del senyal. Per trobar el centre agafarem el valor màxim i el mínim i cercarem el punt mig. Considerarem que el cicle cardíac comença cada cop que travessem el valor central del senyal en sentit ascendent. A la següent gràfica s'indiquen els valors que acabem de comentar i, en vermell, el nom de la variable que farem servir per guardar-los. Els noms en verd no es corresponen estrictament amb les variables del mateix nom.

mesura

Atès que no ens cal molta precisió, llegirem el senyal analògic amb només vuit bits. El nostre programa detecta els inicis de pols i en mesura el període; a més encén un LED quan hi ha el pols i l'apaga a la zona vall. Farem servir el Timer 1 per fer una lectura cada 2 ms. Anem a veure quina pot ser la configuració del Timer 1. La taula següent té les possibles opcions:

Bits Escala Període Iteracions Preselecció
11 1/8 8 μs 250 65286
10 1/4 4 μs 500 65036
01 1/2 2 μs 1000 64536
00 1/1 1 μs 2000 63536

Hem escollit un factor de 8, de manera que el temporitzador s'incrementarà cada 8 μs. Atès que cal fer 250 iteracions per tenir 2 ms, calculem les preseleccions:

	TMR1 = 65536 - 250 = 65286
	TMR1H = 65286 / 256 = 255
	TMR1L = 65286 % 256 = 6

Presentarem dues formes de llegir el sensor. En la primera, més senzilla, tindrem una funció que anirà fent lectures del sensor cada 15 s i ens retornarà el nombre de pulsacions per minut. En el segon mètode farem servir una funció d'interrupció que anirà determinant, pràcticament en temps real, el període del ritme cardíac. Cada mètode presenta avantatges i inconvenients. Amb el primer triguem més de 15 s entre l'inici de la mesura i el resultat però ja tenim directament les pulsacions; en canvi, amb el segon tenim mesures més seguides. Si fem servir la matriu de LED, atès que el segon mètode fa servir interrupcions, pot interferir-se amb les interrupcions de la matriu (que, recordem, tenen una funció que dura força temps) i això pot portar a mesures que no siguin del tot correctes.

Versió senzilla

Veiem que, fonamentalment, el senyal té una zona vall i un pols. Ens interessen els polsos. El fabricant, recomana considerar que es passa de pols a vall (o al contrari) en el centre del senyal. Per trobar el centre agafarem el valor màxim i el mínim i cercarem el punt mig, la mitjana. Per evitar problemes causats per petites oscil·lacions, considerarem que el pols comença quan el senyal supera la mitjana entre el centre i el màxim i que acaba quan baixa de la mitjana entre el centre i el mínim. A la següent gràfica s'indiquen els valors que acabem de comentar i, en vermell, el nom de la variable que farem servir per guardar-los. En verd s'indica el període del senyal, que no farem servir.

mesura

A continuació presentarem una funció que primer cerca els valors que hem indicat a la imatge anterior (mentrestant Centre = 0) i després compta el nombre de polsos que es produeixen en quinze segons. Amb aquesta dada, calcula les pulsacions per minut, que és el valor que retorna. La funció també encén un LED quan hi ha el pols i l'apaga a la zona vall. Això és útil per veure si tenim el sensor ben posat en el dit. La determinació dels valors màxim, mínim i central es fa durant 2048 ms, temps suficient per veure entre un i uns pocs polsos. Les variables que emprarem en la funció seran les següents:

Nom Mida Finalitat Observacions
Max 1 byte Valor màxim del senyal en un període
Min 1 byte Valor mínim del senyal en un període
Centre 1 byte Valor mig del senyal en un període Centre = (Max + Min) / 2
Puja 1 byte Valor en el que considerem l'inici del pols Puja = (Max + Centre) / 2
Baixa 1 byte Valor en el que considerem el final del pols Baixa = (Min + Centre) / 2
Polsos 1 byte Durant l'execució, compta els polsos
Al final, conté les pulsacions per minut
Temps 2 bytes Compta el nombre de finals del timer, per comptar el temps
Lectura 1 byte Valor llegit a l'entrada analògica
Bits 1 byte Variable on guardarem els bits d'estat que fem servir
Pols 1 bit S'activa quan el senyal està per sobre del centre Bits,0

Guardem els valors en el que considerem l'inici i el final del pols a Puja i Baixa per claredat; si anéssim malament de memòria, els podríem guardar a Max i Min perquè aquests ja no els necessitarem. A continuació tenim un programa senzill que llegeix les pulsacions i les envia a la pantalla sèrie.

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
#define	ValComp	.6	; Nombre de repeticions per eliminar soroll
	cblock 0x20	; Zona de memòria de dades habitual
Max			; Valor màxim del senyal en un període
Min			; Valor mínim del senyal en un període
Puja			; Valor en el que considerem l'inici del pols
Baixa			; Valor en el que considerem el final del pols
Centre			; Valor mig del senyal en un període	
Polsos			; Durant l'execució, compta els polsos
			;   al final, conté les pulsacions per minut
Temps:2			; Compta el nombre de finals del timer, per comptar el temps	
Lectura			; Valor llegit del sensor
Bits			; Variable on guardarem els bits d'estat que fem servir	
			;	Pols	Bits,0	S'activa quan el senyal està per sobre del valor mig
D1			; Variable unitats de la conversió BCD
D2			; Variable desenes de la conversió BCD
D3			; Variable centenes de la conversió BCD
Caracter		; Caràcter o codi a enviar
Retard1			; Variables de retard	
Retard2
Retard3
	endc
	org 0
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	TRISB		; Tot el port B és de sortida
	movlw	b'11110000'	; Posa les potes dels LED com a sortida
	movwf	TRISC		; La resta del port C és entrada
	movlw	b'00010000'	; Posa el conversor a 1/8 de la freqüència
	movwf	ADCON1		; Copia W a la configuració del conversor A/D
	bsf	TXSTA,BRGH	; Configuració de velocitat
	bcf	BAUDCTL,BRG16	; Paràmetre de velocitat de 8 bits
	movlw	.25		; Velocitat de 9600 baud
	movwf	SPBRG		; Paràmetre de velocitat
	bcf	TXSTA,SYNC 	; Comunicació asíncrona
	bcf	TXSTA,TX9 	; Comunicació de 8 bits
	bcf	STATUS,RP0
	bsf	STATUS,RP1	; Tria el banc 2
	movlw	b'00000101'
	movwf	ANSEL		; Configura AN0 i AN2 com entrades analògiques
	movlw	b'00000001'
	movwf	ANSELH		; Configura AN8 com entrada analògica
	bcf	STATUS,RP1	; Tria el banc 0
	bsf	RCSTA,SPEN	; Activa comunicació sèrie
	bsf	STATUS,RP0	; Tria el banc 1
	bsf	TXSTA,TXEN 	; Activa comunicació
	bcf	STATUS,RP0	; Tria el banc 0
	movlw	5		; Retard d'1 s
	call	Rets		; Retard per esperar la inicialització de la pantalla
	movlw	.254		; Caràcter de control
	movwf	Caracter	; Ho guarda a la variable
	call	EnviaL		; Ho envia
	movlw	.1		; Esborra la pantalla i posa el cursor a l'inici
	movwf	Caracter	; Ho guarda a la variable
	call	EnviaL		; Ho envia
	movlw	b'00110000'	; Configuració de Timer1
				; 11 - Factor d'escala de 8
	movwf	T1CON		; Ho guarda al registre de configuració del Timer1
	movlw	b'00100001'	; activa el conversor A/D connectat a AN8
	movwf	ADCON0		; amb el resultat justificat per l'esquerra
	clrf	PORTC		; Apaguem els LED
				; Configurem el Timer
	movlw	.6		; Nova preselecció
	movwf	TMR1L		; Ho posem a TMR1L
	movlw	.255		; Nova preselecció
	movwf	TMR1H		; Ho posem a TMR1H
	bsf	T1CON,TMR1ON	; Engega el Timer1
Bucle
	call	Llegir
	movlw	.254		; Control de la posició del cursor
	movwf	Caracter	; Ho guarda a la variable
	call	EnviaL		; Ho envia
	movlw	.0		; Filera 1 columna 1
	iorlw	b'10000000'	; Posa el bit de posicionat a 1
	movwf	Caracter	; Ho guarda a la variable
	call	EnviaL		; Ho envia
	movf	Polsos,w	; Anem a escriure les pulsacions
	call	escriuBCD	; Escrivim
	movlw	.25		; Retard de 5 s
	call	Rets		; Retard
	goto	Bucle
				;
				; Llegim el sensor i guardem les pulsacions a Polsos
				;
Llegir
	clrf	Max		; Qualsevol lectura serà més gran o igual
	movlw	0xFF		; Valor màxim que cap en un byte
	movwf	Min		; Qualsevol lectura serà menor o igual
	clrf	Centre		; Serà 0 fins que determinem el seu valor
	clrf	Polsos		; Inicialment val zero
	clrf	Temps		; Posem Temps a zero
	clrf	Temps+1		; Posem Temps+1 a zero
	clrf	Bits		; Posa tots els bits a zero
	goto	PrimerCop	; El primer cop no cal esperar que acabi el temporitzador
bucPols				; Bucle que repetirem durant 15 s
	btfss	PIR1,TMR1IF	; Mira si Timer1 ha arribat a zero
				; Si hi ha arribat, no fa la instrucció següent
	goto	bucPols		; Si no hi ha arribat, repeteix la instrucció
				; Han passat 2 ms
PrimerCop
	bcf	T1CON,TMR1ON	; Atura momentàniament el Timer1
	movlw	.6		; Nova preselecció
	movwf	TMR1L		; Ho posem a TMR1L
	movlw	.255		; Nova preselecció
	movwf	TMR1H		; Ho posem a TMR1H
	bsf	T1CON,TMR1ON	; Torna a engegar el Timer1
	bcf	PIR1,TMR1IF	; Desactivem el bit
				; Llegim el sensor
	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
	movf	ADRESH,w	; Llegeix el valor (8 bits)
	movwf	Lectura		; I el guarda
	incf	Temps,f		; Incrementem Temps
	btfsc	STATUS,Z	; Si s'activa Z vol dir que hem incrementat un 255
	incf	Temps+1,f	; Si s'activa, incrementem el byte superior
	movf	Centre,f	; Si Centre és 0 estem buscant el centre
	btfsc	STATUS,Z	; Mirem si és 0
	goto	buscCentre
	btfss	Bits,0		; Mirem si Pols està activat o no
	goto	nopols
				; Si Pols està activat, busquem la vall
	movf	Lectura,w
	subwf	Baixa,w		; W = Baixa - Lectura
	btfss	STATUS,C	; C = 1 si Baixa >= Lectura
	goto	miraTemps	; Baixa < Lectura
	bcf	Bits,0		; Desactiva Pols
	bcf	PORTC,0		; Apaga el LED
	goto	miraTemps
nopols				; Si pols està desactivat, busquem el pic
	movf	Puja,w
	subwf	Lectura,w	; W = Lectura - Puja
	btfss	STATUS,C	; C = 1 si Lectura >= Puja
	goto	miraTemps	; Lectura < Puja
	bsf	Bits,0		; Activa Pols
	bsf	PORTC,0		; Encén el LED
	incf	Polsos,f	; Incrementa Polsos
miraTemps
				; El procés ha de durar fins que hagin passat 15000 ms
				; Això passa quan s'han fet 7500 cicles del timer
				; O sigui, quan Temps+1 = 29 i Temps = 76
	movlw	.29		; Mirarem Temps+1
	xorwf	Temps+1,w	; Compara
	btfss	STATUS,Z	; Si coincideixen, mirem Temps
	goto	bucPols		; Si no coincideixen, seguim
	movlw	.76		; Mirarem Temps
	xorwf	Temps,w		; Compara
	btfss	STATUS,Z	; Si coincideixen, ja estem
	goto	bucPols		; Si no coincideixen, seguim
				; Si ja estem, tenim els polsos en 15 s
				; Cal multiplicar per 4 per tenir pulsacions per minut
	bcf	STATUS,C	; Entrarem zeros
	rlf	Polsos		; Multipliquem per 2
	bcf	STATUS,C	; Entrarem zeros
	rlf	Polsos		; Multipliquem per 2
	return			; Tornem al lloc des d'on hem vingut
buscCentre
	movf	Max,w		; W = Max
	subwf	Lectura,w	; W = Lectura - Max
	btfss	STATUS,C	; C = 1 si Lectura >= Max
	goto	noMax		; Lectura < Max
	movf	Lectura,w	; Agafa Lectura
	movwf	Max		; i ho guarda a Max
noMax
	movf	Lectura,w	; W = Lectura
	subwf	Min,w		; W = Min - Lectura
	btfss	STATUS,C	; C = 1 si Min >= Lectura
	goto	noMin		; Min < Lectura
	movf	Lectura,w	; Agafa Lectura
	movwf	Min		; i ho guarda a Min
noMin
				; Mirem si han passat els 2048 ms (1024 activacions del timer)
				; Implica que Temps+1 >= 4
	movlw	4		; Valor que hem de superar
	subwf	Temps+1,w	; W = Temps+1 - 4
	btfss	STATUS,C	; C = 1 si Temps+1 >= 4
	goto	bucPols		; Si no ha passat el temps, repetim el bucle
				; Anem a calcular els valors i inicialitzem el temps
				; Centre = (Max + Min) / 2
	movf	Max,w		; Agafa Max
	addwf	Min,w		; Ho suma amb Min i el resultat queda a W
				; Si en portem C serà 1 i si no serà 0
	movwf	Centre		; Els darrers 8 bits de la suma a Centre
	rrf	Centre,f	; Dividim per 2 (rodem a la dreta) afegint el novè bit
				; Guardem aquests valors a Puja i Baixa per claredat
				; Si anéssim malament de memòria, els podríem guardar
				; a Max i Min perquè ja no els necessitarem
	movf	Centre,w	; Agafa Centre
	addwf	Max,w		; Ho suma amb Max i el resultat queda a W
				; Si en portem C serà 1 i si no serà 0
	movwf	Puja		; Els darrers 8 bits de la suma a Puja
	rrf	Puja,f		; Dividim per 2 (rodem a la dreta) afegint el novè bit
	movf	Centre,w	; Agafa Centre
	addwf	Min,w		; Ho suma amb Min i el resultat queda a W
				; Si en portem C serà 1 i si no serà 0
	movwf	Baixa		; Els darrers 8 bits de la suma a Baixa
	rrf	Baixa,f		; Dividim per 2 (rodem a la dreta) afegint el novè bit
	clrf	Temps		; Posem Temps a zero
	clrf	Temps+1		; Posem Temps+1 a zero
				; Escrivim Max, Min, Centre, Puja i Baixa a la pantalla
				; Activant la línia següent podem fer que no es mostrin
	; goto	PrimerCop	; Torna a començar a mirar polsos
				; A la pantalla tindrem:
				; Polsos    Max       Min
				; Centre    Puja      Baixa
	movlw	.254		; Control de la posició del cursor
	movwf	Caracter	; Ho guarda a la variable
	call	EnviaL		; Ho envia
	movlw	.4		; Filera 1 columna 5
	iorlw	b'10000000'	; Posa el bit de posicionat a 1
	movwf	Caracter	; Ho guarda a la variable
	call	EnviaL		; Ho envia
	movf	Max,w
	call	escriuBCD	; Escrivim Max
	movlw	' '			; Espai en blanc
	movwf	Caracter	; Ho guarda a la variable
	call	EnviaL		; Ho envia
	movf	Min,w
	call	escriuBCD	; Escrivim Min
	movlw	.254		; Control de la posició del cursor
	movwf	Caracter	; Ho guarda a la variable
	call	EnviaL		; Ho envia
	movlw	.64		; Filera 2 columna 1
	iorlw	b'10000000'	; Posa el bit de posicionat a 1
	movwf	Caracter	; Ho guarda a la variable
	call	EnviaL		; Ho envia
	movf	Centre,w
	call	escriuBCD	; Escrivim Centre
	movlw	' '			; Espai en blanc
	movwf	Caracter	; Ho guarda a la variable
	call	EnviaL		; Ho envia
	movf	Puja,w
	call	escriuBCD	; Escrivim Puja
	movlw	' '			; Espai en blanc
	movwf	Caracter	; Ho guarda a la variable
	call	EnviaL		; Ho envia
	movf	Baixa,w
	call	escriuBCD	; Escrivim Baixa
	goto	PrimerCop	; Torna a començar a mirar polsos
				; Fi de la funció Llegir
				;
BCD				; Funció de conversió a BCD en ASCII
				; El valor a convertir està a W
				; El nombre resultant s'envia a la pantalla
	clrf	D3		; Posa D3 (centenes) a zero
	clrf	D2		; Posa D2 (desenes) a zero
	movwf	D1		; Guarda W (valor a convertir) a D1 
				; D1 són les unitats
Cent				; Anem a trobar les centenes (D3)
	movlw	.100		; Carrega 100 decimal a W
	subwf	D1,w		; Li resta W a D1
	btfss	STATUS,C	; Mira C i si és 1 no fa la següent
				; Si és 1 vol dir resultat positiu
	goto	Desen		; Si el resultat és negatiu les centenes ja estan
				; el valor de W es perd i anem a les desenes
	movwf	D1		; Guarda el resultat (W) a D1
	incf	D3,f		; La centena restada a D1 l'afegeix a D3
	goto	Cent		; Tornem-ho a fer
Desen				; Anem a trobar les desenes
	movlw	.10		; Carrega 10 decimal a W
	subwf	D1,w		; Li resta W a D1
	btfss	STATUS,C	; Mira C i si és 1 no fa la següent
				; Si és 1 vol dir resultat positiu
	goto	Final		; Si el resultat és negatiu les desenes ja estan
				; el valor de W es perd i anem a ASCII
	movwf	D1		; Guarda el resultat (W) a D1
	incf	D2,f		; La desena restada a D1 l'afegeix a D2
	goto	Desen		; Tornem-ho a fer
Final
	movlw	'0'		; Carrega el codi ASCII del número 0
				; Sumant-li la xifra tindrem el codi ASCII
	addwf	D3,f		; Ho afegeix al dígit
	addwf	D2,f		; Ho afegeix al dígit
	addwf	D1,f		; Ho afegeix al dígit
	movf	D3,w		; Llegeix el dígit
	xorlw	'0'		; Compara amb 0
	btfss	STATUS,Z	; Si Z està activat eren iguals
	return			; Si no eren iguals, ja estem
	movlw	' '		; Carrega un espai en blanc
	movwf	D3		; Substitueix el 0 per l'espai
	movf	D2,w		; Llegeix el dígit
	xorlw	'0'		; Compara amb 0
	btfss	STATUS,Z	; Si Z està activat eren iguals
	return			; Si no eren iguals, ja estem
	movlw	' '		; Carrega un espai en blanc
	movwf	D2		; Substitueix el 0 per l'espai
	return
escriuBCD			; Convertim el valor a ASCII i l'escrivim
				; El valor a convertir està a W
				; El nombre resultant s'envia a la pantalla
	call	BCD		; Primer el convertim a BCD
	movf	D3,w		; Llegeix el dígit
	movwf	Caracter	; El prepara per enviar
	call	EnviaL		; L'envia
	movf	D2,w		; Llegeix el dígit
	movwf	Caracter	; El prepara per enviar
	call	EnviaL		; L'envia
	movf	D1,w		; Llegeix el dígit
	movwf	Caracter	; El prepara per enviar
	call	EnviaL		; L'envia
	return
				;
				; Funció de retard de 0,2 W s
				;
Rets
	movwf	Retard3
Bucles
	decfsz	Retard1,f		
	goto	Bucles		
	decfsz	Retard2,f		
	goto	Bucles		
	decfsz	Retard3,f	
	goto	Bucles
	return
				;
				; Enviem caràcters a visualitzar
				;
EnviaL					
	movf	Caracter,w	; Agafa el caràcter
	movwf	TXREG		; L'envia
	nop
	nop			; Espera 2 us
	btfss	PIR1,TXIF	; El registre TXREG ha quedat lliure?
	goto	$-1		; No, doncs esperem
	return			; Tornem al lloc des d'on hem vingut
	end

Versió basada en interrupcions

La lectura i el tractament del sensor el farem amb una funció d'interrupció que es representa al diagrama següent. En el diagrama hem indicat, amb text de color verd, les etiquetes a les que salta el programa en cada punt. Podem observar que la funció té tres parts: una primera en la que es guarden els valors màxims i mínims del senyal mesurat, una segona en la que es fa el tractament del senyal per detectar els inicis i finals de pols i una tercera en la que es detecta que el ritme cardíac és inferior a 30 pulsacions per minut.

programa

Les variables que emprarem seran les següents:

Nom Mida Finalitat Observacions
Lectura 1 byte Valor llegit a l'entrada analògica
Temps 2 bytes S'incrementa cada cop que es fa la interrupció
(cada 2 ms)
Max 1 byte Valor màxim del senyal en un període
Min 1 byte Valor mínim del senyal en un període
Centre 1 byte Valor mig del senyal en un període Centre = (Max + Min) / 2
Periode 2 bytes Quart de període (en ms) Guarda la meitat del nombre d'interrupcions
entre dos inicis de pols
Comp 1 byte Comptador per filtrar soroll
Bits 1 byte Variable on guardarem els bits d'estat que fem servir
Pols 1 bit S'activa quan el senyal està per sobre del valor mig Bits,0
Tenim1 1 bit S'activa quan ja hem detectat l'inici del primer pols Bits,3
Estable 1 bit S'activa quan ja hem detectat l'inici del segon pols i,
per tant, ja tenim dades útils
Bits,2

La primera cosa que fem a cada interrupció és llegir l'entrada AN8, on tenim el sensor, i incrementar la variable Temps. Si el valor llegit és superior a Centre, mirarem si és més gran que el màxim que tenim guardat. En cas afirmatiu guardarem el nou valor com a màxim. Per al mínim fem una cosa similar però amb un afegit. És freqüent que, després del pic, hi hagi un segon pic en sentit contrari i, també, que hi hagi soroll en la zona vall. Per això no començarem a cercar el mínim fins que hagi passat mig període. Atès que no sabem el que dura un cicle fins que no ha acabat, fem servir les dades del cicle anterior.

A la segona part de la funció mirem si estàvem (a la interrupció anterior) en la part superior (Pols = 1) o en la inferior (Pols = 0). En la superior comprovem si estem per sota de la meitat, en quin cas voldria dir que ja deixem d'estar a la part superior. Una comprovació similar fem en la part inferior però comprovant que hem passat de mig període com a mesura per filtrar soroll. En tots dos casos no fem res fins que hem detectat que estem per sobre o per sota del mig sis vegades (que comptem amb la variable Comp) per tal de filtrar soroll. Quan ja està clar que estem per sota del valor mig desactivem Pols i calculem uns nous valors de Max, Min i Centre a partir del pols que acabem de veure. D'altra banda, quan ja està clar que estem per sobre del valor mig actualitzem el valor de la variable Periode i reinicialitzem la variable Temps. En tots dos casos reiniciem Comp.

Els valors de les variables només són fiables quan ja hem vist dos inicis de pols. Tenim dos bits de control que ens indiquen si les dades són estables o no. Inicialment els bits Tenim1 i Estable valen zero. Quan s'ha detectat el primer inici de pols s'activarà Tenim1 i quan es detecti el segon s'activarà Estable.

A la tercera part es mira si el temps transcorregut és superior a 2,048 s (la variable Temps és més gran que 1024) i si és així es reinicialitzen totes les variables per tornar a buscar el primer pols.

Disposarem també d'una pantalla sèrie on podrem indicar, per exemple, les pulsacions per minut. També podem mostrar altres valors o escriure text.

Si, per exemple, ens interessés mostrar les pulsacions a la pantalla, podríem comptar quants polsos es fan en un temps determinat. Per comptar el temps, podem incrementar una variable apropiada sabent que la funció d'interrupció s'executa cada 2 ms.

El programa de prova que conté la funció d'interrupció que hem comentat és el següent. Podem observar que en el bucle principal no hi ha res perquè l'única cosa que fem amb la lectura del sensor és encendre uns LED i això ho hem posat directament al final de la funció. Si fem servir la pantalla, segur que tindrem codi per posar al bucle.

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
#define	ValComp	.6	; Nombre de repeticions per eliminar soroll
	cblock 0x20	; Zona de memòria de dades habitual
Lectura			; Valor llegit a l'entrada analògica	
Temps:2			; S'incrementa cada cop que es fa la interrupció (cada 2 ms)	
Max			; Valor màxim del senyal en un període	
Min			; Valor mínim del senyal en un període	
Centre			; Valor mig del senyal en un període	
Periode:2		; Quart de període
			; Guarda la meitat del nombre d'interrupcions entre dos inicis de pols
Comp			; Comptador per filtrar soroll
Bits			; Variable on guardarem els bits d'estat que fem servir	
			;	Pols	Bits,0	S'activa quan el senyal està per sobre del valor mig
			;	Tenim1	Bits,3	S'activa quan ja hem detectat l'inici del primer pols
			; 	Estable	Bits,2	S'activa quan ja hem detectat l'inici del segon pols
			;			i, per tant, ja tenim dades útils
	endc
	cblock 0x70	; Zona de memòria que no depèn del banc triat
W_Copia			; Guardarà el contingut de W durant la interrupció
ST_Copia		; Guardarà STATUS durant la interrupció
	endc
	org 0
	goto	Inici		; Saltem al lloc on hi ha el programa principal
	nop			; Zona de memòria de programa que no utilitzem
	nop
	nop
Interrup
	movwf	W_Copia		; Copiem l'acumulador a W_Copia
	swapf	STATUS,w	; Copiem STATUS a l'acumulador permutant els nibbles
	clrf	STATUS		; Posa a 0 i així segur que el banc és el 0
	movwf	ST_Copia	; Guarda STATUS permutat a ST_Copia
	btfss	PIR1,TMR1IF	; Mira si Timer1 ha arribat a zero
				; Si hi ha arribat, no fa la instrucció següent
	goto	FiInt		; Si la interrupció no és del Timer0 no fem res
Timer1				; Programa corresponent a Timer0
	bcf	T1CON,TMR1ON	; Atura momentàniament el Timer1
	movlw	.6		; Nova preselecció
	movwf	TMR1L		; Ho posem a TMR1L
	movlw	.255		; Nova preselecció
	movwf	TMR1H		; Ho posem a TMR1L
	bsf	T1CON,TMR1ON	; Torna a engegar el Timer1
	bcf	PIR1,TMR1IF	; Si ha arribat, desactivem el bit
				; Llegim el sensor
	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
	movf	ADRESH,w	; Llegeix el valor (8 bits)
	movwf	Lectura		; I el guarda
	incf	Temps,f		; Incrementem Temps
	btfsc	STATUS,Z	; Si s'activa Z vol dir que hem incrementat un 255
	incf	Temps+1,f	; Si s'activa, incrementem el byte superior
	movf	Centre,w
	subwf	Lectura,w	; W = Lectura - Centre
	btfss	STATUS,C	; C = 1 si Lectura >= Centre
	goto	baix		; Lectura < Centre
				; Lectura >= Centre
	movf	Max,w
	subwf	Lectura,w	; W = Lectura - Max
	btfss	STATUS,C	; C = 1 si Lectura >= Max
	goto	mirapols	; Lectura < Max
				; Lectura >= Max
	movf	Lectura,w
	movwf	Max		; Guarda el nou màxim
	goto	mirapols	; Passem a la segona part
baix				; Lectura < Centre
				; Anem a mirar si Temps:2 > Periode:2
				; Si Temps+1 > Periode+1 segur que sí
				; Si Temps+1 < Periode+1 segur que no
				; Si Temps+1 = Periode+1 cal comprovar si Temps > Periode
	movf	Periode+1,w	
	subwf	Temps+1,w	; W = Temps+1 - Periode+1
	btfss	STATUS,C	; C = 1 si Temps+1 >= Periode+1
	goto	mirapols	; Temps+1 < Periode+1
				; Temps+1 >= Periode+1
	movf	Periode+1,w	
	xorwf	Temps+1,w	; Ho comparem amb Temps+1
	btfss	STATUS,Z
	goto	miramin		; Si són diferents és que Temps+1 > Periode+1
	movf	Periode,w
	subwf	Temps,w		; W = Temps - Periode
	btfss	STATUS,C	; C = 1 si Temps >= Periode
	goto	mirapols	; Temps < Periode
miramin				; Temps >= Periode
	movf	Min,w
	subwf	Lectura,w	; W = Lectura - Min
	btfsc	STATUS,C	; C = 1 si Lectura >= Min
	goto	mirapols	; Lectura >= Min
				; Lectura < Min
	movf	Lectura,w
	movwf	Min		; Guarda el nou mínim
mirapols
	btfsc	Bits,0		; Mira si Pols està activat
	goto	activat		; Sí ho està
	movf	Centre,w
	subwf	Lectura,w	; W = Lectura - Centre
	btfss	STATUS,C	; C = 1 si Lectura >= Centre
	goto	miratemps	; Lectura < Centre
				; Lectura >= Centre
				; Anem a mirar si Temps:2 > Periode:2
				; Si Temps+1 > Periode+1 segur que sí
				; Si Temps+1 < Periode+1 segur que no
				; Si Temps+1 = Periode+1 cal comprovar si Temps > Periode
	movf	Periode+1,w
	subwf	Temps+1,w	; W = Temps+1 - Periode+1
	btfss	STATUS,C	; C = 1 si Temps+1 >= Periode+1
	goto	miratemps	; Temps+1 < Periode+1
				; Temps+1 >= Periode+1
	movf	Periode+1,w
	xorwf	Temps+1,w	; Ho comparem amb Temps+1
	btfss	STATUS,Z
	goto	sipols		; Si són diferents és que Temps+1 > Periode+1
	movf	Periode,w
	subwf	Temps,w		; W = Temps - Periode
	btfss	STATUS,C	; C = 1 si Temps >= Periode
	goto	miratemps	; Temps < Periode
sipols
	decfsz	Comp,f		; Decrementa Comp
	goto	miratemps	; Si no ha arribat a zero, ja estem
	bsf	Bits,0		; Activa Pols
	movf	Temps+1,w
	movwf	Periode+1	; Periode+1 = Temps+1
	movf	Temps,w
	movwf	Periode		; Periode = Temps
	bcf	STATUS,C	; Volem entrar un zero
	rrf	Periode+1,f	; Dividim Periode per 2
	rrf	Periode,f
	clrf	Temps		; Posem Temps a zero
	clrf	Temps+1		; Posem Temps+1 a zero
	movlw	ValComp		; Nombre de repeticions per eliminar soroll
	movwf	Comp		; Ho posa a Comp
	btfss	Bits,3		; Mira si Tenim1 està activat
	goto	tenimpols	; Si no ho està, l'activa i surt
	btfss	Bits,2		; Mira si Estable està activat
	bsf	Bits,2		; Si no ho estava, l'activa
	goto	miratemps
activat
	movf	Centre,w
	subwf	Lectura,w	; W = Lectura - Centre
	btfsc	STATUS,C	; C = 1 si Lectura >= Centre
	goto	miratemps	; Lectura > Centre
				; Lectura <= Centre
	decfsz	Comp,f		; Decrementa Comp
	goto	miratemps	; Si no ha arribat a zero, ja estem
	bcf	Bits,0		; Desactiva Pols
	movf	Min,w
	movwf	Centre		; Guarda Min, provisionalment, a Centre
	movf	Max,w
	addwf	Centre,f	; Centre = Max + Min
				; Si ens en portem, quedarà a C
	rrf	Centre,f	; Dividim la resta per dos (les que portem entren per l'esquerra)
	movf	Centre,w	; El resultat queda a Centre
	movwf	Max		; I el copiem a Max
	movwf	Min		; i a Min
	movlw	ValComp		; Nombre de repeticions per eliminar soroll
	movwf	Comp		; Ho posa a Comp
miratemps
	movlw	.4		; Equival a menys de 30 pulsacions per minut
	subwf	Temps+1,w	; W = Temps+1 - 4
	btfss	STATUS,C	; C = 1 si Temps+1 >= 4
	goto	FiInt		; Temps+1 < 4
reinici
	clrf	Bits		; Posa tots els bits a zero
	clrf	Periode		; Posem Periode a zero
	clrf	Periode+1	; Posem Periode+1 a zero
	clrf	Temps		; Posem Temps a zero
	clrf	Temps+1		; Posem Temps+1 a zero
	movlw	.127		; Valor central del conversor (255/2)
	movwf	Centre		; Ho posa a Centre
	movwf	Max		; Ho posa a Max
	movwf	Min		; Ho posa a Min
	movlw	ValComp		; Nombre de repeticions per eliminar soroll
	movwf	Comp		; Ho posa a Comp
	goto	FiInt
tenimpols
	bsf	Bits,3		; Si no ho estava, l'activa
FiInt
	movf	Bits,w		; Agafa el valor de Bits
	movwf	PORTC		; Ho posa al port C; Només actúa el bit 0 (Pols)
	swapf	ST_Copia,w	; Copia permutant ST_Copia a l'acumulador
	movwf	STATUS		; I ho passa a STATUS recuperant el valor d'abans
				; de la interrupció
	swapf	W_Copia,f	; Permuta els bits de W_Copia
	swapf	W_Copia,w	; Torna a permutar els bits de W_Copia
				; i els guarda a l'acumulador sense variar STATUS
	retfie			; Torna al programa principal, on s'havia quedat
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	TRISB		; Tot el port B és de sortida
	movlw	b'11110000'	; Posa les potes dels LED com a sortida
	movwf	TRISC		; La resta del port C és entrada
	movlw	b'00010000'	; Posa el conversor a 1/8 de la freqüència
	movwf	ADCON1		; Copia W a la configuració del conversor A/D
	bsf	PIE1,TMR1IE	; Activa les interrupcions del timer 1
	bcf	STATUS,RP0
	bsf	STATUS,RP1	; Tria el banc 2
	movlw	b'00000101'
	movwf	ANSEL		; Configura AN0 i AN2 com entrades analògiques
	movlw	b'00000001'
	movwf	ANSELH		; Configura AN8 com entrada analògica
	bcf	STATUS,RP1	; Tria el banc 0
	movlw	b'00110000'	; Configuració de Timer1
				; 11 - Factor d'escala de 8
	movwf	T1CON		; Ho guarda al registre de configuració del Timer1
	bcf	PIR1,TMR1IF	; Desactivem el bit de fi del temporitzador
	movlw	b'00100001'	; activa el conversor A/D connectat a AN8
	movwf	ADCON0		; amb el resultat justificat per l'esquerra
				; Inicialització de variables
	clrf	Bits		; Posa tots els bits a zero
	clrf	Periode		; Posem Periode a zero
	clrf	Periode+1	; Posem Periode+1 a zero
	clrf	Temps		; Posem Temps a zero
	clrf	Temps+1		; Posem Temps+1 a zero
	movlw	.127		; Valor central del conversor (255/2)
	movwf	Centre		; Ho posa a Centre
	movwf	Max		; Ho posa a Max
	movwf	Min		; Ho posa a Min
	movlw	ValComp		; Nombre de repeticions per eliminar soroll
	movwf	Comp		; Ho posa a Comp
				; Configurem el Timer i activem interrupcions
	movlw	.6		; Nova preselecció
	movwf	TMR1L		; Ho posem a TMR1L
	movlw	.255		; Nova preselecció
	movwf	TMR1H		; Ho posem a TMR1L
	bsf	T1CON,TMR1ON	; Engega el Timer1
	movlw	b'11000000'	; Activem GIE i PEIE
	movwf	INTCON		; Activa les interrupcions globals i les de PIE1 i PIE2
Bucle
	goto	Bucle		; En el bucle no hi ha res
	end

 

 

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