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

文章目录


前言

近年来,毕业设计和答辩的要求与难度逐渐加大,传统的毕业设计题目往往缺乏创新性和亮点,难以满足毕业答辩的标准。

为了帮助大家顺利完成毕业设计,减少不必要的精力投入,将分享优质的毕业设计项目,🌝今天的分享的是:

📕基于STM32单片机心率角度检测GSM报警系统(程序+原理图+元件清单全套资料)

⭐难度系数:3分

⭐工作量:4分

⭐创新点:3分


一、主要功能介绍

第一部分为STM32F103C8T6单片机作为主控芯片,通过I/O口,以及单总线、 IIC、SPI、串口等通信方式控制其他模块工作。

第二部分为MAX30102模块,用来检测使用者心率数据。

第三部分为ADXL345模块,用来检测使用者倾斜角度。

第四部分为按键电路,用来设置心率值监测阈值及按键控制报警电路实现。

第五部分为电源模块,采用外接5V电压供电。

第六部分为晶振模块,采用无源晶体振荡电路为单片机提供时钟来源,再由单片机内部PLL锁相环模块进行倍频。

第七部分为报警电路,可采用蜂鸣器和LED灯组成声光报警。

第八部分为显示模块,采用OLED作为显示屏进行心率值、角度值、按键调节阈值显示。

第九部分为GSM模块,采用SIM800C通信模块向预设的紧急联系人发送报警短信通知。(摔倒约6~10s蜂鸣器叫和发短信)

二、硬件设计

👉功能视频演示链接

硬件实物展示

正面展示:

背面展示:

短信接收展示:

三、软件设计

简述一下此设计的软件部分

主要模块代码实现如下,
MAX10102获取心率代码:

c 复制代码
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);
}

角度&摔倒监测程序:

c 复制代码
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;
				}
		}
}

按键设置阈值

c 复制代码
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;
			 }
		}
}

四、总结

资料与实物获取方式

相关推荐
IronmanJay1 小时前
【LeetCode每日一题】——862.和至少为 K 的最短子数组
数据结构·算法·leetcode·前缀和·双端队列·1024程序员节·和至少为 k 的最短子数组
加载中loading...2 小时前
Linux线程安全(二)条件变量实现线程同步
linux·运维·服务器·c语言·1024程序员节
Wx120不知道取啥名2 小时前
C语言之长整型有符号数与短整型有符号数转换
c语言·开发语言·单片机·mcu·算法·1024程序员节
biomooc3 小时前
R语言 | paletteer包:拥有2100多个调色板!
r语言·数据可视化·1024程序员节
Hello.Reader3 小时前
FFmpeg 深度教程音视频处理的终极工具
ffmpeg·1024程序员节
Y.O.U..4 小时前
STL学习-容器适配器
开发语言·c++·学习·stl·1024程序员节
就爱敲代码4 小时前
怎么理解ES6 Proxy
1024程序员节
憧憬一下4 小时前
input子系统的框架和重要数据结构详解
arm开发·嵌入式·c/c++·1024程序员节·linux驱动开发
三日看尽长安花4 小时前
【Tableau】
1024程序员节
sswithyou5 小时前
Linux的调度算法
1024程序员节