简介
本次设计实现了一个简易的心率传感器,主控采用了atmel的atsamd51 ARM Cortex M4F MCU,心率测量采用了美信的MAX30101传感器,供电采用了ADI的adp150 ldo芯片。
本次的板卡为自行绘制,采用了立创eda,板卡采用feather版型设计,带有qwic iic接口,可以非常简单地进行传感器数据读取。
硬件介绍:
心率传感器:MAX30101(美信)
LDO芯片:ADP150AUJZ-3.3(ADI)
开发软件介绍
采用Arduino IDE开发
PCB基于立创EDA绘制
原理图简介
MAX30101的供电相对复杂,传感器需要1.8v供电,传感器LED需要5v供电,所以电路上采用外部3-5v电压输入,先降压至3.3V,再分别降压到1.8V和升压至5V,好在芯片实际功耗并不大。
VCC-3V3降压采用了ADI的ADP150AUJZ-3.3 LDO,这是一颗能够提供150mA供电的CMOS超低噪声LDO。
3V3-1.8V降压同样来自ADI,ADP150AUJZ-1.8 LDO,它的输出电流同样可以达到150mA。
3V3-5V升压选择了美台的PAM2401升压芯片,此颗芯片外围电路器件少,非常适合小体积使用。
实现效果
1)系统连接
2)数据显示
总结
本项目软件调试期间曾出现了很大的问题,单片机和MAX30101的通信出现了比较奇怪的异常,表现为相同代码,时而烧录能正常通信并运行,时而又不行。后来在调试funpack12的wio terminal板卡时,我遇到了seeed的tft库和我之前用的tft/espi库冲突但不报错导致屏幕无法正常点亮的情况,这个问题的发现让我开始猜测MAX30101是否也出现了类似的问题,后来经过检查发现果然是因为这个原因,MAX30101和MAX30100的库函数出现了交叉调用,但arduino ide并没有报错,所以出现了通信失败的情况。
附代码
#include <Wire.h>
#include "MAX30105.h"
#include "heartRate.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
MAX30105 particleSensor;
const byte RATE_SIZE = 4; //Increase this for more averaging. 4 is good.
byte rates[RATE_SIZE]; //Array of heart rates
byte rateSpot = 0;
long lastBeat = 0; //Time at which the last beat occurred
float beatsPerMinute;
int beatAvg;
void setup()
{
Serial.begin(115200);
Serial.println("Initializing...");
// Initialize sensor
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
{
Serial.println("MAX30105 was not found. Please check wiring/power. ");
while (1);
}
Serial.println("Place your index finger on the sensor with steady pressure.");
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
particleSensor.setup(); //Configure sensor with default settings
particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED
display.clearDisplay();
}
void loop()
{
long irValue = particleSensor.getIR();
if (checkForBeat(irValue) == true)
{
//We sensed a beat!
long delta = millis() - lastBeat;
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0);
if (beatsPerMinute < 255 && beatsPerMinute > 20)
{
rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
rateSpot %= RATE_SIZE; //Wrap variable
//Take average of readings
beatAvg = 0;
for (byte x = 0 ; x < RATE_SIZE ; x++)
beatAvg += rates[x];
beatAvg /= RATE_SIZE;
}
}
Serial.print("IR=");
Serial.print(irValue);
Serial.print(", BPM=");
Serial.print(beatsPerMinute);
Serial.print(", Avg BPM=");
Serial.print(beatAvg);
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 10);
display.print("IR=");
display.println(irValue);
display.setCursor(0, 30);
display.print("BPM=");
display.println(beatsPerMinute);
display.setCursor(0, 50);
display.print("Avg BPM=");
display.println(beatAvg);
display.display();
if (irValue < 50000)
Serial.print(" No finger?");
Serial.println();
}