本项目设计一种可穿戴式的跌倒检测报警系统,通过水平检测模块检测水平信息,采用STC新型单片机进行实时计算、分析,判别是否发生跌倒,若判定为佩戴者跌倒则控制MCU将通过GPS模块实时获取经纬度信息,并通过GSM模块向特定联系人发送警报,通知相关监护人员此情况。
/*******************************************************************************
* 文件名称:基于嵌入式的老人定位追踪监测仪
* 实验目的:1.
* 2.
* 程序说明:完整程序Q:2772272579;@: [email protected]
* 日期版本:基本的程序逻辑都在这个main.c文件中,有基础的可做参阅,作为电子栅栏的设计方法。2022年8月1日。
*******************************************************************************/
#include"config.h"
#include"delay.h"
#include"GPIO.h"
#include"Uart2_Timer2.h"
#include"GSM.h"
#include"Uart1_Timer1.h"
#include"Key_Duli_S.h"
#include"eeprom.h"
/********************全局宏定义 **************************/
#define ON 1
#define OFF 0
#define false 0
#define true 1
//定义数组长度
#define UTCTime_Length 11
#define latitude_Length 11
#define N_S_Length 2
#define longitude_Length 12
#define E_W_Length 2
#define LED_GREEN 0x01
#define LED_RED 0x02
#define BEEP 0x04
#define ALL 0xff
#define SMS_Massege_Max 50
#define EE_ADDRESS 0x0400 //保存的地址 IAP方式读写 使用了第三扇区,0x0400-0x05ff 参照STC手册:P742
char xdata Data_SentTemp[200];
char xdata SMS_Massege_Table[SMS_Massege_Max]={"3342.503153N,11328.607354E,con:80"};
bit Flag_Check=0,Flag_Warning=0,Flag_GPS_StateOk=0,Flag_GSM_StateOk=0,Flag_GPS_Wait=0,Flag_GPS_Time=1,Flag_GPS_WorkTime=0;
bit Flag_Warning_Key=0,Flag_KeyWarning=0,Flag_KeyTime=0,Flag_Warning_GpsCheck=0;
char xdata set_phone_num[25]={"AT+CMGS=\"18339698097\""}; //固定接收信息的联系人手机号
bit Flag_GSM_Error=0;
char xdata Display_GPGGA_Buffer[80];
bit Flag_Calc_GPGGA_OK = 0;
int GPS_WaitTime=40;
typedef struct SaveData
{
char UTCTime[UTCTime_Length]; //UTC时间
char latitude[latitude_Length]; //纬度
char N_S[N_S_Length]; //N/S
char longitude[longitude_Length]; //经度
char E_W[E_W_Length]; //E/W
char isUsefull; //定位信息是否有效
} xdata _SaveData;
_SaveData Save_Data;
/********************函数声明函数 **************************/
bit GPS_Check();
void Key_Handle(uchar date);
void GPS_Handle();
void Timer0_Init(uchar ms);
void GSM_Init();
void LED_BEEP_Prompt(uchar components,uchar state);
void SystemInit();
/******************** IO配置函数 **************************/
void GPIO_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
GPIO_InitStructure.Pin = GPIO_Pin_2; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P2,&GPIO_InitStructure); //初始化 蜂鸣器IO,推挽输出
}
/******************** 主函数 **************************/
void main()
{
uchar Key_NumRead=20;
int ret=0;
SystemInit();
while(1)
{
Key_NumRead=Key_Scan();
if(Key_NumRead<20)
{
Key_Handle(Key_NumRead);
}
if(Flag_GPS_Wait)
{
Flag_GPS_Wait=0;
GPS_Handle();
Flag_Warning_GpsCheck=GPS_Check();
}
if(Flag_Warning_Key || Flag_Warning_GpsCheck)
{
Flag_Warning=1;
LED_BEEP_Prompt(LED_GREEN,OFF);
}
else
{
Flag_Warning=0;
if(Flag_GSM_StateOk && Flag_GPS_StateOk)
{
LED_BEEP_Prompt(LED_GREEN,ON);
LED_BEEP_Prompt(LED_RED|BEEP,OFF);
}
else
{
LED_BEEP_Prompt(LED_RED|BEEP,ON);
LED_BEEP_Prompt(LED_GREEN,OFF);
}
}
if(Flag_KeyTime)
{
Flag_KeyTime=0;
GSM_CLR_Buf();
ret = send_text_message_set("Emergency situations! The elderly have safety problems, please deal with them in time!");
if(ret == 1)
{
SendStr("****当前状态:GSM发送报警短信成功!\r\n");
Delay_Ms(Lcd_Message_Time*4);
}
else
{
SendStr("****当前状态:GSM发送报警短信失败!\r\n");
Delay_Ms(Lcd_Message_Time*4);
Flag_GSM_Error=1;
}
GSM_CLR_Buf();
GSM_find_string_flag = 0;
}
if(GSM_find_string_flag == 1)
{
Delay_Ms(2000);//延时一点,让串口把数据接收完成
if(Find("+CMTI"))//说明接收到了短信
{
ret = read_message();
SendStr("****当前状态:GSM接收信息查看:\r\n");
SendStr(GSM_Receive_Buf);
extract_phone_number();
if(ret == 1)
{
if(Find("check"))
{
memset(Data_SentTemp, 0, sizeof(Data_SentTemp)); //清空
sprintf(Data_SentTemp,"UTCTime:%s,GPS:lat:%s,lng:%s \r\n",Save_Data.UTCTime,Save_Data.latitude,Save_Data.longitude);
SendStr("****当前状态:待回复的内容为:\r\n");
SendStr(Data_SentTemp);
ret = send_text_message(Data_SentTemp);
if(ret == 1)
{
SendStr("****当前状态:单片机接收到查看指令,将GPS信息回复给监控人!\r\n");
}
}
if(Find("set"))
{
extract_SMS_Massege(SMS_Massege_Table);
sprintf(Data_SentTemp,"Successfully changed the electronic fence settings! \r\n");
ret = send_text_message(Data_SentTemp);
if(ret == 1)
{
SendStr("****当前状态:单片机接收到设置指令,将回馈成功短信...\r\n");
}
/********* 调试 *********/
memset(Data_SentTemp, 0, sizeof(Data_SentTemp)); //清空
sprintf(Data_SentTemp,"****当前状态:提取到的短信设定内容为:%s \r\n",SMS_Massege_Table);
SendStr(Data_SentTemp);
EEPROM_SectorErase(EE_ADDRESS);
SMS_Massege_Table[sizeof(SMS_Massege_Table)-1]=99;
EEPROM_write_n(EE_ADDRESS,SMS_Massege_Table,sizeof(SMS_Massege_Table));
SendStr("****当前状态:已将提取到的短信内容存储到EEROM中...\r\n");
}
GSM_CLR_Buf();
GSM_find_string_flag = 0;
}
}
}
}
}
/********************系统初始化函数 **************************/
char xdata EEPROM_Table[SMS_Massege_Max];
char xdata EEPROM_Check[2];
void SystemInit()
{
GPIO_config();
LED_BEEP_Prompt(ALL,ON);
Timer0_Init(20); //20MS定时
UART1_Init();
UART2_Init();
Delay_Ms(1000);
LED_BEEP_Prompt(ALL,OFF);
Delay_Ms(1000);
Flag_Check=1;
SendStr("****** STC15F2K32S2 -- Uart1 Sent *******\r\n");
SendStr("******** 欢迎使用 老年人定位追踪检测仪 *****\r\n");
SendStr("******** 本设计由 **** *** 制作 *******\r\n");
SendStr("** Real-time display of data transmission **\r\n");
SendStr("****当前状态:正在检测GSM模块,等待信号中...\r\n");
GSM_Init();
if(Flag_GSM_Error)
{
Flag_GSM_StateOk=0;
SendStr("****当前状态:检测到GSM模块异常,请及时处理!下一项:等待GPS信号接收...\r\n");
}
else
{
Flag_GSM_StateOk=1;
SendStr("****当前状态:GSM模块工作正常,下一项:等待GPS信号接收...\r\n");
}
EEPROM_read_n(EE_ADDRESS+SMS_Massege_Max+1,EEPROM_Check,1); //读出字节
if(EEPROM_Check[0] !=99) // 新单片机,没有断电标记
{
EEPROM_SectorErase(EE_ADDRESS); //清空EEROM内存,装载断电存储值
EEPROM_Check[0]=99;
EEPROM_write_n(EE_ADDRESS+SMS_Massege_Max+1,EEPROM_Check,1);
EEPROM_write_n(EE_ADDRESS,SMS_Massege_Table,SMS_Massege_Max);
}
else
{
memset(EEPROM_Table, 0, sizeof(EEPROM_Table)); //清空
EEPROM_read_n(EE_ADDRESS,EEPROM_Table,SMS_Massege_Max); //读出字节
strcpy(SMS_Massege_Table,EEPROM_Table); //赋值给当前的设定数组
}
memset(Data_SentTemp, 0, sizeof(Data_SentTemp)); //清空
sprintf(Data_SentTemp,"****当前状态:设定的GPS电子栅栏为:%s \r\n",SMS_Massege_Table);
SendStr(Data_SentTemp);
Save_Data.isUsefull = false;
memset(Save_Data.UTCTime, 0, UTCTime_Length);
memset(Save_Data.latitude, 0, latitude_Length);
memset(Save_Data.N_S, 0, N_S_Length);
memset(Save_Data.longitude, 0, longitude_Length);
memset(Save_Data.E_W, 0, E_W_Length);
memset(Data_SentTemp, 0, sizeof(Data_SentTemp)); //清空
while(!Flag_GPS_StateOk)
{
if(Flag_GPS_Wait)
{
Flag_GPS_Wait=0;
memset(Data_SentTemp, 0, sizeof(Data_SentTemp)); //清空
sprintf(Data_SentTemp,"***当前状态:等待GPS接收信号倒计时:%d \r\n",GPS_WaitTime--);
SendStr(Data_SentTemp);
if(GPS_WaitTime<0)
{
GPS_WaitTime=40;
Flag_GPS_Time=0;
Flag_GPS_WorkTime=1;
Flag_GPS_StateOk=0;
SendStr("****当前状态:GPS模块接收信号失败!\r\n");
goto ENDCHECK;
}
GPS_Handle();
}
}
ENDCHECK: Flag_Check=0;
LED_BEEP_Prompt(ALL,OFF);Flag_Check=0;
Flag_GPS_Time=0;Flag_GPS_WorkTime=1;
if(Flag_GSM_StateOk && Flag_GPS_StateOk)
{
LED_BEEP_Prompt(LED_GREEN,ON);
SendStr("****当前状态:上电检测完成,进入待机检测状态...\r\n");
}
else
{
LED_BEEP_Prompt(LED_RED|BEEP,ON);
}
}
/********************电子栅栏函数 **************************/
int xdata lat_H=0,lat_L=0,lng_H=0,lng_L=0;
int xdata lat_Set_H=0,lat_Set_L=0,lng_Set_H=0,lng_Set_L=0;
int xdata con=10;
int xdata cal_qian=0,cal_bai=0,cal_shi=0,cal_ge=0;
bit GPS_Check() //SMS_Massege_Table: 3342.503153N,11328.607354E,con:80 //11:N 25:E 31,32:80
{
memset(Data_SentTemp, 0, sizeof(Data_SentTemp)); //清空
sprintf(Data_SentTemp,"****当前状态:设定的GPS电子栅栏为:%s \r\n",SMS_Massege_Table);
SendStr(Data_SentTemp);
cal_bai=(int)(Save_Data.latitude[0]-0x30);
cal_shi=(int)(Save_Data.latitude[1]-0x30);
cal_ge=(int)(Save_Data.latitude[2]-0x30);
lat_H=cal_bai*100+cal_shi*10+cal_ge; //维度高三位
cal_bai=(int)(Save_Data.latitude[3]-0x30);
cal_shi=(int)(Save_Data.latitude[5]-0x30);
cal_ge=(int)(Save_Data.latitude[6]-0x30);
lat_L=cal_bai*100+cal_shi*10+cal_ge; //维度低三位
cal_qian=(int)(Save_Data.longitude[0]-0x30);
cal_bai=(int)(Save_Data.longitude[1]-0x30);
cal_shi=(int)(Save_Data.longitude[2]-0x30);
cal_ge=(int)(Save_Data.longitude[3]-0x30);
lng_H=cal_qian*1000+cal_bai*100+cal_shi*10+cal_ge; //经度高四位
cal_bai=(int)(Save_Data.longitude[4]-0x30);
cal_shi=(int)(Save_Data.longitude[6]-0x30);
cal_ge=(int)(Save_Data.longitude[7]-0x30);
lng_L=cal_bai*100+cal_shi*10+cal_ge; //经度低三位
memset(Data_SentTemp, 0, sizeof(Data_SentTemp)); //清空
sprintf(Data_SentTemp,"lat_H:%d,lat_L:%d,lng_H:%d,lng_L:%d;\r\n",lat_H,lat_L,lng_H,lng_L);
SendStr("****当前状态:GPS信息校对:\r\n");
SendStr(Data_SentTemp);
cal_bai=(int)(SMS_Massege_Table[0]-0x30);
cal_shi=(int)(SMS_Massege_Table[1]-0x30);
cal_ge=(int)(SMS_Massege_Table[2]-0x30);
lat_Set_H=cal_bai*100+cal_shi*10+cal_ge; //维度高三位
cal_bai=(int)(SMS_Massege_Table[3]-0x30);
cal_shi=(int)(SMS_Massege_Table[5]-0x30);
cal_ge=(int)(SMS_Massege_Table[6]-0x30);
lat_Set_L=cal_bai*100+cal_shi*10+cal_ge; //维度低三位
cal_qian=(int)(SMS_Massege_Table[13]-0x30);
cal_bai=(int)(SMS_Massege_Table[14]-0x30);
cal_shi=(int)(SMS_Massege_Table[15]-0x30);
cal_ge=(int)(SMS_Massege_Table[16]-0x30);
lng_Set_H=cal_qian*1000+cal_bai*100+cal_shi*10+cal_ge; //经度高四位
cal_bai=(int)(SMS_Massege_Table[17]-0x30);
cal_shi=(int)(SMS_Massege_Table[19]-0x30);
cal_ge=(int)(SMS_Massege_Table[20]-0x30);
lng_Set_L=cal_bai*100+cal_shi*10+cal_ge; //经度低三位
cal_shi=(int)(SMS_Massege_Table[31]-0x30); //引号占两个位置!!!!!!
cal_ge=(int)(SMS_Massege_Table[32]-0x30);
con=cal_shi*10+cal_ge; //电子栅栏范围
// SendStr("****当前状态:con调试:");
// SendByte(SMS_Massege_Table[29]);
// SendByte(SMS_Massege_Table[30]);
// SendByte(SMS_Massege_Table[31]);
// SendByte(SMS_Massege_Table[32]);
// SendStr("\r\n");
memset(Data_SentTemp, 0, sizeof(Data_SentTemp)); //清空 调试经验:sprintf函数可容纳输入变量只有4个,再多会导致错误!!!!
sprintf(Data_SentTemp,"lat_Set_H:%d,lat_Set_L:%d,lng_Set_H:%d,lng_Set_L:%d;\r\n",lat_Set_H,lat_Set_L,lng_Set_H,lng_Set_L);
SendStr("****当前状态:GPS设定校对:\r\n");
SendStr(Data_SentTemp);
memset(Data_SentTemp, 0, sizeof(Data_SentTemp)); //分多次格式化输入和传送!
sprintf(Data_SentTemp,"con:%d\r\n",con);
SendStr("****当前状态:电子栅栏范围:");
SendStr(Data_SentTemp);
SendStr("\r\n");
if(lat_H==lat_Set_H && ((lat_L+con)>lat_Set_L && (lat_L-con)<lat_Set_L))
{
if(lng_H==lng_Set_H && ((lng_L+con)>lng_Set_L && (lng_L-con)<lng_Set_L))
{
return 0; //处于栅栏范围返回0
}
}
return 1; //超出栅栏范围返回1
}
/******************** 按键处理函数 **************************/
extern uint Timer0_Count_04;
void Key_Handle(uchar date)
{
if(date==2)
{
Flag_Warning_Key=1;
Flag_KeyWarning=1;
SendStr("****当前状态:紧急呼叫按键按下,15S后发送报警信...\r\n");
}
if(date==1)
{
Flag_Warning_Key=0;
Flag_KeyWarning=0;
Flag_KeyTime=0;
Timer0_Count_04=0;
SendStr("****当前状态:取消紧急呼叫状态...\r\n");
}
}
/********************GPS 函数 **************************/
void GPS_Handle()
{
char i=0;
char *subString;
char *subStringNext;
char usefullBuffer[2];
if(Flag_Calc_GPGGA_OK)
{
Flag_Calc_GPGGA_OK=0;
for (i = 0 ; i <= 6 ; i++)
{
if (i == 0)
{
if ((subString = strstr(Display_GPGGA_Buffer, ",")) == NULL) //$GNRMC,152642.000,A,3342.503153,N,11328.607354,E,0.00,189.14,050520,,,A*7C
{
SendStr("****当前状态:GPS信号解析错误!\r\n"); //解析错误
Flag_GPS_StateOk=0;
}
}
else
{
subString++; //出现第一个','的位置开始截取,此位置为',',需要地址加一,判断下一个','所在位置
if((subStringNext = strstr(subString, ",")) != NULL) // char *strstr(const char *haystack, const char *needle) 在字符串 haystack 中查找第一次出现字符串 needle 的位置,从此位置开始截取字符串,不包含终止符 '\0'
{
switch(i)
{
case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break; //获取UTC时间
case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break; //获取GPS接收信号状态
case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break; //获取纬度信息
case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break; //获取N/S
case 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break; //获取经度信息
case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break; //获取E/W
default:break;
}
subString = subStringNext;
if(usefullBuffer[0] == 'A')
{
Save_Data.isUsefull = true;
Flag_GPS_StateOk=1;
}
else if(usefullBuffer[0] == 'V')
{
Save_Data.isUsefull = false;
Flag_GPS_StateOk=0;
SendStr("****当前状态:当前GPS未接收到信号!正在重试...\r\n"); //解析错误
}
}
else
{
SendStr("****当前状态:GPS信号解析错误!\r\n"); //解析错误
Flag_GPS_StateOk=0;
}
}
}
}
if(Save_Data.isUsefull)
{
Save_Data.isUsefull = false;
SendStr("****当前状态:GPS模块接收正常,本次使用的数据为:\r\n");
SendStr(Display_GPGGA_Buffer);
SendStr("\r\n");
SendStr("****当前状态:从GPS帧中提取到的信息为:\r\n");
SendStr("Save_Data.UTCTime = ");
SendStr(Save_Data.UTCTime);
SendStr("\r\n");
SendStr("Save_Data.latitude = ");
SendStr(Save_Data.latitude);
SendStr("\r\n");
SendStr("Save_Data.N_S = ");
SendStr(Save_Data.N_S);
SendStr("\r\n");
SendStr("Save_Data.longitude = ");
SendStr(Save_Data.longitude);
SendStr("\r\n");
SendStr("Save_Data.E_W = ");
SendStr(Save_Data.E_W);
SendStr("\r\n");
}
}
/********************定时器0 函数 **************************/
#define T1MS (65536-MAIN_Fosc/1000) //1T模式
void Timer0_Init(uchar ms) //ms:定时多少毫秒,12T下最好选择0-20 ,1T下只有100US-2MS
{
// AUXR |= 0x80; //定时器0为1T模式
AUXR &= 0x7f; //定时器0为12T模式
TMOD &= 0xF0; //设置定时器为模式0(16位自动重装载)
TL0 = T1MS*(ms); //初始化计时值
TH0 = T1MS*(ms)>> 8;
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
EA = 1;
}
uint Timer0_Count_01=0,Timer0_Count_02=0,Timer0_Count_03=0,Timer0_Count_04=0,Timer0_Count_05=0;
void Timer0_isr() interrupt 1
{
if(Flag_Check)
{
Timer0_Count_01++;
if(Timer0_Count_01==20)
LED_BEEP_Prompt(LED_GREEN|BEEP,ON);
if(Timer0_Count_01>40)
{
Timer0_Count_01=0;
LED_BEEP_Prompt(LED_GREEN|BEEP,OFF);
}
}
if(Flag_Warning)
{
Timer0_Count_02++;
if(Timer0_Count_02==10)
LED_BEEP_Prompt(LED_RED|BEEP,ON);
if(Timer0_Count_02>20)
{
Timer0_Count_02=0;
LED_BEEP_Prompt(LED_RED|BEEP,OFF);
}
}
if(Flag_GPS_Time)
{
Timer0_Count_03++;
if(Timer0_Count_03>50)
{
Timer0_Count_03=0;
Flag_GPS_Wait=1;
}
}
if(Flag_KeyWarning)
{
Timer0_Count_04++;
if(Timer0_Count_04>50*15)
{
Timer0_Count_04=0;
Flag_KeyTime=1;
Flag_KeyWarning=0;
}
}
if(Flag_GPS_WorkTime)
{
Timer0_Count_05++;
if(Timer0_Count_05>50*20)
{
Timer0_Count_05=0;
Flag_GPS_Wait=1;
}
}
}
/********************SIM868 GSM初始化函数 **************************/
void GSM_Init()
{
int ret=0; uchar i=0;
for(i = 0;i < STABLE_TIMES;i++)//等待网络稳定
{
Delay_Ms(Lcd_Message_Time);
}
ret = GSM_check_status(); //初始化配置 检测GSM
if(ret == 1)
{
SendStr("****当前状态:GSM检测信号正常!\r\n");
Delay_Ms(Lcd_Message_Time);
ret = config_format();//配置
if(ret == 1)
{
SendStr("****当前状态:GSM通信配置正常!\r\n");
Delay_Ms(Lcd_Message_Time);
}
else
{
SendStr("****当前状态:GSM通信配置失败!\r\n");
Delay_Ms(Lcd_Message_Time);
Flag_GSM_Error=1;
}
}
else
{
SendStr("****当前状态:GSM检测信号失败!\r\n");
Delay_Ms(Lcd_Message_Time);
Flag_GSM_Error=1;
}
GSM_CLR_Buf();
ret = send_text_message_set("Hello,SIM868 GSM Deploy OK!");
if(ret == 1)
{
SendStr("****当前状态:GSM发送短信测试成功!\r\n");
Delay_Ms(Lcd_Message_Time);
}
else
{
SendStr("****当前状态:GSM发送短信测试失败!\r\n");
Delay_Ms(Lcd_Message_Time);
Flag_GSM_Error=1;
}
GSM_CLR_Buf();
GSM_find_string_flag = 0;
}
/******************** 报警提示信息函数,LED,蜂鸣器 **************************/
sbit Beep=P2^2;
sbit LED_RedIo=P3^4;
sbit LED_GreenIo=P2^0;
void LED_BEEP_Prompt(uchar components,uchar state)
{
if(components & 0x01)
{
if(state)
LED_GreenIo=0;
else
LED_GreenIo=1;
}
if(components & 0x02)
{
if(state)
LED_RedIo=0;
else
LED_RedIo=1;
}
if(components & 0x04)
{
if(state)
Beep=0;
else
Beep=1;
}
}