草庐IT

毕业设计 STM32老人防摔倒报警系统 - 物联网 嵌入式 单片机

MDC_sir 2023-12-26 原文

文章目录


0 前言

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

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

🚩 stm32老人跌倒检测预防系统

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

  • 难度系数:3分
  • 工作量:4分
  • 创新点:4分



1 整体设计

学长以STM32F103C8T6为中央处理器,GPS模块用获取当前老人位置,通过DS18B20和心率传感器采集当前人体健康信息,利用ADXL345判断老人是否发生跌倒,最后将数据发送给单片机后,单片机根据定位计算公式得出当前位置的经纬度信息。经过OLED液晶进行显示,数据还可以通过SIM800模块发送短信到设定的手机号上,将检测到的经纬度和心率体温展示在短信上。

1、电路供电部分:整个电路基本工作电压为5V,单片机烧写程序可通过STINK V2下载器进行下载。

2、人机交互。通过SIM800模块,将单片机和手机进行短信通信,手机上可以显示采集到的心率体温、是否跌倒和经纬度信息。

3、信号处理。STM32F103C8T6单片机作为CPU,进行数据的采样以及分析运算。

4、数据采集。使用心率血氧传感器进行心率采集,通过DS18B20采集体温,ADXL345判断老人是否跌倒,GPS进行定位,通过GPS接收模块,采集到相应的检测到的卫星信号后,可以计算出卫星轨道参数等数据,最后接收机中的微处理器就可以按照定位解算算法进行定位解算,得出机器所在位置的经度、纬度、最后通过GSM短信模块把当前的数据发送到用户设计端进行显示提醒。

5、数据展示。在经过运算之后,通过设备上的OLED液晶显示屏可以得到当前测试地的经纬度及老人生理状况。如图

2 硬件电路

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

核心主控stm32

stm32最小系统

3 软件设计

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

4 跌倒检测算法

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

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


学长用 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 的采样频率是完全足够的

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

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 最后

有关毕业设计 STM32老人防摔倒报警系统 - 物联网 嵌入式 单片机的更多相关文章

  1. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  2. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  3. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  4. 物联网MQTT协议详解 - 2

    一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su

  5. STM32的HAL和LL库区别和性能对比 - 2

    LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L

  6. ruby-on-rails - 在服务器上没有互联网访问权限的 Capistrano 部署 - 2

    如何使用Capistrano将Rails应用程序部署到无法访问外部网络或存储库的生产或暂存服务器?我已经设法完成部署的一半,并意识到Capistrano没有在我的本地机器上下载gitrepo,但它首先连接到远程服务器并尝试在那里下载Git存储库。我希望有一个类似Javaee的构建系统,其中创建可交付成果并将该可交付成果发送到服务器。就像您构建.ear文件并将其部署到您想要的任何服务器上一样。显然在RoR中,你被迫(据我所知)在该服务器上构建应用程序,在那里创建一个gem存储库,在那里克隆最新的分支等等。有什么方法可以将准备运行的包发送到远程服务器吗? 最佳答

  7. ruby - ZeroMQ 安全地通过互联网 - 2

    我一直在使用zeroMQ,我希望能够通过Internet安全连接。我在ruby​​中,可以使用SSL和/或某种shh连接,但找不到有关如何执行此操作的任何示例。我找到了这个旧的stackoverflow链接,HowdoeszeromqworktogetherwithSSL?说他们正在研究某种安全性,但那是一年前的事了,我找不到任何新的引用资料。即使这不是内置在zeroMQ中,我也假设会有一些方法可以使用OpenSSL或类似的东西来设置它。注意:如果您想要安全传输,zeroMQ网站提到使用VPN或其他东西。我不想使用VPN。一定有更好的方法。 最佳答案

  8. Win10 / 11新电脑最简单跳过联网激活和使用本地账户登录方法 - 2

    跳过联网激活:OOBE界面直接按Ctrl+Shift+F3进入审核模式。这样就可以直接进入系统进行一些硬件测试等,而不用联网激活导致新机无法退货。需要注意的是,在审核模式下进行的一些操作都会保留,并不会在退出后自动还原!安装的软件在正常开机进系统后还会看见!如果电脑确实没连互联网又不想强行跳过OOBE(网上很多教程会叫你直接结束OOBE进程,但这是不推荐的,因为一些厂商自带优化程序和系统初始化设置在后面都会应用,对于笔记本跳过的话你会发现驱动和内置应用都没有装上。其实这部分脚本就在系统盘的Recovery隐藏文件夹下),可以参考以下方式:https://www.landiannews.com/

  9. micropython复现经典单片机项目(二)可视化音频 频谱解析(基本搞定) - 2

    本人是音乐爱好者,从小就特别喜欢那个随着音乐跳动的方框效果,就是这个:arduino上一大把对,我忍你很久了,我就想用mpy做,全网没有,行我自己研究。果然兴趣是最好的老师,我之前有篇博客专门讲音频,有兴趣的可以回顾一下。提到可视化频谱,必然绕不开fft,大学学过这玩意,当时一心玩,老师讲的一个字都么听进去,网上教程简略扫了一下,大该就是把时域转频域的工具,我大mpy居然没有fft函数,奶奶的,先放着。音频信息如何收集?第一种傻瓜式的ADC,模拟转数字,原始粗暴,第二种,I2S库,我之前博客有讲过,数据是PCM编码。然后又去学PCM编码,一学豁然开朗,舒服,以代码为例:audio_in=I2S

  10. ruby-on-rails - Ruby On Rails 3.x 离线安装(没有互联网连接) - 2

    如果有人能提供一些关于在没有互联网连接的计算机上安装ruby​​onrails3.x框架的见解,我将不胜感激。所有教程或解释似乎都假设始终存在互联网连接。有没有简单的方法来下载包含所有依赖项的包并简单地安装包。提前致谢 最佳答案 最后。您需要手动下载的Gem的完整列表,以便在离线模式下安装Rails(或在阻止您的“gem”命令工作的代理之后)。此列表假定您已经拥有以下内容(Windows7):Ruby1.9.2RubyGems1.8.24DevKit列表。转到ruby​​gems.org并使用搜索功能下载以下每个Gem。您不需要键入

随机推荐