功能介绍:
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;
}