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.

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.

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.

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.
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.

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
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.

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

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