毕业设计 基于STM32单片机健康检测/老人防跌倒系统 心率角度检测GSM远程报警 (程序+原理图+元件清单全套资料)

news2024/11/26 11:13:36

文章目录

  • 前言
  • 一、主要功能介绍
  • 二、硬件设计
    • 硬件实物展示
  • 三、软件设计
  • 四、总结
    • 资料与实物获取方式


前言

近年来,毕业设计和答辩的要求与难度逐渐加大,传统的毕业设计题目往往缺乏创新性和亮点,难以满足毕业答辩的标准。
为了帮助大家顺利完成毕业设计,减少不必要的精力投入,将分享优质的毕业设计项目,🌝今天的分享的是:

📕基于STM32单片机心率角度检测GSM报警系统(程序+原理图+元件清单全套资料)
⭐难度系数:3分
⭐工作量:4分
⭐创新点:3分
———————————————————————————————————————————————————————————

一、主要功能介绍

第一部分为STM32F103C8T6单片机作为主控芯片,通过I/O口,以及单总线、 IIC、SPI、串口等通信方式控制其他模块工作。
第二部分为MAX30102模块,用来检测使用者心率数据。
第三部分为ADXL345模块,用来检测使用者倾斜角度。
第四部分为按键电路,用来设置心率值监测阈值及按键控制报警电路实现。
第五部分为电源模块,采用外接5V电压供电。
第六部分为晶振模块,采用无源晶体振荡电路为单片机提供时钟来源,再由单片机内部PLL锁相环模块进行倍频。
第七部分为报警电路,可采用蜂鸣器和LED灯组成声光报警。
第八部分为显示模块,采用OLED作为显示屏进行心率值、角度值、按键调节阈值显示。
第九部分为GSM模块,采用SIM800C通信模块向预设的紧急联系人发送报警短信通知。(摔倒约6~10s蜂鸣器叫和发短信)

二、硬件设计

👉功能视频演示链接

硬件实物展示

正面展示:
在这里插入图片描述
在这里插入图片描述

背面展示:
在这里插入图片描述
短信接收展示:
在这里插入图片描述

三、软件设计

简述一下此设计的软件部分
主要模块代码实现如下,
MAX10102获取心率代码:

void GetHeartRateSpO2(void)
{
	  int32_t i;
	  float f_temp;
	  static u8 COUNT=8;
	
		i = 0;
		un_min = 0x3FFFF;
		un_max = 0;

		//dumping the first 50 sets of samples in the memory and shift the last 100 sets of samples to the top
		for(i = 50; i < 150; i++)
		{
				aun_red_buffer[i - 50] = aun_red_buffer[i];
				aun_ir_buffer[i - 50] = aun_ir_buffer[i];

				//update the signal min and max
				if(un_min > aun_red_buffer[i])
						un_min = aun_red_buffer[i];
				if(un_max < aun_red_buffer[i])
						un_max = aun_red_buffer[i];
		}

		//take 50 sets of samples before calculating the heart rate.
		for(i = 100; i < 150; i++)
		{
				un_prev_data = aun_red_buffer[i - 1];
				maxim_max30102_read_fifo((aun_ir_buffer+i), (aun_red_buffer+i));  //新版本

				//calculate the brightness of the LED
				if(aun_red_buffer[i] > un_prev_data)
				{
						f_temp = aun_red_buffer[i] - un_prev_data;
						f_temp /= (un_max - un_min);
						f_temp *= MAX_BRIGHTNESS;
						f_temp = un_brightness - f_temp;
						if(f_temp < 0)
								un_brightness = 0;
						else
								un_brightness = (int)f_temp;
				}
				else
				{
						f_temp = un_prev_data - aun_red_buffer[i];
						f_temp /= (un_max - un_min);
						f_temp *= MAX_BRIGHTNESS;
						un_brightness += (int)f_temp;
						if(un_brightness > MAX_BRIGHTNESS)
								un_brightness = MAX_BRIGHTNESS;
				}
		}
		maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_spo2, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid);
		if(COUNT++ > 8)
		{
					COUNT = 0;
					temperature = DS18B20_Get_Temp();//读取温度
					if ((ch_hr_valid == 1) && (n_heart_rate < 150) && (n_heart_rate > 40))
					{
							hrTimeout = 0;
							// Throw out up to 1 out of every 5 valid samples if wacky
							if (hrValidCnt == 4)
							{
									hrThrowOutSamp = 1;
									hrValidCnt = 0;
									for (i = 12; i < 16; i++)
									{
											if (n_heart_rate < hr_buf[i] + 10)
											{
													hrThrowOutSamp = 0;
													hrValidCnt   = 4;
											}
									}
							}
							else
							{
									hrValidCnt = hrValidCnt + 1;
							}

							if (hrThrowOutSamp == 0)
							{

									// Shift New Sample into buffer
									for(i = 0; i < 15; i++)
									{
											hr_buf[i] = hr_buf[i + 1];
									}
									hr_buf[15] = n_heart_rate;

									// Update buffer fill value
									if (hrBuffFilled < 16)
									{
											hrBuffFilled = hrBuffFilled + 1;
									}

									// Take moving average
									hrSum = 0;
									if (hrBuffFilled < 2)
									{
											hrAvg = 0;
									}
									else if (hrBuffFilled < 4)
									{
											for(i = 14; i < 16; i++)
											{
													hrSum = hrSum + hr_buf[i];
											}
											hrAvg = hrSum >> 1;
									}
									else if (hrBuffFilled < 8)
									{
											for(i = 12; i < 16; i++)
											{
													hrSum = hrSum + hr_buf[i];
											}
											hrAvg = hrSum >> 2;
									}
									else if (hrBuffFilled < 16)
									{
											for(i = 8; i < 16; i++)
											{
													hrSum = hrSum + hr_buf[i];
											}
											hrAvg = hrSum >> 3;
									}
									else
									{
											for(i = 0; i < 16; i++)
											{
													hrSum = hrSum + hr_buf[i];
											}
											hrAvg = hrSum >> 4;
									}
							}
							hrThrowOutSamp = 0;
					}
					else
					{
							hrValidCnt = 0;
							if (hrTimeout == 4)
							{
									hrAvg = 0;
									hrBuffFilled = 0;
							}
							else
							{
									hrTimeout++;
							}
					}

					if ((ch_spo2_valid == 1) && (n_spo2 > 75))
					{
							spo2Timeout = 0;

							// Throw out up to 1 out of every 5 valid samples if wacky
							if (spo2ValidCnt == 4)
							{
									spo2ThrowOutSamp = 1;
									spo2ValidCnt = 0;
									for (i = 12; i < 16; i++)
									{
											if (n_spo2 > spo2_buf[i] - 10)
											{
													spo2ThrowOutSamp = 0;
													spo2ValidCnt   = 4;
											}
									}
							}
							else
							{
									spo2ValidCnt = spo2ValidCnt + 1;
							}

							if (spo2ThrowOutSamp == 0)
							{

									// Shift New Sample into buffer
									for(i = 0; i < 15; i++)
									{
											spo2_buf[i] = spo2_buf[i + 1];
									}
									spo2_buf[15] = n_spo2;

									// Update buffer fill value
									if (spo2BuffFilled < 16)
									{
											spo2BuffFilled = spo2BuffFilled + 1;
									}

									// Take moving average
									spo2Sum = 0;
									if (spo2BuffFilled < 2)
									{
											spo2Avg = 0;
									}
									else if (spo2BuffFilled < 4)
									{
											for(i = 14; i < 16; i++)
											{
													spo2Sum = spo2Sum + spo2_buf[i];
											}
											spo2Avg = spo2Sum >> 1;
									}
									else if (spo2BuffFilled < 8)
									{
											for(i = 12; i < 16; i++)
											{
													spo2Sum = spo2Sum + spo2_buf[i];
											}
											spo2Avg = spo2Sum >> 2;
									}
									else if (spo2BuffFilled < 16)
									{
											for(i = 8; i < 16; i++)
									 		{
													spo2Sum = spo2Sum + spo2_buf[i];
											}
											spo2Avg = spo2Sum >> 3;
									}
									else
									{
											for(i = 0; i < 16; i++)
											{
													spo2Sum = spo2Sum + spo2_buf[i];
											}
											spo2Avg = spo2Sum >> 4;
									}
							}
							spo2ThrowOutSamp = 0;
					}
					else
					{
							spo2ValidCnt = 0;
							if (spo2Timeout == 4)
							{
									spo2Avg = 0;
									spo2BuffFilled = 0;
							}
							else
							{
									spo2Timeout++;
							}
					}
		}
}

void DisplayHeartRateSPO2(void)//显示心率函数
{
	OLED_ShowChar(0,2,hrAvg%1000/100+'0',2,0);
	OLED_ShowChar(8,2,hrAvg%100/10+'0',2,0);
	OLED_ShowChar(16,2,hrAvg%10+'0',2,0);
}

角度&摔倒监测程序:

void FallDetection(void)//摔倒检测
{
	  char i;
	  adxl345_read_average(&adx,&ady,&adz,10);//获取数据
		acc=ady;
		if(acc<0)acc=-acc;
		Zacc=(int)acc;
				OLED_ShowChar(96,2,acc/100+'0',2,0);
				OLED_ShowChar(96+8,2,Zacc%100/10+'0',2,0);	
				OLED_ShowChar(96+8+8,2,Zacc%100%10+'0',2,0);		
	
	
    
		if(((u16)acc)<40)//检测到摔倒
		{
			if(FallFlag==0)
			{
					FallFlag=1;
				  OLED_CLS();//清屏
				  for(i=0;i<4;i++)OLED_ShowCN(i*16+32,2,i+21,0);//测试显示中文:老人摔倒
				  OLED_ShowCN(96,2,16,0);
				  DelayMs(1000); 
				  DelayMs(1000); 
				  FallTime=10;
				  InitFlag = 1;
			}
		}
	  if(((u16)acc)>200)//检测到站立
		{
				if(FallFlag==1)
				{
						FallFlag=0;
					  OLED_CLS();//清屏
					  for(i=0;i<2;i++)OLED_ShowCN(i*16+16,2,i+21,0);
						for(i=0;i<3;i++)OLED_ShowCN(i*16+48,2,i+25,0);//测试显示中文:老人已站立
					  DelayMs(1000); 
					  if(CancelAlarm==0)
						{
								gsm_send_msg(ConversionNum,"8BF76CE8610FFF0C80014EBA5DF27ECF7AD98D7767654E86FF01");//发送短信,老人站起来了
						}
						DelayMs(1000); 
						InitFlag = 1;
				}
		}
}

按键设置阈值

void KeySettings(void)//按键设置函数
{
	  unsigned char keynum = 0;
	  char i;
	
	  keynum = KEY_Scan(1);//获取按键值
		if(keynum==1)//设置
		{
				setn++;
				if(setn > 16)
				{
					STMFLASH_Write(FLASH_SAVE_ADDR + 0x40,(u16*)PhoneNumber,11);//退出设置前,先把手机号存储一遍
					PhoneNumTranscoding();
					setn=0;
					InitFlag=1;
				}
			  if(setn==1)
				{
					OLED_CLS();//清屏
					for(i=0;i<2;i++)OLED_ShowCN(i*16+32,0,i+28,0);//测试显示中文:设置
					for(i=0;i<2;i++)OLED_ShowCN(i*16+64,0,i,0);   //测试显示中文:心率
					for(i=0;i<2;i++)OLED_ShowCN(i*16,4,i+30,0);   //测试显示中文:下限
					for(i=0;i<2;i++)OLED_ShowCN(i*16,6,i+32,0);   //测试显示中文:上限
					OLED_ShowChar(34,4,':',2,0);
					OLED_ShowChar(34,6,':',2,0);  
				}

				if(setn==6)
				{
					  OLED_CLS();//清屏
						for(i=0;i<8;i++)OLED_ShowCN(i*16,0,i+34,0);//测试显示中文:设置接收短信号码
				}
				DisplaySetValue();
		}
		if(keynum==2)//加
		{
        if((setn==1)&&(hrMax-hrMin>1))hrMin++;
				if((setn==2)&&(hrMax<200))hrMax++; 
			  if((setn==3)&&(spoMin<100))spoMin++;
			  if((setn==4)&&(teMax-teMin>1))teMin++;
				if((setn==5)&&(teMax<999))teMax++; 
			  if(setn>5)
				{
						PhoneNumber[setn-6]++;
					  if(PhoneNumber[setn-6]>'9')PhoneNumber[setn-6]='0';

				}
			DisplaySetValue();
		}
		if(keynum==3)//减
		{
				if((setn==1)&&(hrMin>0))hrMin--;
				if((setn==2)&&(hrMax-hrMin>1))hrMax--; 
			  if((setn==3)&&(spoMin>0))spoMin--;
			  if((setn==4)&&(teMin>0))teMin--;
				if((setn==5)&&(teMax-teMin>1))teMax--; 
			  if(setn>5)
				{
						PhoneNumber[setn-6]--;
					  if(PhoneNumber[setn-6]<'0')PhoneNumber[setn-6]='9';
					
				}
			DisplaySetValue();
		}
		if(keynum==4)//一键SOS报警键
		{
			 SOS_Flag=1;
		}
		if(keynum==5)//取消报警
		{
			 CancelAlarm = 1;
			 BEEP = 0;
			 alarmFlag &= 0xF7;    //一键SOS报警标志位清除
			 if(((u16)acc)<40)    //在摔倒的状态,如果在报警之前按下了取消报警,则不会报警。如果下次再是摔倒的状态则会重新报警
			 {
						alarmFlag |= 0x10;
			 }
		}
}

四、总结

资料与实物获取方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2223111.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32L476芯片在KEIL环境下BOOT跳转APP注意事项

BOOT工程 分配BOOT程序地址、设置参数地址、APP程序地址、下载缓冲区地址 #define BOOT_SECTOR_ADDR 0x08000000 #define BOOT_SECTOR_SIZE 0x0000A000 #define SETTING_SECTOR_ADDR 0x0800A000 #define SETTING_SECTOR_SIZE 0x00002000 #define APP_S…

Spring Boot:植物健康监测的智能管家

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

python——数据类型(数字,字符串)

&#xff08;一&#xff09;基本知识 首先我们需要知道&#xff0c;在python中数据类型大体可以分为两类 1.基本数据类型&#xff1a;数字和字符串 2.复合数据类型&#xff1a;列表&#xff0c;元组&#xff0c;字典&#xff0c;集合 &#xff08;二&#xff09;基本数据类型 …

LabVIEW水质监测系统

在面对全球性的海洋污染问题时&#xff0c;利用先进技术进行水质监测成为了保护海洋环境的关键手段之一。开发了一种基于LabVIEW的海洋浮标水质监测系统&#xff0c;该系统能够实时监测并评估近海水域的水质状况&#xff0c;旨在为海洋保护和污染防治提供科技支持。 项目背景 …

【数据结构】专栏开篇 | 1024程序员节

专栏说明&#xff1a;本专栏用于数据结构复习&#xff0c;文章中出现的代码由C语言实现&#xff0c;在专栏中会涉及到部分OJ题目&#xff0c;如对你学习有所帮助&#xff0c;可以点赞鼓励一下博主喔~~~&#x1f493; 博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a…

关于bp抓不到本地包

关于bp抓不到本地包 关于bp抓不到本地包 关于bp抓不到本地包 pikachu练习时&#xff0c;发现用bp抓本地&#xff08;127.0.0.1&#xff09;数据包时&#xff0c;竟然直接放行访问。 是因为系统默认127.0.0.1无法使用代理&#xff0c;因此bp才抓不到本地数据包&#xff0c;需要…

vue中为什么data属性在实例中可以定义成对象,而在组件中定义成对象会抛出错误

在vue组件中将data属性定义成对象会报错 为什么data属性在实例中可以定义成对象&#xff0c;而在组件中定义成对象则会抛出错误&#xff1f; Vue 实例中的 data 属性&#xff1a; 当 data 被定义在一个单一的 Vue 实例中时&#xff0c;这个实例通常是全局唯一的&#xff0c…

数据结构笔记(其七)--树(二叉树)

目录 1.知识总览 2.二叉树的基本概念 &#xff08;1&#xff09;.满二叉树 &#xff08;2&#xff09;.完全二叉树 &#xff08;3&#xff09;.二叉排序树 &#xff08;4&#xff09;.平衡二叉树 3.二叉树常考点 i.叶子结点与二分支结点的数量关系 ii.第i 层的最多结点数&…

如何禁止上班期间浏览无关网站?

禁止员工在上班期间浏览无关网页主要是为了提升工作效率和生产力&#xff0c;确保员工能够专注于工作任务。同时&#xff0c;这种做法有助于降低网络安全风险&#xff0c;防止恶意软件和钓鱼攻击&#xff0c;减少数据泄露和法律风险&#xff0c;维护公司的专业形象&#xff0c;…

【前端开发入门】JavaScript快速入门--js变量

目录 引言一、为什么要定义变量二、定义变量的一些技巧1. 解构赋值1.1 Object解构赋值1.2 Array解构赋值1.3 总结规律 2. 字符串拼接 三、变量作用域四、总结 引言 本系列教程旨在帮助一些零基础的玩家快速上手前端开发。基于我自学的经验会删减部分使用频率不高的内容&#xf…

Unity引擎:游戏开发的核心力量

目录 引言 Unity引擎的发展历程 早期发展 跨平台支持 Unity引擎的核心特性 易用性 社区支持 跨平台能力 Unity在游戏开发中的应用 移动游戏 独立游戏 3A游戏 Unity的未来展望 高级图形和渲染技术 扩展现实&#xff08;XR&#xff09;支持 云服务和多人游戏 结论…

C#判断点是否在多边形内

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff01;人工智能学习网站 前言&#xff1a; 大家好&#xff0c;我是上位机马工&#xff0c;硕士毕业4年年入40万&#xff0c;目前在一家自动化公司担任…

在不支持AVX的linux上使用PaddleOCR

背景 公司的虚拟机CPU居然不支持avx, 默认的paddlepaddle的cpu版本又需要有支持avx才行,还想用PaddleOCR有啥办法呢? 是否支持avx lscpu | grep avx 支持avx的话,会显示相关信息 如果不支持的话,python运行时导入paddle会报错 怎么办呢 方案一 找公司it,看看虚拟机为什么…

logdata-anomaly-miner:一款安全日志解析与异常检测工具

关于logdata-anomaly-miner logdata-anomaly-miner是一款安全日志解析与异常检测工具&#xff0c;该工具旨在以有限的资源和尽可能低的权限运行分析&#xff0c;以使其适合生产服务器使用。 为了确保 logdata-anomaly-miner的正常运行&#xff0c;推荐安装了python > 3.6的…

通过异地组网工具+RustDesk实现虚拟局域网使用远程桌面RDP

通过异地组网工具RustDesk实现虚拟局域网使用远程桌面RDP 预期效果 常见的远程桌面工具就不多说&#xff0c;麻烦而且不好用 QQ 使用普及率高 卡顿、延迟高 TeamViewer 功能强大、兼容性好 官方查询商业用途频繁 向日葵 安全性高、支持多种设备 强制登录、免费用户限速、限…

10. mapreduce实现wordcount

一. mapreduce 概述 mapreduce是一个并行计算框架&#xff0c;它起源于Google的MapReduce论文&#xff0c;它主要用于离线海量数据计算。 优点&#xff1a;海量数据离线处理&#xff0c;开发简单&#xff0c;部署方便缺点&#xff1a;仅适用于批处理&#xff0c;不支持实时数…

二极管那些事儿

一.发光二极管&#xff08;LED&#xff09; 1.压降很大&#xff08;2~3v&#xff09; 二.普通二极管&#xff08;eg:1N4007&#xff09; 1.一般用于整流和续流 2.比较廉价 3.一般压降0.7v 4.可用于防反接电路如下&#xff1a; 三&#xff1a;肖特基 1.开关速度第一&#…

UE5之5.4 第一人称示例代码阅读1 FirstPersonProjectile

既然如此&#xff0c;这几个文件都看看 先看看FirstPersonProjectile头文件 定义了几个函数 然后是两个component 这个projectilemovement应该是控制物理运动的 看看CPP文件 sphere那个就创建了一个subobject&#xff0c;初始化了一下&#xff0c;然后这里 CollisionComp-&g…

【C++差分数组】P10903 商品库存管理

本文涉及知识 C差分数组 洛谷 P10903 商品库存管理 题目简述&#xff1a; 有n中商品&#xff0c;编号[1,n]。有m中操作 ope[i]{LI,RI}&#xff0c;将编号LI到LR的商品都加1。 有m个查询&#xff0c;第i个查询 &#xff0c;执行所有ope[i],i ≠ \neq  i 后为0的商品数。 1…

基于PID控制器和四象限DC-DC功率转换器的永磁直流电机速度控制系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于PID控制器和四象限DC-DC功率转换器的永磁直流电机速度控制系统simulink建模与仿真。系统包括电流PI控制器&#xff0c;速度PI控制器&#xff0c;四象限DC-DC功率转换器&am…