毕业设计 基于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;
			 }
		}
}

四、总结

资料与实物获取方式

相关推荐
学传打活4 天前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续3)
微信公众平台·1024程序员节·汉字·昆仑正义文化
学传打活9 天前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续1)
微信公众平台·1024程序员节·汉字·昆仑正义文化
fangzhanpeng16817 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心19 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552725 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552725 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝1 个月前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u0103055271 个月前
Java图像处理实战指南
人工智能·1024程序员节
u0103055271 个月前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u0103055271 个月前
Java实用类应用精讲
人工智能·1024程序员节