基于51单片的物联网空巢老人安全监护系统心率跌倒检测原理图PCB

功能介绍:
0.本系统采用STC89C52作为单片机
1.采用LCD1602作为显示液晶可实时显示各项参数的状态
3.采用SIM800L作为短信通信模块,当检测到老人有特殊情况时候发短信到监护人手机
4.火焰检测使用模块,方便接插
5.心率脉搏检测采用成熟的模块,外接LM393比较器将心率信号进一步整形给单片机采集
6.加速度传感器采用的是ADXL345模块,用于检测老人是否跌倒。

原理图:
在这里插入图片描述

PCB:
在这里插入图片描述

主程序:

#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#include <math.h> //Keil library
#include "delay.h"
#include "adxl345.h"
#include "lcd1602.h"

#define ON  0
#define OFF 1

sbit FIRE_MONITOR = P1^2;
sbit BUZZER = P2^2;
sbit KEY_ALARM = P3^5; //手动报警按钮
sbit KEY_CANCEL  = P3^3; //退出报警

unsigned char dispFlag = 0; //刷新数据标志
bit fireFlag = OFF;
unsigned char fireDelaySec = 0; //温度过高计时

bit fallFlag = OFF;  //摔倒标志
unsigned char fallDelaySec = 0;   //摔倒计时

unsigned char datIndex = 0;
unsigned int timeCnt = 0;
unsigned int heartRateBuf[6] = {0}; //暂存心率值
bit heartRateFlag = OFF; //心率报警标志
unsigned char heartRateDelaySec = 0; //心率超标计时
unsigned int heartRate = 0;

bit refreshFlag = 0;
bit updateFlag = 0; //更新心率标志
bit alarmFLag = OFF;  //自动报警标志
bit alarmFLag1 = OFF; //手动报警标志

unsigned char dis[16];

unsigned char i;
unsigned char x;


void Ext0_Init(void); //外部中断0初始化程序
void Timer0_Init(void); //函数声明
void Timer1_Init(void); //函数声明
void KeyProcess(void);
void GSM_Send(void);
void HeartRate_Monitor(void);


void UART_Init(void);
void UART_SendByte(unsigned char dat);
void UART_SendStr(unsigned char *s, unsigned char length);

void main(void)
{
    static unsigned char ErrorNum = 0; //adxl345数据判断结果计数
    static unsigned char CheckNum = 0;

    Ext0_Init();
    Timer0_Init(); //定时器0初始化
    Timer1_Init(); //定时器1初始化
    UART_Init();
    Init_ADXL345();            //初+始化ADXL345
    Single_Read_ADXL345(0X00); //读出的数据为0XE5,表示正确
    LCD_Init();
    LCD_Clear();
    LCD_DispStr(0, 0, "    Welcome!    ");

    DelayS(3);
    UART_SendStr("AT+CMGF=1\r\n", 11);
    DelayS(3);
    LCD_Clear();
    
    
    while (1) //主循环
    {
        if (refreshFlag == 1)
        {
            HeartRate_Monitor(); //心率监测
        }

        if (dispFlag == 1) //定时读取温度标志
        {
            dispFlag = 0;

            if (FIRE_MONITOR == 0) //检测到由火焰
            {
                DelayMs(20);
                if (FIRE_MONITOR == 0) //确认检测到由火焰
                {
                    fireFlag = ON; //火焰预警标志
                }
            }
            else
            {
                fireFlag = OFF;
            }

            if (updateFlag == 0) //如果显示关  检测心率是否真实
            {
                heartRate = 0;
            }
            else //如果显示开
            {
                // heartRate = 60000 / (heartRateBuf[1] / 5 + heartRateBuf[2] / 5 + heartRateBuf[3] / 5 + heartRateBuf[4] / 5 + heartRateBuf[5] / 5); //心率计算 5次求平均值
                heartRate = 60000 / ((heartRateBuf[1]>>2) + (heartRateBuf[2]>>2) + (heartRateBuf[3]>>2) + (heartRateBuf[4]>>2)); //心率计算 4次求平均值
            }
            if (heartRate > 100) //心率超过100
            {
                heartRateFlag = ON; //心率预警标志
            }
            else
            {
                heartRateFlag = OFF;
            }

            ReadData_x(); //检测姿态
            CheckNum++;
            if ((fabs(temp_X) < 450) && (fabs(temp_Y) < 450)) //方位值判断 查看正常次数
            {
                ;
            }
            else //错误次数
            {
                ErrorNum++;
            }
            if (CheckNum >= 5) //进行5次处理
            {
                if (ErrorNum > 3) //3次以上则认为摔倒
                {
                    fallFlag = ON;
                }
                else
                {
                    fallFlag = OFF;
                }             //清除 摔倒标志
                ErrorNum = 0; //清空滤波计数
                CheckNum = 0; //清除总计数
            }

            sprintf(dis, "HeartRate:%3.0fbpm", (float)heartRate);
            LCD_DispStr(0, 0, dis); //显示心率

            if (fireFlag == ON)
            {
                LCD_DispStr(0, 1, "fire"); //显示火焰
                fireDelaySec++; //火焰检测计时
            }
            else
            {
                LCD_DispStr(0, 1, "    "); //显示
                fireDelaySec = 0; //否则清零
            }
            if (heartRateFlag == ON)
            {
                LCD_DispStr(5, 1, "heart"); //显示心率异常
                heartRateDelaySec++; //火焰检测计时
            } 
            else
            {
                LCD_DispStr(5, 1, "     "); //显示
                heartRateDelaySec = 0; //否则清零
            }
            if (fallFlag == ON)
            {
                LCD_DispStr(11, 1, "fall"); //显示摔倒
                fallDelaySec++; //摔倒计时
            }
            else
            {
                LCD_DispStr(11, 1, "    "); //显示
                fallDelaySec = 0; //否则清零
            }
                
        }

        if ((fireFlag == OFF) && (heartRateFlag == OFF) && (fallFlag == OFF))
        {
            alarmFLag = OFF; //关闭报警
        }

        if ((fireDelaySec >= 10) || (heartRateDelaySec >= 10) || (fallDelaySec >= 10)) //一定时间上报
        {
            alarmFLag = ON;
        }

        if (alarmFLag == ON || alarmFLag1 == ON) 
        {
            BUZZER = ON;
            GSM_Send();
        }
        else
        {
            BUZZER = OFF;
        }

        KeyProcess();

    }
}

void KeyProcess(void)
{
    if (KEY_ALARM == 0) //报警按键按下
    {
        DelayMs(5);
        if (KEY_ALARM == 0)
        {
            alarmFLag1 = ~alarmFLag1;
        }
        while (KEY_ALARM == 0);
    }

    else if (KEY_CANCEL == 0) //清零按键按下
    {
        DelayMs(5);
        if (KEY_CANCEL == 0)
        {
            fireFlag = OFF;     //火焰标志清零
            heartRateFlag = OFF; //心率超高标志清零
            fallFlag = OFF; //摔倒标志清零
            alarmFLag = OFF;    
            alarmFLag1 = OFF; 
        }
        while (KEY_CANCEL == 0);
    }
}

void HeartRate_Monitor(void)
{
    EX0 = 0;
    TR0 = 0;
    TR1 = 0;
    refreshFlag = 0;
    heartRateBuf[datIndex] = timeCnt * 5; //算出间隔时间
    TH0 = 0xEE; //(65536 - 0.005*11059200/12 + 200) / 256
    TL0 = 0xC8; //(65536 - 0.005*11059200/12 + 200) % 256  5ms
    timeCnt = 0; //50ms计数清零
    datIndex++;
    if (datIndex > 5) //记录到超过等于4次时间
    {
        datIndex = 1;   //计数从1开始
        updateFlag = 1; //测得5次开始显示
    }

    EX0 = 1;
    TR0 = 1;
    TR1 = 1;

}

void GSM_Send(void)
{
    UART_SendStr("AT+CMGF=1\r\n", 11);
    DelayS(2);

    UART_SendStr("AT+CSCS=\"GSM\"\r\n", 15);
    DelayS(2);

    UART_SendStr("AT+CMGS=\"+86xxxxxxxxxxx\"\r\n", 26); //可以修改电话号码
    DelayS(2);

    if (alarmFLag1 == ON)
    {
        UART_SendStr("I'm not well!\x1a", 14); //可以修改短信内容,不可以发汉字,如果发汉字的话,需要转化为特定的码
        alarmFLag1 = OFF;
    }

    if (fireDelaySec >= 10)
    {
        UART_SendStr("The house is on fire!\x1a", 22); //可以修改短信内容,不可以发汉字,如果发汉字的话,需要转化为特定的码
        fireDelaySec = 0;                //清除计数
    }
    
    if (heartRateDelaySec >= 10)
    {
        UART_SendStr("Arrhythmia!\x1a", 12); //可以修改短信内容,不可以发汉字,如果发汉字的话,需要转化为特定的码
        heartRateDelaySec = 0;                //清除计数
    }

    if (fallDelaySec >= 10)
    {
        UART_SendStr("I fell down!\x1a", 13); //可以修改短信内容
        fallDelaySec = 0;              //清除计数
    }
    DelayS(1);

}

/***********外部中断0初始化程序****************/
void Ext0_Init() //外部中断0初始化程序
{
    IT0 = 1; //外部中断0负跳变中断
    PX0 = 1; //设置高优先级
    EX0 = 1; //允许外部中断0中断
}

void Ext0_Interrupt() interrupt 0
{
    if (timeCnt < 100) //当连续两次检测时间间隔小于10*50ms=500ms不处理
    {
        TR0 = 1; //开定时器
    }
    else
    {
        refreshFlag = 1;
    }
}

/*************定时器初始化程序***************/
void Timer0_Init()
{
    TMOD &= 0xF0;
    TMOD |= 0x01; //定时器0工作方式1
    TH0 = 0xB8; //(65536 - 0.02*11059200/12) / 256
    TL0 = 0x00; //(65536 - 0.02*11059200/12) % 256  20ms
    PT0 = 1;    //设置高优先级
    ET0 = 1;    //开定时器0中断
    TR0 = 1;    //允许定时器0定时
}

/*************定时器0中断服务程序***************/
void Timer0_Interrupt() interrupt 1
{
    TH0 = 0xEE; //(65536 - 0.005*11059200/12 + 200) / 256
    TL0 = 0xC8; //(65536 - 0.005*11059200/12 + 200) % 256  5ms
    timeCnt++; //每5ms一次计数

    if (timeCnt > 250) //当超过25*50ms=1.5s没有检测到信号停止显示
    {
        datIndex = 0;   //数据个数清零
        timeCnt = 0;  //50ms计数清零
        updateFlag = 0;
        TR0 = 0;      //定时器关
    }
}

void Timer1_Init(void)
{
    TMOD &= 0x0F;                //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
    TMOD |= 0x10;                //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
    TH1 = 0xB8; //(65536 - 0.02*11059200/12) / 256
    TL1 = 0x00; //(65536 - 0.02*11059200/12) % 256  20ms
    EA = 1;  //总中断打开
    ET1 = 1; //定时器中断打开
    TR1 = 1; //定时器开关打开
}

void UART_Init(void)
{
    SCON = 0x50;
	TH2 = 0xFF;
	TL2 = 0xFD;
	RCAP2H = 0xFF;  //(65536-(FOSC/32/BAUD))   BAUD = 115200 FOSC = 11059200
	RCAP2L = 0xFD;

	/*****************/
	TCLK = 1;
	RCLK = 1;
	C_T2 = 0;
	EXEN2 = 0;

	/*****************/
	TR2 = 1;
	ES   = 1; //打开串口中断
	EA   = 1; //打开总中断
}

void UART_SendByte(unsigned char dat) //串口发送单字节数据
{
    unsigned char time_out;
    time_out = 0x00;
    SBUF = dat;                       //将数据放入SBUF中
    while ((!TI) && (time_out < 100)) //检测是否发送出去
    {
        time_out++;
        DelayUs10x(2);
    }       //未发送出去 进行短暂延时
    TI = 0; //清除ti标志
}

void UART_SendStr(unsigned char *s, unsigned char length) //发送定长度字符串
{
    unsigned char NUM;
    NUM = 0x00;
    while (NUM < length) //发送长度对比
    {
        UART_SendByte(*s); //放松单字节数据
        s++;              //指针++
        NUM++;            //下一个++
    }
}

void Timer1_Interrupt(void) interrupt 3
{
    static unsigned char times_20ms = 0; //定时20ms计时

    TH1 = 0xB8; //(65536 - 0.02*11059200/12) / 256
    TL1 = 0x00; //(65536 - 0.02*11059200/12) % 256  20ms
    times_20ms++;
    if (times_20ms > 50)
    {
        times_20ms = 0;
        dispFlag = 1; //显示标志置1
    }
}

void UART_SER(void) interrupt 4 //串行中断服务程序
{    
    if (RI) //判断是接收中断产生
        RI = 0; //标志位清零
    if (TI) //如果是发送标志位,清零
        TI = 0;
}

实物演示视频:
https://www.bilibili.com/video/BV1cY411F7Lc/

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值