目录
一、设计背景和意义
1.1设计背景
随着医疗技术的进步与人均寿命的提高,全球人口老龄化问题日益严峻。据国家统计局数据显示,中国60岁及以上老年人口已接近3亿,占全国总人口的比重持续上升,预计在2035年前后将进入"深度老龄化"社会。在这一背景下,传统的家庭照护与机构养老服务日益显现出人力紧张、响应不及时、监护盲区等诸多现实问题,尤其是针对独居、高龄、慢性病患者等重点老年群体,其突发性健康事件(如高热、低血氧、心律异常、意外摔倒)极具风险,若未能及时发现与干预,极易造成严重后果。
1.2设计意义
本课题的研究不仅具有突出的技术整合与工程实现价值,更体现了信息技术在社会民生领域的广泛应用前景。通过构建低成本、可部署、功能完备的养老监护系统,不仅能够有效填补传统养老方式在安全监护方面的不足,还可为社区居家养老、智慧医疗、远程健康管理等更广泛的应用场景提供技术支撑,具有较高的社会价值与推广潜力。
二、实物效果展示
2.1实物图片

2.2实物演示视频
【开源】基于STM32的人体健康监测系统
三、硬件功能简介
3.1项目功能详解
1.传感器检测:检测体温、心率、血氧等健康相关数据
2.跌倒检测:ADXL345检测是否跌倒
3.GPS定位:实时检测定位坐标的经纬度数据
4.数据显示:0.96OLED屏幕显示全部的传感器数据以及传感器的阈值等数据
5.App远程监控:通过蓝牙模块连接App远程监控全部传感器数据
6.阈值数据设定:系统通过按键设定阈值
7.报警:检测到体温超过阈值、心率超过阈值、血氧低于阈值会开启或检测到摔倒蜂鸣器报警
3.2元器件清单
- 主控STM32F103C8T6最小系统板
- 0.96OLED显示屏幕
- ESP8266联网WIFI(ESP01S)
- DS18B20温度传感器
- MAX30102心率血氧传感器
- ADXL345三轴加速度传感器
- GPS定位模块
- 按键
四、主框图与软件流程图
主框图

流程图

五、硬件PCB展示


六、软件程序设计
cpp
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "string.h"
#include "max30102.h"
#include "ds18b20.h"
#include "beep.h"
#include "key.h"
#include "timer.h"
#include "oled.h"
#include "adxl345.h"
#include "iic.h"
double lat_minutes = 32.138118;
double lon_minutes = 116.447290;
#define GPS_STR_LEN 48
unsigned char display[16];
/**** 数据变量 ****/
int temp_door = 38;
int oxy_door = 90;
int heart_door = 100;
uint8_t send_time = 3;
uint8_t printd_flag = 0;
float adx,ady,adz;
float acc,acc2;
uint8_t tiltFlag = 0;
uint8_t fallTime = 0;
/**** 菜单变量 ****/
uint8_t option = 0; //阈值选项
uint8_t key_num = 0; //按键赋值
uint8_t page_id = 1; //页面ID
/**** 功能函数声明 ****/
void oled_show_onepage(); //第一屏显示内容
void oled_show_twopage(); //第二屏显示内容
void get_all_sensor_data(); //传感器数据采集
void Sensor_Data_Handle(); //不同模式下控制效果
void FallDetection(void); //摔倒检测
int main(void)
{
delay_init(); //系统延时函数初始化
OLED_Init(); //OLED初始化
uart2_init(9600); //串口2初始化,波特率9600
USART1_Config(); //串口1初始化,波特率9600
uart3_init(9600); //串口3初始化,波特率9600
DS18B20_Init(); //DS18B20温度检测初始化
MAX30102_Init(); //心率血氧检测初始化
un_min=0x3FFFF;
un_max=0;
Max30102_right_data();
BEEP_Init(); //蜂鸣器初始化
beep = 0;
KEY_Init(); //按键初始化
IIC_init(); //ADXL345摔倒检测初始化
adxl345_init();
TIME_Config(); //定时器初始化
while(1)
{
get_all_sensor_data(); //传感器数据采集
if(Time_Period[1]>1000) //Time_Period[1] 在定时器中累加
{
Time_Period[1] = 0;
if(page_id == 1){ //屏幕更新
oled_show_onepage();
}else if(page_id == 2){
oled_show_twopage();
}
if(tiltFlag==1){ //摔倒后,每隔一段时间进行语音播报提醒
send_time++;
if(send_time>=5){
send_time=0;
BY_U2_SendBuff(sound_buf,7);
}
}
printd_flag = !printd_flag;
if(printd_flag==1){ //蓝牙消息发送
printf("\r\n\r\n\r\n\r\n");
printf("*********************\r\n");
printf("心率:%d次/分钟 血氧:%d%%\r\n",dis_hr,dis_spo2);
printf("体温:%d℃\r\n",body_temp);
if(tiltFlag==1)printf("老人摔倒\r\n");
else printf("活动正常\r\n");
printf("经度:%10.6f\r\n",lon_minutes);
printf("纬度:%10.6f\r\n",lat_minutes);
printf("*********************\r\n");
}
}
Sensor_Data_Handle(); //数据处理
}
}
void Sensor_Data_Handle()
{
//体温超过阈值 或 心率超过阈值 或 血氧低于阈值且大于0,蜂鸣器报警提醒
if(body_temp>temp_door||dis_hr>heart_door||(dis_spo2<oxy_door&&dis_spo2>0)||tiltFlag==1)beep=1;
else beep=0;
}
void get_all_sensor_data() //获取数据
{
body_temp = DS18B20_Get_Temp(); //获取DS18B20体温数据
Get_Max30102_Data(); //获取心率血氧数据
FallDetection(); //摔倒检测
}
// 心(0) 率(1) 血(2) 氧(3) 体(4) 温(5) ℃(6) 宠(7) 物(8) 状(9) 态(10) 正(11) 常(12) 经(13) 纬(14) 度(15) 阈(16) 值(17)
// 活(18) 动(19) 老(20) 人(21) 摔(22) 倒(23)
void oled_show_onepage(){
OLED_ShowChinese(16*0,0,0,16,1); //心
OLED_ShowChinese(16*1,0,1,16,1); //率
OLED_ShowChar(16*2,0,':',16,1);
OLED_ShowNum(16*2+8,0,dis_hr,3,16,1); //心率数据
OLED_ShowChinese(16*4,0,2,16,1); //血
OLED_ShowChinese(16*5,0,3,16,1); //氧
OLED_ShowChar(16*6,0,':',16,1);
OLED_ShowNum(16*6+8,0,dis_spo2,3,16,1); //血氧数据
OLED_ShowChinese(16*0,16,4,16,1); //体
OLED_ShowChinese(16*1,16,5,16,1); //温
OLED_ShowChar(16*2,16,':',16,1);
OLED_ShowNum(16*2+8,16,body_temp,2,16,1); //体温数据
if(tiltFlag==1){
OLED_ShowChinese(16*4,16,20,16,1);
OLED_ShowChinese(16*5,16,21,16,1);
OLED_ShowChinese(16*6,16,22,16,1);
OLED_ShowChinese(16*7,16,23,16,1);
}else {
OLED_ShowChinese(16*4,16,18,16,1);
OLED_ShowChinese(16*5,16,19,16,1);
OLED_ShowChinese(16*6,16,11,16,1);
OLED_ShowChinese(16*7,16,12,16,1);
}
sprintf((char *)display,"%10.6f ",lon_minutes);
OLED_ShowChinese(16*0,32,13,16,1); //经
OLED_ShowChinese(16*1,32,15,16,1); //度
OLED_ShowChar(16*2,32,':',16,1);
OLED_ShowString(16*3,32,(u8*)display,16, 1);//显示经度
sprintf((char *)display,"%10.6f ",lat_minutes);
OLED_ShowChinese(16*0,48,14,16,1); //纬
OLED_ShowChinese(16*1,48,15,16,1); //度
OLED_ShowChar(16*2,48,':',16,1);
OLED_ShowString(16*3,48,(u8*)display,16, 1);//显示纬度
OLED_Refresh();
}
void oled_show_twopage(){
uint8_t a,b,c,d;
if(option==1){a=0;b=1;c=1;d=1;}
else if(option==2){a=1;b=0;c=1;d=1;}
else if(option==3){a=1;b=1;c=0;d=1;}
else {a=1;b=1;c=1;d=1;}
OLED_ShowChinese(16*0,0,0,16,1); // "心"
OLED_ShowChinese(16*1,0,1,16,1); // "率"
OLED_ShowChinese(16*2,0,16,16,1); // "阈"
OLED_ShowChinese(16*3,0,17,16,1); // "值"
OLED_ShowChar(16*4,0,':',16,1); // ":"
OLED_ShowNum(16*4+8,0,heart_door,3,16,a); // heart_door
OLED_ShowChinese(16*0,16,2,16,1); // "血"
OLED_ShowChinese(16*1,16,3,16,1); // "氧"
OLED_ShowChinese(16*2,16,16,16,1); // "阈"
OLED_ShowChinese(16*3,16,17,16,1); // "值"
OLED_ShowChar(16*4,16,':',16,1); // ":"
OLED_ShowNum(16*4+8,16,oxy_door,3,16,b); // oxy_door
OLED_ShowChinese(16*0,32,4,16,1); // "体"
OLED_ShowChinese(16*1,32,5,16,1); // "温"
OLED_ShowChinese(16*2,32,16,16,1); // "阈"
OLED_ShowChinese(16*3,32,17,16,1); // "值"
OLED_ShowChar(16*4,32,':',16,1); // ":"
OLED_ShowNum(16*4+8,32,temp_door,3,16,c); // temp_door
OLED_Refresh();
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //检测更新中断是否发生
{
key_num = KEY_Scan(0); //按键扫描赋值
switch(key_num)
{
case 1: //按键1按下
if(page_id==1){
page_id=2;
OLED_Clear();oled_show_twopage();
}else if(page_id==2){
option++;
if(option>3){
option=0;
page_id=1;
OLED_Clear();oled_show_onepage();
}else oled_show_twopage();
}
break;
case 2: //按键2按下
if(page_id==2){
if(option==1)heart_door+=1;
else if(option==2)oxy_door+=1;
else if(option==3)temp_door+=1;
oled_show_twopage();
}
break;
case 3: //按键3按下
if(page_id==2){
if(option==1)heart_door-=1;
else if(option==2)oxy_door-=1;
else if(option==3)temp_door-=1;
oled_show_twopage();
}
break;
case 4: //按键4按下
// BY_U2_SendBuff(sound_buf,7);
lanya_flag = 0;
break;
}
Time_Period[0]++;
Time_Period[1]++;
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清楚更新中断标志位,如果不清除,会一直进中断
}
}
void FallDetection(void)//倾斜检测
{
u8 i;
adxl345_read_average(&adx,&ady,&adz,10);//获取数据
acc=ady;
acc2=adx;
if(acc<0)acc=-acc;
if(acc2<0)acc2=-acc2;
if(((u16)acc)>=190 || ((u16)acc2)>=190)//检测到倾斜
{
tiltFlag=1;
}else{
tiltFlag=0;
}
}
七、项目资料包内容
