基于STM32的人体健康状态检测系统:一个开源的毕业设计项目

文章目录

  • 0 前言
  • 1 硬件电路
  • 2 软件设计
  • 3 跌倒检测算法
  • 4 软件部分
  • MLX90614 红外温度传感器
  • 5 关键代码
  • 6 最后

  • 0 前言

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。

    为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的是

    🚩 毕业设计 stm32的人体健康状态检测系统(项目开源)

    🥇学长这里给一个题目综合评分(每项满分5分)

  • 难度系数:3分
  • 工作量:4分
  • 创新点:4分
  • 🧿 项目分享:

    https://gitee.com/sinonfin/sharing

    主要功能

    基于stm32的人体状态检测

    1.利用max30100传感器测心率、血氧

    2.利用体温传感器测量体温

    3.利用mpu6050传感器检测自己身体倾斜状态(是否摔倒)

    4.显示在oled

    1 硬件电路

    图中单片机为STM32单片机,包括整个最小系统,显示器为OLED液晶显示屏,和单片机之间通过上拉电阻连接整个电路的电源采用5V电源进行供电。将开关和电源设计成一体。采用普通拨动开关进行控制。GPS模块用于检测经纬度和时间信息。SIM800模块用于短信发送,还包含按键,用于设置。包括心率血氧体温传感器和ADXL345跌倒检测其硬件电路原理图如图

    核心主控stm32

    stm32最小系统

    2 软件设计

    根据整个系统设计的需求来看,本次软件功能主要是首先STM32开始配置我们需要使用的引脚,然后各个模块初始化,GPS采集和处理,OLED显示和短信发送。为了方便编写和运行效果进行整理,我们在编写程序的时候考虑到美观方面,利于观察我们把每个相关的功能进行封装,在程序需要调用到那个功能的时候我们直接调用就可以了,不需要把程序都写在主函数里。软件的主要部分由主函数、按键子程序、GPS采集程序、SIM800短信模块子程序等构成、心率血氧采集AD转换、跌倒检测ADXL345等。整个主程序流程图如图

    3 跌倒检测算法

    基于穿戴式传感器的跌倒检测技术又可以根据佩戴传感器的类型及位置不同 可以分为加速度传感器检测方式和压力传感器检测方式。压力传感器的的检测方 式主要是利用在足底放置压力传感器。利用足底压力传感器与其他传感器的协同 工作,可以区分开人体的跌倒与正常行为。基于加速度传感器的检测方法主要是 实时监控人体运动的加速度参数,当人体运动的加速度参数发生改变时,通过算 法的运算判断是否发生跌倒。而基于加速度传感器的检测技术又可以细分为阀值 检测法和模式识别法

    跌倒判断就是把人体跌倒行为与日常活动区别开来, 进行标记。 而不需要将所有的人体活动分类:而另一方面, 在实际应用中设备资源非常宝贵,实时系统的许多局限性也是复杂度较高的算法都无法实现, 即便实现,也会导致高成本、 高能耗、 高复杂度、 低实时性等一系列与本系统的设计初衷背道而驰的问题。 所以,在“有效”的前提下尽量“简单”是算法设计的指导思想。 同时需要强调的是,针对尤其是像老人这类生理上比较脆弱的的安全监测系统,遵循的基本原则是“可误不可漏”。 即将不是跌倒的情况判断为跌倒,这样可由使用者自行排除;但决不允许出现漏报, 即漏掉用户真正的跌倒, 却没有报警, 一旦出现这样的情况, 后果影响极大。 于此同时, 也并不代表我们要把报警的阈值设置的过低


    学长用 MPU6050 以 5hz 的采样频率来记录数据, 即每 0.2s 采集一次数据。 据研究表明, 成年人身高 h一般在 1.5 m 到 1.9 m 之间,此处选择 h= 1.7 m 用于估算。 研究发现﹐ 人体肚脐是人体头顶至足底的黄金分割点 [10] ﹐ 即肚脐至足底的长度是人体身高的 0.618 倍﹐ 而肚脐恰好处在人体腰部,同时认为人体摔倒时纵向初速度为零,加速度 a 取为阈值 1g, g=9.8 m/s^2,根据重力加速度公式:


    得到在极限状态下, 人体落至地面的时间大约 0.21 s。 也就是说人体平行于地面在腰部位置约 1.05m位置处做自由落体, 需要 0.21s 才能摔倒地面。 经实验, 实际情况中, 跌倒过程所需时间是远大于 0.21s 的,一般在 1.6s 到 2.0s, 所以取 5hz 的采样频率是完全足够的

    详细过程会放在配套的资料中,篇幅有限这里就不在复述了

    🧿 项目分享:

    https://gitee.com/sinonfin/sharing

    4 软件部分

    主芯片程序设计
    STM32的程序设计基于RT-Thread行开发。系统初始化之外,在主程序中,完成如下功能:

  • 通过内部AD接口对传感器的AD数据进行采集;
  • 将数据通过算法进行处理;
  • 将处理好的数据打包提供WiFi模块发送给服务器;
  • 喂狗。
  • 按照以上4点功能进行设计,程序工作流程图如图所示

    心率采集算法
    心率采集算法的目标是找到瞬间心跳的连续时刻,并测量两者之间的时间间隔(IBI)。通过遵循PPG波形的可预测的形状和模式,我们能够做到这一点。当心脏将血液泵入人体时,每次搏动都会有一个脉冲波(有点像冲击波)沿着所有的动脉传到脉搏传感器附着的毛细血管组织的末端。实际的血液循环比脉搏波传播慢得多。从下图所示的PPG上的T点开始跟踪事件。当脉搏波在传感器下方通过时,信号值迅速上升,然后信号回落到正常点。有时候,双向切口(向下尖峰)比其他更明显,但通常信号在下一个脉冲波冲洗之前稳定到背景噪声。由于波浪是重复的和可预测的,可以选择几乎任何可识别的特征作为参考点,比如峰值,并通过在每个峰值之间的时间计算心率。然而,这可能会从二分的切口中错误地读取,并且对基线噪声可能也是不准确的。理想情况下,想要找到心脏跳动的瞬间时刻需要准确的BPM计算,心率变异性(HRV)研究和脉搏传递时间(PTT)测量。

    通过使用定时器中断,我们的节拍查找算法在后台运行,并自动更新变量值。整体的算法流程图如图所示

    红外测温

    工作原理很简单,红外测温传感器MLX90614在额头与传感器之间的距离(由红外传感器测量)匹配设定值时读取人体温度。传感器读数发送到 Arduino 进行处理,处理后的值显示在 0.96" OLED 显示屏上。

    除了 OLED 显示屏外,还使用了两个 LED 和一个蜂鸣器来指示输出。

    1. 当体温正常时,绿色LED(LED1)亮,蜂鸣器鸣叫。

    2. 当体温高于 104 华氏度时,红色 LED ( LED2 ) 会亮起,蜂鸣器会发出较长时间的哔哔声。

    MLX90614 红外温度传感器

    MLX90614 是一款用于非接触式温度测量的红外测温仪,能够测量 -70 至 380°C 之间的温度。该传感器采用红外敏感热电堆探测器芯片和信号调节ASIC集成在一个芯片中。它基于 Stefan-Boltzmann 定律工作,该定律指出所有物体都会发射 IR 能量,并且该能量的强度将与该物体的温度成正比。传感器中的传感单元测量目标物体发射了多少红外能量,计算单元使用 17 位内置 ADC 将其转换为温度值,并通过 I2C 通信协议输出数据。

    传感器测量物体温度和环境温度以校准物体温度值。MLX 90614 传感器可以读取 -40 到 125 ˚C(-40 到 257 °F)范围内的环境温度和 -70 到 380 ˚C(-94 到 716 °F)范围内的物体温度。

    红外测温仪与 Arduino 的连接非常简单,因为它像许多其他组件一样使用 I2C 通信接口。
    MLX90614 温度计有 4 个引脚:VIN、GND、SCL 和 SDA。

    连接应如下所示:

    stm32–> MLX 90614

    5V —> VIN
    地 –> 地
    gpio2 —-> SCL
    gpio3 —-> SDA

    其他器件就不展示了

    最后接线如下:

    5 关键代码

    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;//保存之前的开关
    				spswitchtemp =SpeedControlSwitch;
    				DirectionControlSwitch=0;
    				  SpeedControlSwitch=0;
    					ZL.P*=1.5f;
    					ZL.D*=1.5f;
    					DelayMs(500);
    					Motor_Enable();
    					IS_RUNNING=1;//将小车运行标志置位
    					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++;//速度控制节拍+1
    		systime_direction++;//方向控制节拍+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;//重置平滑系数
    		 Get_Speed();
            Speed_Calculate();
        }
        if(FindZeroFlag)
        {
            FindZeroIndex++;
              if(FindZeroIndex>=400)//说白了按下键之后两秒才开始记录数据
              {
                  GYROY_SUM+=T_Y;
    			  GYROX_SUM+=T_X;
                      if(FindZeroIndex>=499)
                      {
                          FindZeroFlag=0;//次数够了,清标志位
                          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初始化,用作系统运行指示***********//
      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数据输出中断*/
    		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);//左边编码器方向角设置为悬空输入
        GPIO_QuickInit(DIR_RIGHT,kGPIO_Mode_IFT);//右边编码器方向角设置为悬空输入
      //**********************串口初始化********/
         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);//按键中断回调函数
        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);  //中断优先级分成2组
    		NVIC_SetPriority(PORTD_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, 0, 0));//遥控器
        NVIC_SetPriority(PIT0_IRQn, NVIC_EncodePriority(NVIC_PriorityGroup_2, 1, 0));//周期性中断优先级
    		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 最后

    🧿 项目分享:

    https://gitee.com/sinonfin/sharing

    物联沃分享整理
    物联沃-IOTWORD物联网 » 基于STM32的人体健康状态检测系统:一个开源的毕业设计项目

    发表评论