本设计硬件部分:由OLED液晶显示屏,ADXL345角度传感器,SIM800C短信模块,GPS定位模块。以及心形脉搏测量,以及蜂鸣器报警电路再加上按键电路组成。
设计可实现:
心率的测量,按键1,即可开始心率的测量,测量结束,数据会显示到OLED液晶上,若心率超过阈值,同时还会发送报警短信用以提醒。
可检测是否摔倒,如若摔倒,则液晶可显示摔倒提示。并产生报警提醒,同时会通过GSM模块获取经纬度信息,发送含有经纬度的报警短信到绑定的手机。如果摔倒后直立,则会发送直立提示短信。
同时还可以进行手动的取消摔倒报警,按下按键2,则可以取消本次的摔倒报警。
按下按键3,则可以发送含有当前具体经纬度的求助短信。
OLED液晶,可以显示出当前状态,心率数据,以及具体的经纬度数据。
发送短信的手机号,只需第一次使用时发送连接短信,单片机会自动将手机号进行保存。后期不需要再次进行发送。
器件选型:
mcu单片机: STC12C5A60S2
GSM/GPRS: SIM800C
加速度模块: ADXL345
心率: PulseSensor
主程序代码:
#include <STC12C5A60S2.H> #include "eeprom12.H" #include "ADXL345.h" #include "OLED.H" #include "usercode.H" #include "SIM800.H" #include "key.H" //===================================================================================================================== 保存经纬度 void Memory_data() { IapEraseSector(0x0400); IapProgramByte(0x0401,jing_du/100000000%10); IapProgramByte(0x0402,jing_du/10000000%10); IapProgramByte(0x0403,jing_du/1000000%10); IapProgramByte(0x0404,jing_du/100000%10); IapProgramByte(0x0405,jing_du/10000%10); IapProgramByte(0x0406,jing_du/1000%10); IapProgramByte(0x0407,jing_du/100%10); IapProgramByte(0x0408,jing_du/10%10); IapProgramByte(0x0409,jing_du/1%10); IapProgramByte(0x0412,wei_du/10000000%10); IapProgramByte(0x0413,wei_du/1000000%10); IapProgramByte(0x0414,wei_du/100000%10); IapProgramByte(0x0415,wei_du/10000%10); IapProgramByte(0x0416,wei_du/1000%10); IapProgramByte(0x0417,wei_du/100%10); IapProgramByte(0x0418,wei_du/10%10); IapProgramByte(0x0419,wei_du/1%10); IapProgramByte(0x040A,SIM800_Heat); } void Read_data() { jing_du = IapReadByte(0x0401)*100000000 + IapReadByte(0x0402)*10000000 + IapReadByte(0x0403)*1000000 + IapReadByte(0x0404)*100000 + IapReadByte(0x0405)*10000 + IapReadByte(0x0406)*1000 + IapReadByte(0x0407)*100 + IapReadByte(0x0408)*10 + IapReadByte(0x0409) ; wei_du = IapReadByte(0x0412)*10000000 + IapReadByte(0x0413)*1000000 + IapReadByte(0x0414)*100000 + IapReadByte(0x0415)*10000 + IapReadByte(0x0416)*1000 + IapReadByte(0x0417)*100 + IapReadByte(0x0418)*10 + IapReadByte(0x0419) ; SIM800_Heat=IapReadByte(0x040A); } //===================================================================================================================== 读取角度数据,判断跌倒 /***************************************************************************************************************** 角度判断跌倒函数: 读取出角度数据后,然后去比较这个角度数据,有没有超过一定值,如果超过一定值则判定为跌倒。 *****************************************************************************************************************/ void Read_ADXL345() { static char cs=0; //-- 定义静态局部变量 角度连续5次数据判断 if(Read_dat) { Read_dat=0; duqujiaodu(); if(Y_dat<=0) Y_dat=0; //-- 平放时,避免角度出现0度以下 if(Y_dat>=300) Y_dat=0; //-- 保证数据合理性。 if(Fall_Flag==0) { //-- 未检测到摔倒情况时 if(cs!=5) { if(Y_dat<190 || Y_dat>300) cs++; else cs=0; }else //-- 连续5次数据都判定为摔倒,此时系统确定当前为摔倒状态 { cs=0; Fall_Flag=1; } }else//-- 检测到摔倒情况时 { if(cs!=5) { if(Y_dat<300 && Y_dat>=190) cs++; else cs=0; }else //-- 连续5次数据都判定为未摔倒,此时系统确定当前为正常状态 { cs=0; Fall_Flag=0; } } } } //===================================================================================================================== 角度报警 void police_ADXL345() { if(Fall_Flag)//-- 确认摔倒后 { Up_Time=0; if(Fall_Time!=Fall_Cnt) { //-- 摔倒一定时间内,可手动取消 if(Hand_Close==0) Fall_Time++; //-- 没有手动取消时,计时++ else Fall_Time=0; //-- 在摔倒一定时间内,手动取消报警,计时清零 }else //-- 时间到,报警发短信 { if(Beep_Flag==0) //-- 计时时间到报警标志为1,产生报警 { //-- 发送摔倒短信 Beep_Flag=1; GSM_Send=1; GSM_Send_Num=1; GSM_Send_Time=0; } } }else //-- 老人没有摔倒 { if(Up_Time!=0) Up_Time--; //-- 如果手动时间不等于0, 手动取消报警时间清零 else Hand_Close=0; //-- 清零后,取消手动标志 Fall_Time=0;//-- 摔倒时间清零 if(Beep_Flag) //-- 直立后取消报警 { //-- 发送直立短信 Beep_Flag=0; GSM_Send=1; GSM_Send_Num=2; GSM_Send_Time=0; } } } //===================================================================================================================== 心率检测 /***************************************************************************************************************** 心率检测函数: 心率检测方法,就是先检测出第一次心跳的时候,将时间清零,开始计时,当再次检测到心跳后,停止计时 读取出,时间数据,这个时间就是两次心跳之间的间隔时间,然后用1分钟除以这个时间,就可以得到1分钟之内 对应的心跳数,循环测量多次,然后取平均值即可。 *****************************************************************************************************************/ bit OnceFlag=1; void Xinlv_dispose() { unsigned int pules=0; static bit Send_Flag=1; if(Start_Flag && Heat_Time==0) { if(Xinlv==0) { if(OnceFlag) { OnceFlag=0; if(Heat_State==0) Heat_State=1; else if(Heat_State==1) Heat_State=2; } }else OnceFlag=1; if(Heat_State==1) TR1=1; //-- 开始计时 else if(Heat_State==2) { Heat_State=0; TR1=0; //-- 停止计时,准备计算 if((6000/Heat_ms) > 50 && (6000/Heat_ms) < 150) { if(Heat_Cnt<7) { Heat_Cnt++; if(Heat_Cnt>=3) { pules = 6000/Heat_ms; //Heat_dat = Heat_Total = Heat_Total+pules; pules=0; } }else { SIM800_Heat = Heat_dat = Heat_Total/5; Heat_Total = Heat_Cnt=0; Heat_Time = xinlv_Time; //-- 显示2分钟 Beep_Num=4; Memory_data(); //-- 存储心率数据 } } Heat_ms = TH1 = TL1=0; } } if(Heat_Time!=0) //-- 心跳测量完成 { if(Heat_dat>Heat_H || Heat_dat<Heat_L) { if(Send_Flag) { Send_Flag=0; Beep_Num = 100; GSM_Send=1; GSM_Send_Num=3; //-- 发送心率报警短信 SIM800_Heat GSM_Send_Time=0; } } }else Send_Flag=1; } uchar dis_Cnt=0; //===================================================================================================================== OLED液晶显示 void OLED_display_Init() { display_GB2312_string(0,0," "); display_GB2312_string(0,1," "); display_GB2312_string(0,2," 初 始 化"); switch(dis_Cnt) { case 0: display_GB2312_string(10,2," "); break; case 1: display_GB2312_string(10,2,". "); break; case 2: display_GB2312_string(10,2,".. "); break; case 3: display_GB2312_string(10,2,"... "); break; default: break; } display_GB2312_string(0,3," "); } //===================================================================================================================== OLED液晶显示 void OLED_display() { display_GB2312_string(0,0,"当前状态:"); //------------------------------------------->第一行显示温度数据 if(Fall_Flag==0) display_GB2312_string(11,0," 正常"); else display_GB2312_string(11,0," 摔倒"); display_GB2312_string(0,1,"心率:"); //------------------------------------------->第二行显示心率数据 if(Start_Flag==0) display_GB2312_string(5,1,"---"); else { if(Heat_dat>99) display_buff(5,1,Heat_dat/100%10); else display_GB2312_string(5,1," "); if(Heat_dat>9) display_buff(6,1,Heat_dat/10%10); else display_GB2312_string(6,1," "); display_buff(7,1,Heat_dat/1%10); } display_GB2312_string(8,1,"次/分 "); display_GB2312_string(0,2,"经度:");//------------------------------------------->第三行 显示经度 display_buff(5,2,jing_du/100000000%10); display_buff(6,2,jing_du/10000000%10); display_buff(7,2,jing_du/1000000%10); display_GB2312_string(8,2,"."); display_buff(9,2,jing_du/100000%10); display_buff(10,2,jing_du/10000%10); display_buff(11,2,jing_du/1000%10); display_buff(12,2,jing_du/100%10); display_buff(13,2,jing_du/10%10); display_buff(14,2,jing_du/1%10); if(BaseFlag==0) display_GB2312_string(15,2," "); else display_GB2312_string(15,2,"*"); display_GB2312_string(0,3,"纬度:");//------------------------------------------->第三行 显示纬度 display_buff(5,3,wei_du/10000000%10); display_buff(6,3,wei_du/1000000%10); display_GB2312_string(7,3,"."); display_buff(8,3,wei_du/100000%10); display_buff(9,3,wei_du/10000%10); display_buff(10,3,wei_du/1000%10); display_buff(11,3,wei_du/100%10); display_buff(12,3,wei_du/10%10); display_buff(13,3,wei_du/1%10); } //===================================================================================================================== 定时器初始化 void Time_Init()//初始化函数 { TMOD=0x11; //-- 配置定时器0和定时器1 TH0=0x4C; TL0=0x00; //-- 定时器0,初值50ms ET0=1; //-- 开启定时器0 TR0=1; //-- 开启定时器0中断 TH1=0xDC; TL1=0x00; //-- 10ms中断 ET1=1; TR1=0; //-- 关闭定时器1中断 EA=1; } //===================================================================================================================== 程序主函数 void main() { Time_Init(); //-- 初始化 Uart_Init(); //-- 串口初始化配置波特率 EA=1; //-- 开总中断 initial_lcd(); //-- 屏幕初始化 Init_ADXL345(); //-- 角度初始化 Read_data(); //-- 读取存储的经纬度数据 Read_Phone(); //-- 读取手机号 while(1) { if(GSM_Send_Time==0) SIM800_Send_Message(); if(Quest_flag==1) OLED_display_Init(); else { OLED_display(); //---------------------->OLED 液晶显示 Read_ADXL345(); //-- 读取角度数据 Xinlv_dispose();//-- 心率测量 } if(GPS_Buff[0]=='$'&&GPS_Buff[1]=='G'&&GPS_Buff[2]=='P'&&GPS_Buff[3]=='G'&&GPS_Buff[4]=='L'&&GPS_Buff[5]=='L'&&GPS_Buff[18]=='N'&&GPS_Buff[32]=='E') { if(((GPS_Buff[30]-0x30)*100+(GPS_Buff[31]-0x30)*10+(GPS_Buff[32]-0x30))>=0&&((GPS_Buff[30]-0x30)*100+(GPS_Buff[31]-0x30)*10+(GPS_Buff[32]-0x30))<=180) //经度0°——180° 纬度0°——90° { jing_du= (((GPS_Buff[20]-0x30)*100000000)+((GPS_Buff[21]-0x30)*10000000)+((GPS_Buff[22]-0x30)*1000000)) +(((((GPS_Buff[23]-0x30)*10)+(GPS_Buff[24]-0x30))*100000)/6) +(((((GPS_Buff[26]-0x30)*1000)+((GPS_Buff[27]-0x30)*100)+((GPS_Buff[28]-0x30)*10)+(GPS_Buff[29]-0x30))*10)/6); wei_du= ((GPS_Buff[7]-0x30)*10000000+(GPS_Buff[8]-0x30)*1000000) +(((((GPS_Buff[9]-0x30)*10)+(GPS_Buff[10]-0x30))*100000)/6) +(((((GPS_Buff[12]-0x30)*1000)+((GPS_Buff[13]-0x30)*100)+((GPS_Buff[14]-0x30)*10)+(GPS_Buff[15]-0x30))*10)/6); GPS_Flag=1; GPS_Time = GPS_Cnt; //-- 赋值存储 GPS接收到卫星定位 Memory_data(); //-- 存储经纬度数据 BaseFlag=0; //-- 取消基站定位 } } if(Quest_flag==0 && GPS_Time==0)//-- GSM初始化完成后 { if(GPS_Flag==0)//--- GPS 未接收到卫星定位 { if(GSM_Send==0 && GSM_Send_Time==0)//-- 未执行AT指令 { Uart1_Count=0; Uartdat_byte("AT+CLBS=1,1\r\n"); //-- 获取经纬度 GSM_Send_Time=200; } } } } } //===================================================================================================================== 定时器0中断 50ms unsigned char Time0_ms=0; //-- 定时器计时变量 void Time_0 ()interrupt 1 //----50MS { TH0=0x4C; TL0=0x00; Time0_ms++; Scan_keyscan(); //-- 50ms进行1次按键扫描 if(GSM_Send_Time!=0) GSM_Send_Time--;//-- AT指令间隔倒计时 if(Beep_Flag!=0 || Beep_Num!=0) //--蜂鸣器产生报警 { if(Beep_Num!=0) Beep_Num--; Beep=!Beep; }else Beep=1; if(Time0_ms%5==0) { Read_dat=1; // 对4取余 200ms 读取一次角度数据 dis_Cnt=(dis_Cnt+1)%4; } if(Time0_ms>=20) { Time0_ms=0; police_ADXL345(); //-- 1s中检测角度报警 if(Heat_Time!=0) { Heat_Time--; if(Heat_Time<=5) { Heat_Time=0; Start_Flag=0; } } if(GPS_Time!=0) GPS_Time--; else GPS_Flag=0; } } //================================================================================================================= 定时器1 心率计时 void Time_1 () interrupt 3 { TH1=0xDC; TL1=0x00; //-- 重载10ms初值 Heat_ms++; } //===================================================================================================================== 串口2中断 GPS定位 void Uart_2 () interrupt 8 { if (S2CON & S2RI) { S2CON &= ~S2RI; if(S2BUF=='$') GPS_Num=0; GPS_Buff[GPS_Num]=S2BUF; GPS_Num=(GPS_Num+1)%100; } }
//