单片机无线调试-看见心跳-手机显示心率波形
? ? 這次帶來一篇使用手機觀察心率波形的教程,這可能是最后一篇 關于藍牙調試器的“硬核廣告” 了,這幾天一直做這個真的做的有些反感了,感覺時間被浪費,如果有人能從中受益就好了,但看起來不是所有的付出都有收獲。不廢話了,先看一下效果吧:
? ? 這次使用的是MAX30102型的心率檢測模塊,其為光電投射式的,因為血液對特定波長的光有吸收作用,每次心臟泵血時,該波長都會被大量吸收,以此就可以確定心跳。在使用這種模塊時,要注意只能使用手指或其他皮膚比較容易透光的部位進行檢測。使用手背或者其它部位基本是檢測不到的。估計是因為皮膚中的黑色素會吸收大部分的光,而手指部分皮膚黑色素較少,因此會比較明顯。
一、單片機端
1.1硬件連接
? ? MAX30102提供了I2C的接口用于與單片機通信,其作為從設備的地址為0xAE。從圖中可以看到其共有八個引腳,其中我們只用了四個,兩個用于供電,這個模塊可以直接使用3.3V供電。然后SCL和SDA引腳用于I2C通信。
1.2程序編寫
完整代碼在這里
1.2.1MAX30102驅動
? ? 一開始我使用的是STM32的硬件I2C接口,但是搞了半天,發現STM32的硬件I2C一直卡在BUSY標志,沒法正常使用,一直聽說STM32的硬件I2C不好用,這次真的是吃了教訓了。沒有辦法,又重新寫了一個使用IO口來模擬I2C的程序 fake_i2c,fake_i2c的初始化有些不同,下面程序中init_fake_i2c(1,2,MAX30102_ADD,1)的參數 1,2,MAX30102_ADD,1? 其中“1”的含義是I2C通信時鐘周期系數,該數越小,則通信速率越高,MAX30102最高支持400kHz的通信頻率,數據傳輸還是挺快的。其中的“2”的含義是等待Ack的延時周期,如果從設備在2個時鐘周期沒有回應,則判定為無Ack。接下來的“MAX30102_ADD”是MAX30102的通信地址。最后的“1”是寄存器地址的寬度,表示寬度為1byte。
//------------------------------------------------------------------------------------------------------
//初始化心率檢測模塊 MAX30102
//設置模式 : 可設置僅 心率 或 SPO2模式
//設置兩種光源的亮度brightness : 配置亮度,范圍是00~ff
void initMAX30102(unsigned char mode,unsigned char ir_led_brightness,unsigned char red_led_brightness){
init_fake_i2c(1,2,MAX30102_ADD,1);
fake_i2c_write_reg(0x02,0xf0);
fake_i2c_write_reg(0x03,0x02);
fake_i2c_write_reg(0x04,0x00);
fake_i2c_write_reg(0x05,0x00);
fake_i2c_write_reg(0x06,0x00);
fake_i2c_write_reg(0x08,0x1f);
fake_i2c_write_reg(0x09, mode);
fake_i2c_write_reg(0x0a,0x61);
fake_i2c_write_reg(0x0c, ir_led_brightness);
fake_i2c_write_reg(0x0d, red_led_brightness);
}
然后是數據的讀取:
//-------------------------------------------------------------------------------------------------------
//讀取采樣值
//這些采樣值都是經過一定的濾波處理的
//將變量地址傳入以讀出數據
void MAX30102_ReadValue( float *ir_v,float *red_v){
static unsigned short last_ir,last_red;
static float rate_ir,rate_red;
unsigned char buffer[6];
unsigned char state;
unsigned short raw_value_ir;
unsigned short raw_value_red;
state =fake_i2c_read_reg(0x04);//讀取FIFO新數據的數目,如果非0,說明有新的數據
if(state){
fake_i2c_read_buff(0x07,6,buffer);
fake_i2c_write_reg(0x04,0x00);
fake_i2c_write_reg(0x06,0x00);
raw_value_ir = (buffer[1]<<8)+buffer[2];
raw_value_red = (buffer[4]<<8)|buffer[5];
if(raw_value_ir!=last_ir)
rate_ir += ((raw_value_ir-last_ir)-rate_ir)*0.18f;
if(raw_value_red!=last_red)
rate_red += ((raw_value_red-last_red)-rate_red)*0.18f;
last_ir = raw_value_ir;
last_red = raw_value_red;
}
(*red_v)+=rate_red;
(*ir_v)+=rate_ir;
(*ir_v)*=0.8f;
(*red_v)*=0.8f;
if(*ir_v>MAX30102_FILTERED_VALUE_RANGE)
*ir_v = MAX30102_FILTERED_VALUE_RANGE;
if(*ir_v<-MAX30102_FILTERED_VALUE_RANGE)
*ir_v = -MAX30102_FILTERED_VALUE_RANGE;
if(*red_v>MAX30102_FILTERED_VALUE_RANGE)
*red_v = MAX30102_FILTERED_VALUE_RANGE;
if(*red_v<-MAX30102_FILTERED_VALUE_RANGE)
*red_v = -MAX30102_FILTERED_VALUE_RANGE;
}
? ? 在這里并沒有輸出讀取的原數據,而是采用一些濾波的算法,先微分,然后確定波動變化率,再對波動變化率積分,并且將積分的數值通過系數向0靠攏,以及限幅,總之就是什么亂七八糟各種手段用上,最終得到一串看得過去的波形。至于心率和血氧等的計算我就偷個懶不寫了。
1.2.2通信配置
//根據實際需要的變量,定義數據包中 bool byte short int float 五種類型的數目
#define TX_BOOL_NUM 0
#define TX_BYTE_NUM 0
#define TX_SHORT_NUM 0
#define TX_INT_NUM 0
#define TX_FLOAT_NUM 2
1.2.3主函數
/// ir:紅外 red:紅光 檢測兩種光源的反射程度
TxPack txpack;
float ir_value,red_value;
int main(void)
{
initMAX30102(MAX30102_MODE_IR,0x66,0x65);
initValuePack(115200);
while(1)
{
//延時
for(inti=0;i<20000;i++)
{}
MAX30102_ReadValue(&ir_value,&red_value);
txpack.floats[0] = ir_value;
txpack.floats[1] = red_value;
sendValuePack(&txpack);
}
}
二、手機端
詳細的手機端應用的介紹見這里,接下來就默認你看過我之前的教程了
2.1通信配置
? ? 我們可以從MAX30102讀取到兩種不同光源的光反射量,分別讀取紅外光和紅色可見光下血液吸收量。
2.2編輯控件
這里為了觀察更方便,我們將工程切換為橫屏視圖
然后編輯控件,添加了一個波形圖和一個能量槽:
鏈接數據,這里我只鏈接了IR 紅外光的檢測值。能量槽上下限的設置需要注意,可以設置為-300~300,如下圖
至此就可以連接藍牙模塊,運行此工程,你就能看到自己的心跳了。
STM32驅動MAX30102代碼在這里
另附MAX30100的代碼
應用可以在這里掃碼下載
如果本文對你有用的話,來個紅包支持一哈
總結
以上是生活随笔為你收集整理的单片机无线调试-看见心跳-手机显示心率波形的全部內容,希望文章能夠幫你解決所遇到的問題。