一、脈搏波簡介
脈搏一般情況下指的都是動脈脈搏。每分鐘的脈搏次數稱為脈率,正常情況下與心率是一致的。心臟的一次收縮和舒張成為一個心動週期。在每個心動週期內,心室的收縮和舒張會引起脈內壓力的週期性波動,使動脈擴張和回縮,從而使得動脈血管發生有規律的搏動,稱為脈搏。當脈搏在血管中向前傳遞的時候,是採用波浪式向前,所以稱為脈搏波。脈搏波是一種波的形式,當心髒規律性的進行收縮和舒張運動的時候,血液注入到主動脈流經身體其他部位時產生的一種波。心室進行收縮運動的時候,主動脈瓣會呈現一種被張開的狀態,血液在這種情況下會注入主動脈,但是在血管中存在著阻撓血液流動的力,這樣血液會有一部分不能夠立即注入到靜脈中,造成血液會暫時存在主動脈的近端,擴張了主動脈,而導致主動脈血液容量變大,血壓升高等變化。而當心室舒張時,主動脈瓣會呈現關閉狀態,停止向動脈注血,主動脈在血管的彈性影響下而回到最初狀態。脈搏波是心臟的收縮和舒張沿動脈向四周傳遞而形成的,其傳播特點與心臟射血能力、血管粗細、血管壁彈性、血液粘稠度等有關。因此,在脈搏波中包含著大量的人體心臟和血管等人體系統的病理和生理資訊。典型的脈搏波如圖所示。
圖中的 1 表示脈搏波的上升支,代表心室的快速射血週期,表現為上升快速且平滑,上升的速度與心室的射血能力以及動脈血管的阻力和血管壁的彈性有關,佔整個脈搏波波動週期的時間比較短,圖中 a 點所處的位置為心室射血結束,緊接著主動脈關閉,進入下降支。2 表示脈搏波的下降支,是心室射血到下一次射血開始前的一段時期,佔整個脈搏波動週期的時間比較長,a 點之後,主動脈內血流向主動脈瓣方向反向流衝擊主動脈瓣,因瓣膜關閉不能進入心室,因而又退回到主動脈,過程類似潮汐,因此稱為潮波,又稱為重波前波,如圖 中 b 所示。c 點為重波波谷,又被稱之為降中峽,它的形成是因為心室收縮完畢、舒張開始,此時主動脈內血流趨向迴流,即血流向主動脈瓣方向反向流動,因此在急速降低的脈搏波的降支形成一個切跡。d 點為重搏波峰。在心室射血期緩慢下來後,心室慢慢舒張,室內的壓力很快降低到明顯低於主動脈的脈壓,主動脈內的血流開始向心室方向反向流動,因主動脈瓣關閉,血流逆流衝擊主動脈瓣,但因瓣膜關閉血流不能流入心室,只能向主動脈退去,因此造成動脈內的壓強在突然降下後,很快的上升,動脈管壁亦隨之稍有擴張,因此,在下降支的終端形成一個小波。
二、系統組成
該系統由Pluse Sensor光電反射式感測器模組、基於IIC的OLED顯示模組和STM32F103ZET6最小系統三個模組組成。Pluse Sensor脈搏波形模組採集原始模擬訊號,通過導線傳輸給STM32晶片經內部ADC轉換為數字訊號,再通過心率脈搏演算法得到心率BPM,然後由畫點函式將資料以波形和資料的方式在OLED螢幕上實時顯示,其系統框圖如下圖所示。
根據圖所示的系統框圖,本設計以STM32F103為核心,簡單的外圍電路為輔助,主要實現實時採集人體的脈搏以及心電訊號,採集到的脈搏波形在顯示屏上實時顯示,並計算出每分鐘心跳次數的功能。
三、系統模組選擇
3.1感測器選擇
PulseSensor 是一款用於脈搏心率測量的光電反射式模擬感測器。將其佩戴於手指、耳垂等處,利用人體組織在血管搏動時造成透光率不同來進行脈搏測量。感測器對光電訊號進行濾波、放大,最終輸出模擬電壓值。微控制器通過將採集到的模擬訊號值轉換為數字訊號,再通過計算就可以得到心率數值。
3.2主控晶片的選擇
本設計的微控制器採用意法半導體的STM32F103ZET6。此晶片是基於高效能的ARMCortex-M3的32位RISC核心,工作頻率最高可達72 MHz。Cortex-M3是一個32位處理器核心。內部的資料路徑是32位的,暫存器是32位的,儲存器介面也是32位的。CM3採用了哈佛結構,擁有獨立的指令匯流排和資料匯流排,可以讓取指與資料訪問並行不悖。這樣一來資料訪問不再佔用指令匯流排,從而提升了效能。為實現這個特性,CM3內部含有好幾條匯流排介面,每條都為自己的應用場合優化過,並且它們可以並行工作。此外此款微控制器還有豐富的外設比較低的功耗,因此可以用在醫療裝置上。
3.3顯示裝置及資料傳輸
我們採用了四引腳的IIC模式OLED螢幕,處理好的資料將在SDA資料線和SCL時鐘的共同控制下通過微控制器的IIC介面實時傳送到OLED顯示屏中顯示出波形。同時也會將計算好的心率BPM顯示。
四、檢測原理
4.1感測器
感測器只有三個引腳,分別為訊號輸出 S 腳 、電源正極 VCC 以及電源負極 GND,供電電壓為 3.3V到5V,可通過杜邦線與開發板連線。
上電後,感測器會不斷從 S 腳輸出採集到的電壓模擬值。需要注意的是,印有心形的一面才是與手指接觸面,在測量時要避免接觸佈滿元件的另一面,否則會影響訊號準確性。模組圖如圖。
4.2心跳節拍採集與計算處理
總體上就是設定一些引數,判斷心跳節拍是否產生(也就是有沒有把手穩定的放到感測器上)。如果有,那麼找到該節拍的峰值和波谷,計算公式如下:
IBI = sampleCounter - lastBeatTime
測量示意如圖所示。
4.3心率計算
通過以下公式即可算得心率。
4.4 OLED顯示
如圖4,脈搏波形可以在OLED螢幕上實時顯示,但由於IIC介面是並行傳輸,螢幕的重新整理速度可能會比較慢
五、電路設計
5.1 STM32F103控制模組
STM32F103微控制器,具有512kB Flash,64kB SRAM,系統時鐘72MHz,核心為ARM32位的Cortex-M3 CPU。 該控制器含有112個多功能雙向I/O口,所有I/O口可以映像到16個外部中斷;同時,還包括多達4個16位定時器,每個定時器有多達4個用於輸入捕獲、輸出比較、PWM或脈衝計數的通道,串列埠通訊介面可用於微控制器與上位機或串列埠顯示屏的通訊。STM32片上資源豐富,功能強大,結合中斷、定時器等其他外設實現行動式心電監測功能。其硬體電路如圖5所示,、串列埠屏的RXD和TXD分別連線微控制器上的PA9(TXD)和PA10(RXD),進行人機資料交換。
5.2 Pulse Sensor心電監測模組
Pulse Sensor是一款用於脈搏心率測量、脈搏波形測量和HRV分析的光電反射式模擬感測器。將其佩戴於手指、耳垂等處,通過導線連線可將採集到的的模擬訊號轉變為數字訊號,再通過微控制器的簡單計算後就可以得到心率數值。本感測器採用了峰值波長為515mm的綠光LED,光接收器採用了APDS-9008,這是一款環境光感受器,感受峰值波長為565mm,兩者峰值波長相近,靈敏度較高。此外,由於脈搏訊號容易受到各種訊號干擾,在感測器後面使用了低通濾波器和由運放MCP6001構成的放大器,將訊號放大了330倍,同時採用分壓電阻設定直流偏置電壓為電源電壓的1/2,使放大後的晶片可以很好的被微控制器的AD採集到的。
5.3 OLED(I2C)顯示模組
本設計採用主控為SSD1306的0.96寸I2C OLED螢幕來顯示得到的資料並繪製波形。其資料傳輸原理是使用STM32F103ZET6自帶的IIC介面(或使用GPIO模擬IIC也行),通過SDA資料線和SCL時鐘線來與OLED螢幕通訊,進而接收或傳送處理好的資料。OLED螢幕顯示影象和字元銳利清晰,並且體積小,功耗低,作為長時間顯示的螢幕十分合適,其實物圖如圖7所示。
六、軟體設計
6.1程式總體設計說明
採集到的模擬量經過STM32F103ZET6中自帶的AD轉換模組轉化為數字量,並以3.3V作為參考電壓將數字量歸化為電壓。
由心率採集與計算處理模組計算得出心率BPM和心跳節拍IBI;
由位於定時器中的波形處理模組繪製波形;
由按鍵控制模組實現通過KEY1切換顯示介面的功能;
6.2 主程式main
本設計的系統軟體主程式流程圖如圖9所示,基於STM32F103ZET6,先初始化各項外設,然後判斷KEY1是否被按下,並且通過按下的次數切換不同的功能模組進行顯示 。這種設計可以更充分地利用OLED螢幕顯示更多的資訊。
6.3按鍵處理函式KEY_deal
在該函式中,需要通過key1_state標誌位處理KEY1按鍵。KEY1就是用於決定display_flag值的。key1_state在等於1時代表某按鍵被按下。當判斷KEY1按下後,清零標誌位key1_state,並通過OLED_Clear()進行初始清屏操作,然後開始對display_flag進行賦值:若當下display_flag等於0(也就是KEY1只按下了一次,display_flag此時還為初始化時賦的0值),則使display_flag等於1;若當下display_flag已經不為0,則判斷其為1(KEY1按下1次)還是2(KEY1按下2次),如果是1則使display_flag等於2,如果是2則清零display_flag。
6.4 數值顯示函式OLED_Value_display
該函式中有兩個主要變數:temp(u8無符號字元型,用於儲存採集到的心率的原始ADC值的整數部分)和xiao(浮點型,儲存小數部分)。
取整數和取小數的邏輯:取整,用原始ADC值(adcx)與1做除法運算(“/”)即可去除小數部分,然後把值儲存在temp;取小數,把原始ADC值與取整後的值相減並存到xiao即可(因為小數可能很小,所以放大1000倍便於顯示)。然後呼叫OLED_ShowString()、OLED_ShowHz()以及OLED_ShowNum()等函式顯示。
6.5 波形顯示OLED_Waveform_display函式
waveform_flag為波形取樣時間計數標誌位,當取樣128次之後才一次性顯示出來,即waveform_flag變為1時(該標誌位在波形處理函式中,由一個取樣延時變數控制),說明已經取樣了128次,此時OLED_Waveform_display()函式按水平方向為Y軸(長度為128),垂直方向為X軸(長度為64)的規定開始繪製波形。值得注意的是,由於OLED螢幕的顯示方式,我們繪製時是按“頁”繪製,一“頁”為OLED上一塊8*1的區域,一共要繪製8“頁”。這也是為什麼要在設計座標系時將x、y軸對調的原因。當繪製完畢,我們將所有資料更新到GRAM即可顯示一幀波形曲線,若重新整理率足夠快,那麼我們就能得到連續的波形。
6.6 自帶庫中的關鍵函式
1、OLED_DrawPoint()畫點函式
該函式有 3 個輸入引數,前兩個是要畫點的座標,第三個 t 為要寫入 1 還是 0。該函式實現了我們在 OLED模組上任意位置畫點的功能。
自定義OLED 座標系如下: 【構建OLED 直角座標系, x,y軸反置 方便函式運算】
↑x
|
127--------
| |
| |
| |
| |
| |
| |
(0,0)----------→y
63
void OLED_DrawPoint(u8 x,u8 y,u8 t)
{
u8 pos,bx,temp=0;
if(x>127||y>63)return;//超出範圍了.
pos=7-y/8;/*輸入的Y座標要除以8,以定位到要改變的那個點對應的“頁”(page),減7是為了轉化為1到8下的位置(因為底層是用0到7表示的) */
bx=y%8;//該點在該頁中的位置
temp=1<<(7-bx);//把該點寫入temp
if(t)OLED_GRAM[x][pos]|=temp; //如果t為1就把該點寫1
else OLED_GRAM[x][pos]&=~temp; //如果t為0就把該點寫0
}
OLED畫圖顯示字元時,水平方向為Y軸;垂直方向才是X軸;
如何點亮一個點(假設為x,y)?因為我們是縱向取模,所以我們只要清楚y座標在哪就行了。首先我們要確定y在哪一“頁”(page)--> pos=y/8;,因為每8行為一頁,而縱向取模是按頁來完成的。其次就要知道y在這一頁裡面的哪裡,這就要用到求餘運算-->bx=y%8。
例如: Y = 25
pos = 25 /8 = 3,即該點處於第4頁(底層驅動是從0開始計數的,程式碼中再用7減3可得到1到8下對應頁數);
bx = 25 % 8= 1, 即該點處於第4頁第2行(底層驅動是從0開始計數的);
2、OLED_Refresh_Gram()gram更新函式
由於我們使用的是正點原子系列開發板,其在 STM32 內部定義了一個塊 GRAM:u8 OLED_GRAM[128][8];此部分 GRAM 對應 OLED 模組上的 GRAM。在操作的時候,我們只要修改 STM32 內部的 GRAM 就可以了,然後通過 OLED_Refresh_Gram 函式把 GRAM 一次重新整理到 OLED 的 GRAM 上。OLED_Refresh_Gram 函式先設定頁地址,然後寫入列地址(也就是縱座標),然後從 0 開始寫入 128 個位元組,寫滿該頁,最後迴圈把 8 頁的內容都寫入,就實現了整個從 STM32 視訊記憶體到 OLED 視訊記憶體的拷貝。
6.7 ADC處理函式
此處定義一個temp(u16,無符號字元型),呼叫Get_Adc()獲得ADC原始值,此時該原始值只是ADC輸出的一個數字量,不帶單位,由於ADC是12位的(最大的數字量是4096),所以這個原始值最大隻能為4096。因為它不帶單位,我們想要用單位表示它就必須有一個參考,於是就用電壓作為這個參考。參考電壓是3.3v,所以用原始值*3.3/4096就可以把ADC採集到的數字量轉化為電壓值,儲存到adcx即可。Signal = temp>>2用於處理感測器的值,向右位移2位。
6.8 心率採集與計算處理函式(程式碼詳見工程)
設定一些引數,判斷心跳節拍是否產生(也就是有沒有把手穩定的放到感測器上)。如果有,那麼找到該節拍的峰值和波谷,用sampleCounter與lastBeatTime做差來得到節拍持續的時間,差值為IBI。其中,sampleCounter是位於通用定時器中的一個自增量,自增值為2ms,用於記錄CPU執行時間;lastBeatTime始終跟隨上一次sampleCounter的值,目的是為了記錄下一次節拍的時間,它的初值為0。
例如從CPU開始執行開始記錄時間到第100ms的時候有了一個脈衝,此時IBI = sampleCounter – lastBeatTime,捨棄此時的IBI,顯然波形沒有持續100ms,此時使sampleCounter = lastBeatTime,當下一次波形到來時(相隔時間很短,因為人的心跳是連續的,可視為脈衝是連續的一個一個到來),此時再用IBI = sampleCounter – lastBeatTime便可以得到單獨一個脈衝的持續時間。將IBI存入一個數組中,用保留的最後十個資料,取一個平均值儲存為runningTotal,再把runningTotal平均到一分鐘裡面就得到心率BPM,計算公式如下:
IBI = sampleCounter - lastBeatTime
6.9 波形處理函式Waveform_deal(程式碼詳見工程)
該函式中包含兩個主要變數,waveSample_times和xiao,前者為取樣延時變數,用於保證每取樣128次記錄一次waveform_flag標誌位,然後使波形顯示函式繪製波形;xiao則是用來控制轉換並放大後的小數的長度以便於oled顯示的,一般我們設定為45到80。最終,xiao經過處理後的值在0到60間,用來控制波形的寬度。(因為我們規定x軸的長度為64,超過的話顯示會不完整)
6.10 通用定時器TIM3
TIM3中斷,執行時間由TIMER控制,每2ms執行一次。該定時器內部的中斷函式為標誌量sampleCounter的自增語句、Waveform_deal()波形資料處理函式和HeartRate_deal()心率採集與計算處理函式,作用就是每2ms執行對應函式或語句一次以達到之前介紹的一些功能。
6.11主介面顯示函式OLED_Main_display
該函式會呼叫一個庫函式OLED_ShowHz()去顯示作者和標題資訊。
七、實物圖
放幾張效果圖(由於時間限制,就直接用現成的開發板了)
工程地址:
https://gitee.com/daycen/STM32-BPM
通過Keil uVision5開啟即可使用