Example code to create a heartbeat sensor using the Si1146 on Silicon Lab's Biometrics expansion board for the Wonder Gecko

Dependencies:   EFM32_SegmentLCD Si114x mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* 
00002 Heart rate example for the SiLabs biometrics board using the Si1146
00003 
00004 Since their own example code is all hidden behind precompiled libraries, here an 
00005 example which is actually useful :D. Take into account this is an example, I just screwed
00006 around a bit and observed some output waveforms to make it work reasonable, there are
00007 for sure better ways to implement this.
00008 
00009 User manual:
00010 If the Gecko symbol turns on on the LCD it is connected to the sensor
00011 Place your finger on the sensor. In the biometrics board manual it is explained how,
00012 but you can also try until it works properly. You don't want to use the extreme tip of your
00013 finger, but a bit further back.
00014 The battery indicator will flash briefly when a beat is detected. 
00015 
00016 Every beat it re-calculates your heartbeat using the time of the previous beat, since no
00017 filtering happens here, it can jump around a bit, but this should be limitted.
00018 
00019 And just to be sure since we can never overestimate human stupidity: This is not a medical tool...
00020 
00021 
00022 Todo: 
00023 1. Get rid of my hardcoded value used as threshold
00024 2. Measure PO2
00025 */
00026 
00027 
00028 #include "mbed.h"
00029 #include "Si114x.h"
00030 #include "EFM32_SegmentLCD.h"
00031 
00032 
00033 DigitalOut myled(LED1);
00034 silabs::EFM32_SegmentLCD segmentDisplay;
00035         
00036 
00037 int main() {
00038     segmentDisplay.AllOff();
00039     Si114x sensor(PD6, PD7);
00040     while(sensor.verifyConnection() != 1);
00041     segmentDisplay.Symbol(LCD_SYMBOL_GECKO, 1);
00042     
00043     int curval;
00044     int prevval = 0;
00045     int mvingavg[3] = {0};
00046     int sum;
00047     int prevtime = 0;
00048     int timesincelast;
00049     float abssum;
00050     float abssum_iir = 0.0f;
00051     
00052     Timer timey;    
00053     timey.start();
00054     while(1) {
00055         curval=sensor.getProximity(2);      //We use visible light, seems to work alot better than IR
00056         
00057         //Three times moving average of the diff of the output
00058         mvingavg[2] = mvingavg[1];
00059         mvingavg[1] = mvingavg[0];
00060         mvingavg[0] = curval - prevval;
00061         sum = mvingavg[2] + mvingavg[1] + mvingavg[0];
00062         
00063         //Float val for abs(sum) to calculate threshold dynamically
00064         abssum = (float)abs(sum);
00065         abssum_iir = abssum_iir * 0.99f + abssum * 0.01f;
00066         
00067         //Now we know the 'average' absolute 'noise' ( plus some part of the heartbeat)
00068         //We multiply this by four (yes randomly chosen) and use it as threshold for heartbeat
00069         //Possibly this is too much if you are really excited, but haven't been excited enough to check this
00070         if (sum < (int)(-4.0f * abssum_iir)) {
00071             segmentDisplay.Battery(4);
00072             timesincelast = timey.read_ms() - prevtime;
00073             if (timesincelast > 250) {
00074                 uint32_t hearthrate = 60000 / timesincelast;
00075                 segmentDisplay.Number(hearthrate);
00076                 prevtime = timey.read_ms();
00077             }
00078         }
00079         else {
00080             segmentDisplay.Battery(0);
00081         }
00082         
00083         prevval = curval;
00084     
00085 }
00086     
00087 }