項(xiàng)目采用MAX30102血氧及心率監(jiān)視模塊、Arduino UNO板、OLED顯示器和蜂鳴器,搭建了一個(gè)簡(jiǎn)單的心率(BPM)測(cè)量?jī)x。
?
這里,BPM為每分鐘的心跳數(shù),正常人的數(shù)字為65-75之間,體育運(yùn)動(dòng)員的數(shù)字要低些;血氧飽和度(SaO2)對(duì)于正常然來(lái)說(shuō)大概為95%。
項(xiàng)目物料
本項(xiàng)目所需材料包括:
Max30102(×1):這是項(xiàng)目的功能器件,是一款用于可穿戴設(shè)備的高靈敏脈沖式血樣及心率傳感器,具有不同版本,但是只要型號(hào)正確即可。?
Arduino UNO(×1)
OLED 128x32(×1):低功耗顯示器。?
Buzzer (×1):蜂鳴器
面包板(×1):方便組件安裝和連接的線路板。
連接線
?
本項(xiàng)目所用代碼來(lái)自Sparkfun_MAX3010x示例庫(kù),OLED和Buzzer代碼根據(jù) "HeartRate" 示例改進(jìn)而來(lái),這需要用戶將手指放在傳感器上。
注意,如果將手指放在傳感器上,就要保持安靜,直到蜂鳴器的“嗶嗶”聲與你的心率節(jié)拍同步,或者與OLED動(dòng)畫(huà)同步,這時(shí)可讀出正確的BPM心率讀數(shù)。
?
本項(xiàng)目采用4次BPM讀數(shù)的平均值,因此比較準(zhǔn)確。
讓OLED顯示bmp圖像
OLED顯示的是小的“心形”柵格圖(bmp),一旦傳感器檢測(cè)到一次心跳,就立即切換為大點(diǎn)的“心形”柵格圖并保持一會(huì)兒,這樣屏幕就像心跳一樣,一閃一閃的,并伴有蜂鳴器的“嗶嗶”聲。
?
選擇希望看到的圖走向的格式,如 .png\ .bmp\ .dib等。切記,本項(xiàng)目屏幕尺寸為128x32px,圖像尺寸要小一些,為32x32px和24x21px。
?
下載LCD助手并打開(kāi)。
?
可看到如下"數(shù)字"
?
這就是所謂的代碼:
display.drawBitmap(5, 5, logo2_bmp, 24, 21, WHITE);
其含義為:
display.drawBitmap(Starting x pos, Starting y pos, Bitmap name, Width, Height, Color);
這段代碼描述了兩件事——“當(dāng)檢測(cè)到手指時(shí)做什么”,以及“撿到心跳時(shí)做什么”。
以下是更新后的代碼:
MAX_BPM_OLED_Buzzer.inoArduino
Modified from the SparkFun MAX3010x library
/* This code works with MAX30102 + 128x32 OLED i2c + Buzzer and Arduino UNO
* It's displays the Average BPM on the screen, with an animation and a buzzer sound
* everytime a heart pulse is detected
* It's a modified version of the HeartRate library example
* Refer to www.surtrtech.com for more details or SurtrTech YouTube channel
*/
#include ? ? ? ?//OLED libraries
#include
#include
#include "MAX30105.h" ? ? ? ? ? //MAX3010x library
#include "heartRate.h" ? ? ? ? ?//Heart rate calculating algorithm
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;
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET ? ?-1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //Declaring the display name (display)
static const unsigned char PROGMEM logo2_bmp[] =
{ 0x03, 0xC0, 0xF0, 0x06, 0x71, 0x8C, 0x0C, 0x1B, 0x06, 0x18, 0x0E, 0x02, 0x10, 0x0C, 0x03, 0x10, ? ? ? ? ? ? ?//Logo2 and Logo3 are two bmp pictures that display on the OLED if called
0x04, 0x01, 0x10, 0x04, 0x01, 0x10, 0x40, 0x01, 0x10, 0x40, 0x01, 0x10, 0xC0, 0x03, 0x08, 0x88,
0x02, 0x08, 0xB8, 0x04, 0xFF, 0x37, 0x08, 0x01, 0x30, 0x18, 0x01, 0x90, 0x30, 0x00, 0xC0, 0x60,
0x00, 0x60, 0xC0, 0x00, 0x31, 0x80, 0x00, 0x1B, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x04, 0x00, ?};
static const unsigned char PROGMEM logo3_bmp[] =
{ 0x01, 0xF0, 0x0F, 0x80, 0x06, 0x1C, 0x38, 0x60, 0x18, 0x06, 0x60, 0x18, 0x10, 0x01, 0x80, 0x08,
0x20, 0x01, 0x80, 0x04, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0xC0, 0x00, 0x08, 0x03,
0x80, 0x00, 0x08, 0x01, 0x80, 0x00, 0x18, 0x01, 0x80, 0x00, 0x1C, 0x01, 0x80, 0x00, 0x14, 0x00,
0x80, 0x00, 0x14, 0x00, 0x80, 0x00, 0x14, 0x00, 0x40, 0x10, 0x12, 0x00, 0x40, 0x10, 0x12, 0x00,
0x7E, 0x1F, 0x23, 0xFE, 0x03, 0x31, 0xA0, 0x04, 0x01, 0xA0, 0xA0, 0x0C, 0x00, 0xA0, 0xA0, 0x08,
0x00, 0x60, 0xE0, 0x10, 0x00, 0x20, 0x60, 0x20, 0x06, 0x00, 0x40, 0x60, 0x03, 0x00, 0x40, 0xC0,
0x01, 0x80, 0x01, 0x80, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x30, 0x0C, 0x00,
0x00, 0x08, 0x10, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x01, 0x80, 0x00 ?};
void setup() { ?
?display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //Start the OLED display
?display.display();
?delay(3000);
?// Initialize sensor
?particleSensor.begin(Wire, I2C_SPEED_FAST); //Use default I2C port, 400kHz speed
?particleSensor.setup(); //Configure sensor with default settings
?particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
}
void loop() {
long irValue = particleSensor.getIR(); ? ?//Reading the IR value it will permit us to know if there's a finger on the sensor or not
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //Also detecting a heartbeat
if(irValue > 7000){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //If a finger is detected
? ?display.clearDisplay(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //Clear the display
? ?display.drawBitmap(5, 5, logo2_bmp, 24, 21, WHITE); ? ? ? //Draw the first bmp picture (little heart)
? ?display.setTextSize(2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //Near it display the average BPM you can display the BPM if you want
? ?display.setTextColor(WHITE);?
? ?display.setCursor(50,0); ? ? ? ? ? ? ? ?
? ?display.println("BPM"); ? ? ? ? ? ??
? ?display.setCursor(50,18); ? ? ? ? ? ? ? ?
? ?display.println(beatAvg);?
? ?display.display();
? ?
?if (checkForBeat(irValue) == true) ? ? ? ? ? ? ? ? ? ? ? ?//If a heart beat is detected
?{
? ?display.clearDisplay(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//Clear the display
? ?display.drawBitmap(0, 0, logo3_bmp, 32, 32, WHITE); ? ?//Draw the second picture (bigger heart)
? ?display.setTextSize(2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//And still displays the average BPM
? ?display.setTextColor(WHITE); ? ? ? ? ? ??
? ?display.setCursor(50,0); ? ? ? ? ? ? ? ?
? ?display.println("BPM"); ? ? ? ? ? ??
? ?display.setCursor(50,18); ? ? ? ? ? ? ? ?
? ?display.println(beatAvg);?
? ?display.display();
? ?tone(3,1000); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//And tone the buzzer for a 100ms you can reduce it it will be better
? ?delay(100);
? ?noTone(3); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//Deactivate the buzzer to have the effect of a "bip"
? ?//We sensed a beat!
? ?long delta = millis() - lastBeat; ? ? ? ? ? ? ? ? ? //Measure duration between two beats
? ?lastBeat = millis();
? ?beatsPerMinute = 60 / (delta / 1000.0); ? ? ? ? ? //Calculating the BPM
? ?if (beatsPerMinute < 255 && beatsPerMinute > 20) ? ? ? ? ? ? ? //To calculate the average we strore some values (4) then do some math to calculate the average
? ?{
? ? ?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;
? ?}
?}
}
?if (irValue < 7000){ ? ? ? //If no finger is detected it inform the user and put the average BPM to 0 or it will be stored for the next measure
? ? beatAvg=0;
? ? display.clearDisplay();
? ? display.setTextSize(1); ? ? ? ? ? ? ? ? ? ?
? ? display.setTextColor(WHITE); ? ? ? ? ? ??
? ? display.setCursor(30,5); ? ? ? ? ? ? ? ?
? ? display.println("Please Place ");?
? ? display.setCursor(30,15);
? ? display.println("your finger "); ?
? ? display.display();
? ? noTone(3);
? ? }
}
審核編輯:湯梓紅
評(píng)論
查看更多