Building a pulse oximeter

At-home pulse oximeters, those fingertip devices doctors use to measure the oxygen saturation in your blood, have been selling out everywhere thanks to the Covid-19 pandemic.

But as my Quartz colleague Amirta Khalid points out in this great article, most people don't need 'em. If your oxygen level is worryingly low, you'll know — you don't need a machine to tell you. Folks with some existing conditions, however, can use a pulse oximeter to help a remote doctor monitor their vitals or to adjust supplementary oxygen devices.

When Khalid mentioned she was working the story, it reminded me of the DIY "pulse ox" sensor Sparkfun sells. It, like other pulse oximeters, shines light into the skin and makes measurements based on how that light is absorbed. I've built heartbeat-driven projects before and had been exploring new ways to monitor pulse rates. So I got one.

Sparkfun warns in red letters that "this device is not intended to diagnose or treat any conditions," and I offer the same caution if you're tempted to build one. The process wasn't hard at all. I got it running quickly ... and then added an LED display for fun and flourish.

Here's how I made it, and the code, too.

The parts

The heart (ha) of the project is the Pulse Oximeter and Heart Rate Sensor, which includes the sensor itself, a tiny brain to make the measurement calculations, and two "Qwiic" connections. Qwiic is Sparkfun's system of making it easier to wire up sensors. So I also bought a little box of Qwiic wires.

I'd also need a microcontroller, a credit card-sized hobby computer, to run the show. Sparkfun makes its own version of an Arduino called a RedBoard that is Qwiic-friendly, and that's probably the easiest option for anyone starting from scratch. I have several Arduino Unos lying around, so I got a cheap Qwiic adapter for Arduino, which the Arduino world calls a "shield."

(While the Qwiic connectors made the project much easier, I could have soldered wires directly to the sensor. See the "connection options" section of this page for an example of that.)

The sensor needs two additional wires to lead back to the Arduino, so I cut the ends off two jumper wires. Here it'd be simpler to use the pigtail wires Sparkfun recommends.

Finally, I got fancy and added an Adafruit RGB Neopixel shield — which is a fun grid of addressable LEDs — to make a display. This is wholly unnecessary; you can read values off the microcontroller with your own computer.

The wires

Mainly I followed the SparkFun Pulse Oximeter and Heart Rate Monitor Hookup Guide.

I added my Qwiic "shield" to my Arduino Uno ...

... soldered up my jumper wires ...

... and wired everything together, using a Qwiic cable to make the connection between the Qwiic ports.

The code

The sensor uses a additional library, so to get that I followed the hookup guide instructions (which include links out to more instructions for people new to Arduino or to adding Arduino libraries). One note: The guide says to search the Arduino libraries for "SparkFun Bio Sensor Arduino Library" — but that's actually not precisely what it's called now. Just search for "Bio Sensor" and you'll find it.

Once the library was installed, several example programs become available. I used "Example1_config_BPM_Mode1" which was available from my Arduino desktop software's menu bar at: File > Examples > SparkFun Bio Sensor Hub Library > Example1_config_BPM_Mode1.ino

I loaded the code onto my Arduino, pinched the board lightly between my fingers, and it worked right away! The values streamed into my serial monitor window, which is available from the Arduino desktop software "Tools" menu.

Making a colorful display

I wanted to display the values for my pulse and saturated oxygen on my LED grid, so I used a RGB Neopixel shield from Adafruit ... and stacked it on top of my Qwiic shield — which I can do because they fit and they don't use any of the same "pins" on the Arduino.

There's a huge guide on how to use this little matrix here, and more about how to make text and graphics appear with the GFX library. Trouble is, that the digits created by the GFX library are toooo big for what I wanted. On my matrix, the digit "1" filled the whole "screen" vertically:

I suddenly remembered that I've been here before: when when I wanted to display the forecast temperature for my weather matrix project. So I stole a bunch of my own code from that project and incorporated it into the sensor example code.

The resulting program checks for the sensor's "status" value (3 means a finger has been detected, for example) and waits for a valid oxygen saturation reading (greater than zero). Then it does some gymnastics to display digits representing the values.

There's not quite enough room to separate the "1" in "100," so I just flash the first row of LEDs as a 1, which seems to work well enough. I also added some startup animation, a "heart" icon to denote the pulse, and a "lungs" icon to indicate the oxygen reading.

The full code is available on Github. Let me know if you find it useful!

1 response
If you want to buy and can't locate one a commercial one, my friend that works at Concord Health Supply,, says they have 12,000 in their warehouse.