c51实现老人跌倒,心率异常报警系统

简介: c51实现老人跌倒,心率异常报警系统

本设计硬件部分:由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;
    }
}


//

image.png

目录
相关文章
|
Kubernetes Cloud Native Java
Activiti 简介以及最新activiti依赖 pom.xml文件(使用时注意对应版本号)
Activiti 简介以及最新activiti依赖 pom.xml文件(使用时注意对应版本号)
1120 2
|
NoSQL 安全 Redis
深入了解Redis:配置文件、动态修改和安全设置
深入了解Redis:配置文件、动态修改和安全设置
1356 0
|
12月前
|
机器学习/深度学习 人工智能 自然语言处理
AI专业术语解析
本文围绕AI领域常见专业术语展开解析,涵盖基础概念、模型与算法、数据处理、生成式人工智能、自然语言处理等多个方面。基础概念类包括人工智能、机器学习、深度学习等,详细阐述其定义、原理及应用场景。模型与算法类涉及支持向量机、决策树、生成对抗网络等。数据处理类介绍了数据标注、特征工程、模型评估等。生成式人工智能相关术语有生成式AI、文本生成、图像生成等。自然语言处理方面涵盖分词、词向量、注意力机制等。此外,还解释了大模型、小样本学习、端到端、对齐等其他专业术语,为读者理解AI领域提供了全面且深入的参考。
2289 4
|
存储 芯片 内存技术
存储器的分类
存储器的分类
1713 1
|
Java 区块链
使用Java实现区块链智能合约
使用Java实现区块链智能合约
|
存储 人工智能 文字识别
AI与OCR:数字档案馆图像扫描与文字识别技术实现与项目案例
本文介绍了纸质档案数字化的技术流程,包括高精度扫描、图像预处理、自动边界检测与切割、文字与图片分离抽取、档案识别与文本提取,以及识别结果的自动保存。通过去噪、增强对比度、校正倾斜等预处理技术,提高图像质量,确保OCR识别的准确性。平台还支持多字体识别、批量处理和结构化存储,实现了高效、准确的档案数字化。具体应用案例显示,该技术在江西省某地质资料档案馆中显著提升了档案管理的效率和质量。
2078 1
|
网络安全 Windows
查看SSH配置文件
查看SSH配置文件
2288 1
|
人工智能 IDE API
在我的开源项目(AI Godot 桌宠)中使用通义灵码
作为一名AI代码助手的忠实用户,我近期尝试了阿里开源的Qwen模型。通过在个人项目——一个由Godot引擎开发的AI桌宠软件中测试Qwen,我发现其在处理小众语言(如GDScript)时表现出色,能够快速准确地解决问题,甚至优化了我的代码。此外,Qwen在GitHub Actions自动化打包等复杂任务上的表现同样令人满意。其高效的代码补全速度更是超越了付费的GitHub Copilot。这次体验让我对开源AI工具刮目相看,强烈推荐大家试用。
|
域名解析 缓存 网络协议
【域名解析DNS专栏】DNS解析过程深度解析:一次完整的域名查询旅程
【5月更文挑战第21天】DNS系统将人类友好的域名(如www.example.com)转化为IP地址,涉及递归和迭代查询。当用户输入域名,浏览器查询本地DNS缓存,未命中则向本地DNS服务器发起请求。本地服务器向根域名服务器查询,根服务器指引到对应顶级域名的权威DNS,权威DNS提供IP地址。Python示例代码展示了这一过程。了解DNS解析有助于理解互联网运作并优化网络资源管理。
1329 2
【域名解析DNS专栏】DNS解析过程深度解析:一次完整的域名查询旅程
|
数据库
element多选框select下拉框数据回显的问题value.push is not a function
element多选框select下拉框数据回显的问题value.push is not a function
1680 1