Autor: Radu Caragea 335CA
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 |
#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; }
[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