Table of Contents

Pulse meter

Autor: Radu Caragea 335CA

Introducere

Descriere generala

Descriere senzor

S1 S0 Sensibilitate
Low Low Off
Low High x1
High Low x10
High High x100
S3 S2 Impartire output la
Low Low 1
Low High 2
High Low 10
High High 100

Hardware Design

Software Design

pulse.c
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#define F_CPU 16000000
#include <util/delay.h>
#include <util/atomic.h>
 
 
int uart_putchar(char c, FILE *unused);
int uart_getchar(FILE* f);
FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
FILE mystdin =  FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
 
 
 
#define WINDOWSIZE 12 
#define MEDINTERVAL 20 //20 ms
unsigned int vwindow[WINDOWSIZE];
 
 
void USART_init(void)
{
	UBRRH=0;
	UBRRL=103; //comunicare pe 9600 bps
 
	UCSRB=(0<<UCSZ2)|(1<<RXEN)|(1<<TXEN);
	UCSRC=(1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1); //8 biti de date
}
 
void COUNTER_init(void)
{
	TCCR1A=0;
	TCCR1B=0;
	TCCR1B=(1<<CS12)|(1<<CS11)|(1<<CS10);
	TCNT1=0;
}
int main(void)
{
	unsigned long currentpulses;
	unsigned int i=0;
	unsigned int counter=0;
	unsigned int j,lastpeak=0;
	unsigned long signalout=0,signalsum=0,signalmean=0,prevsignal=0;
	unsigned long bpm1=0,bpm2=0,bpm3=0,bpm=0;
 
	USART_init();
	stdin = &mystdin;
	stdout = &mystdout;
 
 
	DDRB=0xFF; //toate iesiri
	DDRA=0xFF; //toate iesiri
	DDRC=0xFF; //toate iesiri
 
	DDRB&=~(1<<1); //PB1 intrare -> T1 -> external counter
 
	PORTB=0;
	PORTA=0;
 
	PORTA &= ~(1<<0); //setam bitul 0 LOW;
	PORTB |= (1<<0); //setam bitul 0 HIGH;
 
	// S0 = H S1 = H
	PORTA |= (1<<3); // PA3 = S_0
	PORTA |= (1<<2); // PA2 = S_1 
 
	// S2 = L S3 = L
 
	//PORTB |= (0<<2); // PB2 = S2 = L;
	//PORTB |= (0<<3); // PB3 = S3 = L;
 
 
	COUNTER_init();
 
 
	PORTC=(1<<1); //Activare RED LED
 
	currentpulses = 0;
	while (1) {
		_delay_ms(MEDINTERVAL);
		currentpulses=TCNT1;
		TCNT1=0; //resetare si numarare din nou
 
		if(i < WINDOWSIZE) //umplere initiala
			vwindow[i]=currentpulses;
		else{
			signalout=0;
 
			//filtru Moving average
			for(j=0;j<WINDOWSIZE-1;j++){
				signalout += vwindow[j];
				vwindow[j]=vwindow[j+1];
			}
			signalout += vwindow[WINDOWSIZE-1];
			vwindow[WINDOWSIZE-1]=currentpulses;
 
			signalout=signalout/WINDOWSIZE;
 
			//se face media si pe semnalul filtrat pentru a avea o referinta la varfuri
			if(counter==MEDINTERVAL){
				signalmean=signalsum/MEDINTERVAL;
				signalsum=0;
				counter=0;
			}
 
			//se iau in considerare trecerile in jos de deasupra mediei semnalului 
			//datorita zgomotului se introduce o limitare hardcodata la 20
			//si pentru a pastra o continuitate se face media ultimelor 3 valori, atenuand fluctuatiile
			if(prevsignal>signalout && signalmean>prevsignal&&i-lastpeak>20){
				bpm3=bpm2; 
				bpm2=bpm1;
				//noua valoare:
				//60000 ms intr-un minut
				//se extrapoleaza distanta intre varfuri pentru 1 minut
				//rezulta BPM
				bpm1=(60000/MEDINTERVAL)/(i-lastpeak);
				bpm=(bpm1+bpm2+bpm3)/3;
				#ifdef BPM_OUT
					printf("Peak at %u. BPM is %lu\n",i,bpm);
				#endif
				lastpeak=i;
			}
			#ifndef BPM_OUT
				printf("%u %lu \n",i,signalout);
			#endif
			prevsignal=signalout;
		}
		i++;
		counter++;
		signalsum += signalout;
	}
	return 0;
}
 
 
// Functie ce trateaza trimiterea unui caracter pe seriala
int uart_putchar(char c, FILE *unused)      
{
	if (c == '\n')
		uart_putchar('\r', 0);
	loop_until_bit_is_set(UCSRA, UDRE);
	UDR = c;
	return 0;
}
 
// Functie ce trateaza primirea unui caracter pe seriala
int uart_getchar(FILE* f)
{
	char c;
 
    loop_until_bit_is_set(UCSRA, RXC);
    c = UDR;
    if(c=='\r')
		c='\n';
    uart_putchar(c,NULL); 
    return c;
}

Concluzii

Bibliografie

[1] http://en.wikipedia.org/wiki/Moving_average
[2] http://www.taosinc.com/getfile.aspx?type=press&file=tsl230r-lf-e3.pdf
[3] https://github.com/dkogan/feedgnuplot
[4] http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.60.4055&rep=rep1&type=pdf
[5] http://oximetry.org/pulseox/principles.htm
[6] http://en.wikipedia.org/wiki/Pulse_oximeter