0 前言
?? 這兩年開始畢業(yè)設(shè)計和畢業(yè)答辯的要求和難度不斷提升,傳統(tǒng)的畢設(shè)題目缺少創(chuàng)新和亮點,往往達不到畢業(yè)答辯的要求,這兩年不斷有學(xué)弟學(xué)妹告訴學(xué)長自己做的項目系統(tǒng)達不到老師的要求。
為了大家能夠順利以及最少的精力通過畢設(shè),學(xué)長分享優(yōu)質(zhì)畢業(yè)設(shè)計項目,今天要分享的是
?? 畢業(yè)設(shè)計 stm32的人體健康狀態(tài)檢測系統(tǒng)(項目開源)
??學(xué)長這里給一個題目綜合評分(每項滿分5分)
- 難度系數(shù):3分
- 工作量:4分
- 創(chuàng)新點:4分
?? 項目分享:見文末!
主要功能
基于stm32的人體狀態(tài)檢測
1.利用max30100傳感器測心率、血氧
2.利用體溫傳感器測量體溫
3.利用mpu6050傳感器檢測自己身體傾斜狀態(tài)(是否摔倒)
4.顯示在oled
1 硬件電路
圖中單片機為STM32單片機,包括整個最小系統(tǒng),顯示器為OLED液晶顯示屏,和單片機之間通過上拉電阻連接整個電路的電源采用5V電源進行供電。將開關(guān)和電源設(shè)計成一體。采用普通撥動開關(guān)進行控制。GPS模塊用于檢測經(jīng)緯度和時間信息。SIM800模塊用于短信發(fā)送,還包含按鍵,用于設(shè)置。包括心率血氧體溫傳感器和ADXL345跌倒檢測其硬件電路原理圖如圖
核心主控stm32
stm32最小系統(tǒng)
2 軟件設(shè)計
根據(jù)整個系統(tǒng)設(shè)計的需求來看,本次軟件功能主要是首先STM32開始配置我們需要使用的引腳,然后各個模塊初始化,GPS采集和處理,OLED顯示和短信發(fā)送。為了方便編寫和運行效果進行整理,我們在編寫程序的時候考慮到美觀方面,利于觀察我們把每個相關(guān)的功能進行封裝,在程序需要調(diào)用到那個功能的時候我們直接調(diào)用就可以了,不需要把程序都寫在主函數(shù)里。軟件的主要部分由主函數(shù)、按鍵子程序、GPS采集程序、SIM800短信模塊子程序等構(gòu)成、心率血氧采集AD轉(zhuǎn)換、跌倒檢測ADXL345等。整個主程序流程圖如圖
3 跌倒檢測算法
基于穿戴式傳感器的跌倒檢測技術(shù)又可以根據(jù)佩戴傳感器的類型及位置不同 可以分為加速度傳感器檢測方式和壓力傳感器檢測方式。壓力傳感器的的檢測方 式主要是利用在足底放置壓力傳感器。利用足底壓力傳感器與其他傳感器的協(xié)同 工作,可以區(qū)分開人體的跌倒與正常行為?;诩铀俣葌鞲衅鞯臋z測方法主要是 實時監(jiān)控人體運動的加速度參數(shù),當(dāng)人體運動的加速度參數(shù)發(fā)生改變時,通過算 法的運算判斷是否發(fā)生跌倒。而基于加速度傳感器的檢測技術(shù)又可以細(xì)分為閥值 檢測法和模式識別法
跌倒判斷就是把人體跌倒行為與日?;顒訁^(qū)別開來, 進行標(biāo)記。 而不需要將所有的人體活動分類:而另一方面, 在實際應(yīng)用中設(shè)備資源非常寶貴,實時系統(tǒng)的許多局限性也是復(fù)雜度較高的算法都無法實現(xiàn), 即便實現(xiàn),也會導(dǎo)致高成本、 高能耗、 高復(fù)雜度、 低實時性等一系列與本系統(tǒng)的設(shè)計初衷背道而馳的問題。 所以,在“有效”的前提下盡量“簡單”是算法設(shè)計的指導(dǎo)思想。 同時需要強調(diào)的是,針對尤其是像老人這類生理上比較脆弱的的安全監(jiān)測系統(tǒng),遵循的基本原則是“可誤不可漏”。 即將不是跌倒的情況判斷為跌倒,這樣可由使用者自行排除;但決不允許出現(xiàn)漏報, 即漏掉用戶真正的跌倒, 卻沒有報警, 一旦出現(xiàn)這樣的情況, 后果影響極大。 于此同時, 也并不代表我們要把報警的閾值設(shè)置的過低
學(xué)長用 MPU6050 以 5hz 的采樣頻率來記錄數(shù)據(jù), 即每 0.2s 采集一次數(shù)據(jù)。 據(jù)研究表明, 成年人身高 h一般在 1.5 m 到 1.9 m 之間,此處選擇 h= 1.7 m 用于估算。 研究發(fā)現(xiàn)﹐ 人體肚臍是人體頭頂至足底的黃金分割點 [10] ﹐ 即肚臍至足底的長度是人體身高的 0.618 倍﹐ 而肚臍恰好處在人體腰部,同時認(rèn)為人體摔倒時縱向初速度為零,加速度 a 取為閾值 1g, g=9.8 m/s^2,根據(jù)重力加速度公式:
得到在極限狀態(tài)下, 人體落至地面的時間大約 0.21 s。 也就是說人體平行于地面在腰部位置約 1.05m位置處做自由落體, 需要 0.21s 才能摔倒地面。 經(jīng)實驗, 實際情況中, 跌倒過程所需時間是遠(yuǎn)大于 0.21s 的,一般在 1.6s 到 2.0s, 所以取 5hz 的采樣頻率是完全足夠的
詳細(xì)過程會放在配套的資料中,篇幅有限這里就不在復(fù)述了
?? 項目分享:見文末!
4 軟件部分
主芯片程序設(shè)計
STM32的程序設(shè)計基于RT-Thread行開發(fā)。系統(tǒng)初始化之外,在主程序中,完成如下功能:
- 通過內(nèi)部AD接口對傳感器的AD數(shù)據(jù)進行采集;
- 將數(shù)據(jù)通過算法進行處理;
- 將處理好的數(shù)據(jù)打包提供WiFi模塊發(fā)送給服務(wù)器;
- 喂狗。
按照以上4點功能進行設(shè)計,程序工作流程圖如圖所示
心率采集算法
心率采集算法的目標(biāo)是找到瞬間心跳的連續(xù)時刻,并測量兩者之間的時間間隔(IBI)。通過遵循PPG波形的可預(yù)測的形狀和模式,我們能夠做到這一點。當(dāng)心臟將血液泵入人體時,每次搏動都會有一個脈沖波(有點像沖擊波)沿著所有的動脈傳到脈搏傳感器附著的毛細(xì)血管組織的末端。實際的血液循環(huán)比脈搏波傳播慢得多。從下圖所示的PPG上的T點開始跟蹤事件。當(dāng)脈搏波在傳感器下方通過時,信號值迅速上升,然后信號回落到正常點。有時候,雙向切口(向下尖峰)比其他更明顯,但通常信號在下一個脈沖波沖洗之前穩(wěn)定到背景噪聲。由于波浪是重復(fù)的和可預(yù)測的,可以選擇幾乎任何可識別的特征作為參考點,比如峰值,并通過在每個峰值之間的時間計算心率。然而,這可能會從二分的切口中錯誤地讀取,并且對基線噪聲可能也是不準(zhǔn)確的。理想情況下,想要找到心臟跳動的瞬間時刻需要準(zhǔn)確的BPM計算,心率變異性(HRV)研究和脈搏傳遞時間(PTT)測量。
通過使用定時器中斷,我們的節(jié)拍查找算法在后臺運行,并自動更新變量值。整體的算法流程圖如圖所示
紅外測溫
工作原理很簡單,紅外測溫傳感器MLX90614在額頭與傳感器之間的距離(由紅外傳感器測量)匹配設(shè)定值時讀取人體溫度。傳感器讀數(shù)發(fā)送到 Arduino 進行處理,處理后的值顯示在 0.96" OLED 顯示屏上。
除了 OLED 顯示屏外,還使用了兩個 LED 和一個蜂鳴器來指示輸出。
-
當(dāng)體溫正常時,綠色LED(LED1)亮,蜂鳴器鳴叫。
-
當(dāng)體溫高于 104 華氏度時,紅色 LED ( LED2 ) 會亮起,蜂鳴器會發(fā)出較長時間的嗶嗶聲。
MLX90614 紅外溫度傳感器
MLX90614 是一款用于非接觸式溫度測量的紅外測溫儀,能夠測量 -70 至 380°C 之間的溫度。該傳感器采用紅外敏感熱電堆探測器芯片和信號調(diào)節(jié)ASIC集成在一個芯片中。它基于 Stefan-Boltzmann 定律工作,該定律指出所有物體都會發(fā)射 IR 能量,并且該能量的強度將與該物體的溫度成正比。傳感器中的傳感單元測量目標(biāo)物體發(fā)射了多少紅外能量,計算單元使用 17 位內(nèi)置 ADC 將其轉(zhuǎn)換為溫度值,并通過 I2C 通信協(xié)議輸出數(shù)據(jù)。
傳感器測量物體溫度和環(huán)境溫度以校準(zhǔn)物體溫度值。MLX 90614 傳感器可以讀取 -40 到 125 ?C(-40 到 257 °F)范圍內(nèi)的環(huán)境溫度和 -70 到 380 ?C(-94 到 716 °F)范圍內(nèi)的物體溫度。
紅外測溫儀與 Arduino 的連接非常簡單,因為它像許多其他組件一樣使用 I2C 通信接口。
MLX90614 溫度計有 4 個引腳:VIN、GND、SCL 和 SDA。
連接應(yīng)如下所示:
stm32–> MLX 90614
5V —> VIN
地 --> 地
gpio2 ----> SCL
gpio3 ----> SDA
其他器件就不展示了
最后接線如下:文章來源:http://www.zghlxwxcb.cn/news/detail-839729.html
5 關(guān)鍵代碼
int main()
{
uint8_t dirswitchtemp,spswitchtemp;
SmartCar_Init();
while(1)
{
VisualScope_Out();
while(DMA_IsMajorLoopComplete(HW_DMA_CH2));
if(StandUp_Flag==1&&IS_RUNNING==0)
{
dirswitchtemp=DirectionControlSwitch;//保存之前的開關(guān)
spswitchtemp =SpeedControlSwitch;
DirectionControlSwitch=0;
SpeedControlSwitch=0;
ZL.P*=1.5f;
ZL.D*=1.5f;
DelayMs(500);
Motor_Enable();
IS_RUNNING=1;//將小車運行標(biāo)志置位
DelayMs(500);
StandUp_Flag=0;
DelayMs(1000);
ZL.P/=1.5f;
ZL.D/=1.5f;
SpeedControlSwitch=dirswitchtemp;
DirectionControlSwitch=dirswitchtemp;
}
}
}
void PIT0_ISR()
{
static uint16_t FindZeroIndex=0;
systime_speed++;//速度控制節(jié)拍+1
systime_direction++;//方向控制節(jié)拍+1
ADC_GetDataAndFilter();
Angle_Calculate();
//Yaw_Calculate();
if(systime_direction==5)
{
//HMC_angle=Get_Angle();
systime_direction=0;
Dr_Smooth=0.2;
Direction_Calculate(t2-t2_mid);
}
if(systime_speed==20)
{
systime_speed=0 ;
GPIO_ToggleBit(HW_GPIOE,26);//閃爍
Sp_Smooth=0.05;//重置平滑系數(shù)
Get_Speed();
Speed_Calculate();
}
if(FindZeroFlag)
{
FindZeroIndex++;
if(FindZeroIndex>=400)//說白了按下鍵之后兩秒才開始記錄數(shù)據(jù)
{
GYROY_SUM+=T_Y;
GYROX_SUM+=T_X;
if(FindZeroIndex>=499)
{
FindZeroFlag=0;//次數(shù)夠了,清標(biāo)志位
FindZeroIndex=0;
TY_OFFSET=GYROY_SUM*0.01f;
TX_OFFSET=GYROX_SUM*0.01f;
GYROX_SUM=0;
GYROY_SUM=0;
}
}
}
Motor_Output();
}
void SmartCar_Init()
{
DelayInit();
/******Debug_初始化******/
/*******主要是DMP用到了printf*********/
UART_QuickInit(UART3_RX_PE05_TX_PE04,115200);
UART_SelectDebugInstance(HW_UART3);
//**********LED初始化,用作系統(tǒng)運行指示***********//
GPIO_QuickInit(HW_GPIOE,26,kGPIO_Mode_OPP);
GPIO_SetBit(HW_GPIOE,26);
/********OLED初始化**************/
OLED_Init();
//**************模擬加速度計陀螺儀初始化*****************/
GPIO_QuickInit(MMA7361_EN,kGPIO_Mode_OPP);
GPIO_SetBit(MMA7361_EN); //使能MMA7361
ADC_QuickInit(ADC_ACCEL_Z,kADC_SingleDiff10or11);//單端12位輸入
//**************IIC及L3G4200D\HMC5883初始化******************//
I2C_QuickInit(I2C0_SCL_PD08_SDA_PD09,I2C_SPEED);
L3G4200D_Init();
CT_IIC_Init();
while(mpu_dmp_init())
{
OLED_P8x16Str(0,0,"DMP Error");
OLED_P8x16Num(0,0,mpu_dmp_init());
DelayMs(200);
}
OLED_P8x16Str(0,0,"DMP OK!");
/****DMP數(shù)據(jù)輸出中斷*/
GPIO_QuickInit(HW_GPIOE,4,kGPIO_Mode_IFT); //DMP輸出輸出中斷
GPIO_CallbackInstall(HW_GPIOE,GPIOE_ISR);
GPIO_ITDMAConfig(HW_GPIOE,4,kGPIO_IT_FallingEdge,true);
/****************PWM初始化*****************/
FTM_PWM_QuickInit(FTM0_CH0_PC01,kPWM_EdgeAligned,10000);
FTM_PWM_QuickInit(FTM0_CH1_PC02,kPWM_EdgeAligned,10000);
FTM_PWM_QuickInit(FTM0_CH2_PC03,kPWM_EdgeAligned,10000);
FTM_PWM_QuickInit(FTM0_CH3_PC04,kPWM_EdgeAligned,10000);
FTM_PWM_ChangeDuty(FTM_PWM_LEFT,0);
FTM_PWM_ChangeDuty(FTM_PWM_LEFT_,0);
FTM_PWM_ChangeDuty(FTM_PWM_RIGHT,0);
FTM_PWM_ChangeDuty(FTM_PWM_RIGHT_,0);
/**************FTM正交解碼初始化**************/
/***********初始化位 脈沖-方向型編碼器**********/
FTM_QD_QuickInit(FTM1_QD_PHA_PB00_PHB_PB01,kFTM_QD_NormalPolarity,kQD_CountDirectionEncoding);
FTM_QD_QuickInit(FTM2_QD_PHA_PB18_PHB_PB19,kFTM_QD_NormalPolarity,kQD_CountDirectionEncoding);
GPIO_QuickInit(DIR_LEFT,kGPIO_Mode_IFT);//左邊編碼器方向角設(shè)置為懸空輸入
GPIO_QuickInit(DIR_RIGHT,kGPIO_Mode_IFT);//右邊編碼器方向角設(shè)置為懸空輸入
//**********************串口初始化********/
UART_QuickInit(UART4_RX_PE25_TX_PE24,115200);
UART_ITDMAConfig(HW_UART4,kUART_DMA_Tx,true);
UART_DMASendConfig(HW_UART4,HW_DMA_CH2);
//**********************按鍵中端配置************/
GPIO_QuickInit(KEY_GPIO,KEY_OK,kGPIO_Mode_IPU);
GPIO_QuickInit(KEY_GPIO,KEY_UP,kGPIO_Mode_IPU);
GPIO_QuickInit(KEY_GPIO,KEY_DOWN,kGPIO_Mode_IPU);
GPIO_QuickInit(KEY_GPIO,KEY_LEFT,kGPIO_Mode_IPU);
GPIO_QuickInit(KEY_GPIO,KEY_RIGHT,kGPIO_Mode_IPU);
GPIO_CallbackInstall(KEY_GPIO,GPIOA_ISR);//按鍵中斷回調(diào)函數(shù)
GPIO_ITDMAConfig(KEY_GPIO,KEY_OK,kGPIO_IT_FallingEdge,true);
GPIO_ITDMAConfig(KEY_GPIO,KEY_UP,kGPIO_IT_FallingEdge,true);
GPIO_ITDMAConfig(KEY_GPIO,KEY_DOWN,kGPIO_IT_FallingEdge,true);
GPIO_ITDMAConfig(KEY_GPIO,KEY_LEFT,kGPIO_IT_RisingEdge,true);
GPIO_ITDMAConfig(KEY_GPIO,KEY_RIGHT,kGPIO_IT_FallingEdge,true);
//*************解碼通道配置****************/
GPIO_QuickInit(HW_GPIOD,12,kGPIO_Mode_IFT);
GPIO_QuickInit(HW_GPIOD,13,kGPIO_Mode_IFT);
GPIO_QuickInit(HW_GPIOD,14,kGPIO_Mode_IFT);
GPIO_CallbackInstall(HW_GPIOD,GPIOD_ISR);
GPIO_ITDMAConfig(HW_GPIOD,12,kGPIO_IT_RisingFallingEdge,true);
GPIO_ITDMAConfig(HW_GPIOD,13,kGPIO_IT_RisingFallingEdge,true);
GPIO_ITDMAConfig(HW_GPIOD,14,kGPIO_IT_RisingFallingEdge,true);
//*****************PIT定時中斷初始化*****************/
PIT_QuickInit(HW_PIT_CH0,3000);
PIT_ITDMAConfig(HW_PIT_CH0,kPIT_IT_TOF,true);
PIT_CallbackInstall(HW_PIT_CH0,PIT0_ISR);
/*******************NVIC配置****************/
NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2); //中斷優(yōu)先級分成2組
NVIC_SetPriority(PORTD_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, 0, 0));//遙控器
NVIC_SetPriority(PIT0_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, 1, 0));//周期性中斷優(yōu)先級
NVIC_SetPriority(PORTE_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, 2, 0));//DMP
NVIC_SetPriority(PORTA_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, 3, 0));//按鍵中斷
OLED_P8x16Str(0,2,"Hello World!");
}
6 最后
?? 項目分享:見文末!文章來源地址http://www.zghlxwxcb.cn/news/detail-839729.html
到了這里,關(guān)于通信工程畢設(shè) stm32的人體健康狀態(tài)檢測系統(tǒng)(項目開源)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!