文章目录
前言
近年来,毕业设计和答辩的要求与难度逐渐加大,传统的毕业设计题目往往缺乏创新性和亮点,难以满足毕业答辩的标准。
为了帮助大家顺利完成毕业设计,减少不必要的精力投入,将分享优质的毕业设计项目,🌝今天的分享的是:
📕基于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;
}
}
}