一、功能设计
1、北斗定位器:
北斗卫星导航系统由空面段、地面段和用户段三部分组成,可在全球范围内全天候、全天时为各类用户提供高精度、高可靠定位等功能,已经初步具备区域导航、定位和授时能力,定位精度 10米,测速精度0.2米/秒,授时精度10纳秒。
用户段即用户的终端,即可以是专用于北斗卫星导航系统的信号接收机,也可以是同时兼容其他卫星导航系统的接收机。接收机需要捕获并跟踪卫星的信号,根据数据按一定的方式进行定位计算,最终得到用户的经纬度、高度、速度、时间等信息。
北斗卫星导航系统的定位精度:水平精度100米(1σ),设立标校站之后为20米(类似差分状态)。工作频率:2491.75MHz。
因此安装了北斗定位器的救生衣,可以使得救援人员及时定位遇难者的位置,赢得宝贵的救援时间。我们的智能救生衣将每隔一分钟向中心端发送一次定位信息,因此即使在救援过程中遇难者随着洋流不断地改变位置,搜救人员也能第一时间获取其相关位置,以此缩短救援时间。由救生衣北斗定位信号器发送的地理位置将在搜救中心的中心端服务器上显示,每一位遇难者的位置,都会在具体的地图上以单位坐标点的形势展现,救援中心并可根据此坐标点组织安排救援工作。
2、充电设备:
救生衣的电池组包括单晶硅太阳能板和可充电式蓄电池。太阳能板采用7V单晶硅太阳能板,既保证电能的供应,又轻巧耐用、环保节能。蓄电池采用5V 4000mAH的型号,保证电能的供应。单晶硅太阳能板可在电量不足时,将光能转换为电能为蓄电池充电。以保证救生衣上相关设备的长时间使用。
3、开关设备:
此款救生衣具备自动及手动开关。自动开关运用湿度传感器,如果检测的湿度到达一定特值时,相关开关便会自动打开,并通过无线传输模块将所获信息发送给救援平台,与此同时救生衣上的开关显示灯将会发光,提醒遇难者智能救生衣已开始工作。如果在湿度到达一定特值时,显示灯未亮,此时便需要遇难者手动打开开关。手动开关将位于左胸明显位置处,方便遇难者操作。
4、脉搏检测器:
脉搏检测器将位于颈部位置,可安装压力式式连续心率传感器、低功耗加速度传感器,以此检测遇难者是否还具有生命体征,使得救援中心可以组织安排迅速有效的救援工作。
5、体温维持装备
由于海水温度低,遇难者长时间浸泡在海水中,会使体温降低,不利于救援工作的开展。因此在救生衣的胸腔及背部安装发热片,本装置将在人体体表温度低于25摄氏度时自动开启,延长遇难者的水下生存时间,为救援工作的顺利开展赢得宝贵的时间。本装置核心部件采用石墨烯复合金属纤维,韧性好,发热效率高,功率在1.5W到3W。
6、云存储
采用阿里云提供的OSS云存储平台进行数据的整理及存储。阿里云云存储的优势:(1)易于扩展:根据服务器使用人数和空间及时扩展存储空间,不会影响前端用户的使用。(2)可靠安全:数据同步有效避免了介质存储数据造成丢失损坏的问题。同时对服务器采用磁盘阵列和磁带脱机备份方式,保障了云存储的安全。(3)资源可控性:用户可主动控制数据访问权限。(4)提高资源利用率:将数据集中起来,用户可以在任何地点,依靠单机或是移动设备随时访问数据。实现网内资源共享和协同工作,减少了传统的资源交换,提高资源的利用率。(5)成本的下降:大大减少移动存储设备的使用,降低了企业成本。
二、技术路线
1、技术实现
上位机系统实现了数据信息的高效传递,第一时间将采集到的遇难者信号转化为可视化坐标数据,搜救船与遇难者的位置距离一目了然,让搜救船能迅速赶往遇难者的位置进行救援,2.4Ghz为全球开放ISM频段免许可证使用,双通讯路线拥有更可靠的定位保障,增加了救援机会
- 前端界面采用WEB
- 由信号接收装置进行遇难者的数据采集
- 通过接口与硬件设备连接进行数据交互处理
- 通讯模块采用抗干扰能力强的cc2530模块和GPRS通讯模块 双通讯路线
- 定位数据服务器用于接收救生衣通过GPRS模块上传的各种数据
- 数据服务器用于分析大数据以改进产品
2、存在问题和解决方案
- 如果存在定位不准的情况,可以在救生衣上安装手摇发电的红光探照灯及扬声器,让搜救人员在视线不佳及定位不准的情况下可以快速确定遇难者的位置,缩短救援时间,另外求救者也不必大声呼喊,可以保持体力,延长等待救援时间。
- 生命体征的检测,由于海上事故发生时,遇难者没有足够的时间来佩戴诸如生命体征检测手环等设备。因此可以在救生衣的颈部位置安装脉搏检测器,检测遇难者的脉搏是否跳动,以此确定遇难者是否具有正常生命体征,使搜救中心可以安排合理的搜救路线及先后顺序。
3、模型
三、软件设计报告
(一)流程图设计
- 温控设备设计图
(二)主要代码
- 温控设备设计图
//P37-->J14
//P14-->J15
#include "reg52.h"
#include "intrins.h"
#include "math.h"
#include "stdio.h"
#include "temp.h"
#include "lcd.h"
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
sbit relay=;
u16 getTemp;
char num=0;
u8 show[]="TMP";
/*******************************************************************************
* 函 数 名 : delay
* 函数功能 : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
while(i--);
}
/*******************************************************************************
* 函 数 名 : datapros()
* 函数功能 : 温度读取处理转换函数
* 输 入 : temp
* 输 出 : 无
*******************************************************************************/
void datapros(int temp)
{
float tp;
if(temp< 0) //当温度值为负数
{
DisplayOneChar(2,1,'-'); // -
temp=temp-1;
temp=~temp;
}
else
{
DisplayOneChar(2,1,' ');
}
tp=temp;
temp=tp*0.0625*100+0.5;
//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
//后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
//算加上0.5,还是在小数点后面。
LcdShowStr(0,0,show);
DisplayOneChar(3,0,temp/1000+'0');
DisplayOneChar(4,0,temp%1000/100+'0');
DisplayOneChar(5,0,'.');
DisplayOneChar(6,0,temp%1000%100/10+'0');
DisplayOneChar(7,0,temp%1000%10%10+'0');
getTemp=temp%1000;
}
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
u16 y=0;
LcdInit();
while(1)
{
datapros(Ds18b20ReadTemp()); //数据处理函数
delay(500);
if(y==0)
{
if(getTemp<20)
{
y=1;
}
}
if(y==1)
{
relay=0;
}
}
}
- 心率检测
#include <STC12C5A60S2.h>
#include "stdio.h"
#include <LCD1602.h>
#define false 0
#define true 1
#define FOSC 11059200L //系统时钟
#define BAUD 115200 //波特率
#define T0MS (65536-FOSC/12/500)
#define ADC_POWER 0x80 //ADC POWER CONTROL BIT
#define ADC_FLAG 0x10 //ADC COMPLETE FLAG
#define ADC_START 0x08; //ADC START CONTROL BIT
#define ADC_SPEEDLL 0x00 //540 CLOCKS
#define ADC_SPEEDL 0x20 //360 CLOCKS
#define ADC_SPEEDH 0x40 //180 CLOCKS
#define ADC_SPEEDHH 0x60 //90 CLOCKS
#define ADC_MASK 0x01
void UART_init(void);
void ADC_init(unsigned char channel);
void T0_init(void);
void sendDataToProcessing(char symbol, int dat);
void UART_send(char dat);
unsigned char PulsePin = 0; // P1.0为传感器输入口
int fadeRate = 0;
volatile unsigned int BPM; // 捕捉速率
volatile unsigned int Signal; // 保存传入的原始数据
volatile unsigned int IBI = 600; // 两次心跳之间的时间
volatile bit Pulse = false; // 跳动为true,不然为false
volatile bit QS = false;
volatile int rate[10]; // 保存最后十个IBI值的数组
volatile unsigned long sampleCounter = 0; // 用于确定脉冲时间
volatile unsigned long lastBeatTime = 0; // 用来找到IBI
volatile int Peak =512; // 用于在脉冲波中寻找峰值
volatile int Trough = 512; // 用来找到脉搏波的低谷
volatile int thresh = 512; // 用来寻找瞬间的心跳瞬间
volatile int amp = 100; // 用于保持脉冲波形的振幅
volatile bit firstBeat = true; // 启动BPM
volatile bit secondBeat = false; // 再次启动BPM
static unsigned char order=0;
unsigned char code ucForum0[]="Pulsesensor test";
unsigned char code ucForum1[]=" BPM: ";
unsigned char DisBuff[4]={0};
void sys_init()
{
UART_init();
ADC_init(PulsePin);
T0_init(); // 设置每2mS读取脉冲传感器信号
LCD1602_Init(); //液晶初始化
}
void main(void)
{
sys_init();
LCD1602_DisplayString(ucForum0); //显示的内容
LCD1602_MoveToPosition(1,0); //显示位置移动到指定位置
LCD1602_DisplayString(ucForum1); //显示的内容
while(1)
{
sendDataToProcessing('S', Signal); // 发送原始脉冲传感器数据进行处理
if (QS == true){ // 发现心跳时,QS为真
fadeRate = 255; // 设置'fadeRate'变到255脉冲消失LED
sendDataToProcessing('B',BPM); // 发送心率与'B'前缀
sendDataToProcessing('Q',IBI); // 发送心率与'Q'前缀
QS = false; // QS重置为false
LCD1602_MoveToPosition(1,9);
LCD1602_DisplayString(DisBuff);
}
delay(138);
}
}
void sendDataToProcessing(char symbol, int dat ){
putchar(symbol); // 符号前缀告诉什么类型的数据来处理
printf("%d\r\n",dat); // 数据以回车的形式发送
}
void UART_init(void)
{
PCON &= 0x7f; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
BRT = 0xFD; //独立波特率产生器初值
AUXR |= 0x04; //时钟设置为1T模式
AUXR |= 0x01; //选择独立波特率产生器
AUXR |= 0x10; //启动波特率产生
}
char putchar(unsigned char dat)
{
TI=0;
SBUF=dat;
while(!TI);
TI=0;
return SBUF;
}
void T0_init(void){
// 初始化Timer0为每个2mS引发中断
TMOD |= 0x01;
TL0=T0MS;
TH0=T0MS>>8;
TR0=1;
ET0=1;
EA=1;
}
void ADC_init(unsigned char channel)
{
P1ASF=ADC_MASK<<channel; //启用PlusePin作为模数转换器输入
ADC_RES=0; //清除前期ADC结果
ADC_RESL=0; //清除前期ADC结果
AUXR1 |= 0x04; //调整ADC结果格式
ADC_CONTR=channel|ADC_POWER|ADC_SPEEDLL|ADC_START; //打开ADC电源并开始转换
}
unsigned int analogRead(unsigned char channel)
{
unsigned int result;
ADC_CONTR &=!ADC_FLAG; //清除ADC标志
result=ADC_RES;
result=result<<8;
result+=ADC_RESL;
ADC_CONTR|=channel|ADC_POWER|ADC_SPEEDLL|ADC_START;
return result;
}
// Timer 0中断子程序,每2MS中断一次,读取AD值,计算心率值
void Timer0_rountine(void) interrupt 1
{
int N;
unsigned char i;
unsigned int runningTotal = 0; // 清除runningTotal变量
EA=0;
TL0=T0MS;
TH0=T0MS>>8;
Signal = analogRead(PulsePin); // 读数据
sampleCounter += 2; // 用这个变量来记录毫秒内的时间
N = sampleCounter - lastBeatTime; // 时间从最后一拍后,以避免噪声监测
// 找出脉冲波的波峰和波谷
if(Signal < thresh && N > (IBI/5)*3){ // 通过等待最后一个IBI的3/5来避免毛细血管噪声
if (Signal < Trough){
Trough = Signal; // 跟踪脉冲波的最低点
}
}
if(Signal > thresh && Signal > Peak){
Peak = Signal;
} // 跟踪脉冲波的最高点
//寻找心跳,每次有脉冲时信号的值都会激增
if (N > 250){ // 避免高频噪音
if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ){
Pulse = true; // 设置脉搏标志
IBI = sampleCounter - lastBeatTime; // 测量每拍之间的时间(毫秒)
lastBeatTime = sampleCounter; // 跟踪下一次脉冲
if(secondBeat){
secondBeat = false; // 清除第二次跳动标记
for(i=0; i<=9; i++){ // 种子运行总数,以获得一个真正的BPM在启动
rate[i] = IBI;
}
}
if(firstBeat){
firstBeat = false; // 清除第一次跳动标记
secondBeat = true; // 设置第二次跳动标记
EA=1;
return;
}
for(i=0; i<=8; i++){ // 在速率数组中移位数据
rate[i] = rate[i+1];
runningTotal += rate[i];
}
rate[9] = IBI; // 将最新的IBI添加到速率数组
runningTotal += rate[9];
runningTotal /= 10; // 取最后10个IBI值的平均值
BPM = 60000/runningTotal;
if(BPM>200)BPM=200; //限制BPM最高显示值
if(BPM<30)BPM=30; //限制BPM最低显示值
DisBuff[2] = BPM%10+48;//取个位数
DisBuff[1] = BPM%100/10+48; //取十位数
DisBuff[0] = BPM/100+48; //百位数
if(DisBuff[0]==48)
DisBuff[0]=32;
QS = true;
// QS FLAG IS NOT CLEARED INSIDE THIS ISR
}
}
if (Signal < thresh && Pulse == true){ // 当值下降时,节拍结束
Pulse = false; // 重置脉冲信号
amp = Peak - Trough; // 获得脉冲波的振幅
thresh = amp/2 + Trough; // 将阈值设置为幅度的50%
Peak = thresh;
Trough = thresh;
}
if (N > 2500){ // 如果2.5秒后没有跳动
thresh = 512;
Peak = 512;
Trough = 512;
lastBeatTime = sampleCounter; // 更新最新的节拍
firstBeat = true; // 设置这些以避免噪音
secondBeat = false; //恢复心跳
}
EA=1;
}
- GPS
#include <reg52.h>
#include <uart.h>
sbit Key = P1^0;
sbit Parse = P1^2;
sbit LED = P0^0;
void delay(unsigned int i);
void errorLog(int num);
void parseGpsBuffer();
void printGpsBuffer();
void main(){
Uart_Init();
delay(1000);
clrStruct();
while (1){
if (!Key){
delay(10000);
if(!Key){
LED = ~LED;
UartPrintf("hello!");
}else{
continue;
}
}
if(!Parse){
delay(10000);
if (!Parse){
LED = ~LED;
parseGpsBuffer();
UartPrintf("\r\n");
UartPrintf("Done!");
UartPrintf("\r\n");
UartPrintf("test: ");
printGpsBuffer();
UartPrintf("\r\n");
}
}
}
}
void delay(unsigned int i){
while(i--);
}
void errorLog(int num){
while (1)
{
UartPrintf("ERROR");
UartPrintASCII(num+0x30);
UartPrintf("\r\n");
}
}
//TODO: Need some transform
void parseGpsBuffer(){
char *subString;
char *subStringNext;
char i = 0;
if (Save_Data.isGetData)
{
Save_Data.isGetData = false;
UartPrintf("**************\r\n");
UartPrintf(Save_Data.GPS_Buffer);
for (i = 0 ; i <= 6 ; i++)
{
if (i == 0)
{
if ((subString = strstr(Save_Data.GPS_Buffer, ",")) == NULL)
errorLog(1); //解析错误
}
else
{
subString++;
if ((subStringNext = strstr(subString, ",")) != NULL)
{
char usefullBuffer[2];
switch(i)
{
case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break; //获取UTC时间
case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break; //获取UTC时间
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;
Save_Data.isParseData = true;
if(usefullBuffer[0] == 'A')
Save_Data.isUsefull = true;
else if(usefullBuffer[0] == 'V')
Save_Data.isUsefull = false;
}
else
{
errorLog(2); //解析错误
}
}
}
}
}
void printGpsBuffer()
{
if (Save_Data.isParseData)
{
Save_Data.isParseData = false;
UartPrintf("Save_Data.UTCTime = ");
UartPrintf(Save_Data.UTCTime);
UartPrintf("\r\n");
if(Save_Data.isUsefull)
{
Save_Data.isUsefull = false;
UartPrintf("Save_Data.latitude = ");
UartPrintf(Save_Data.latitude);
UartPrintf("\r\n");
UartPrintf("Save_Data.N_S = ");
UartPrintf(Save_Data.N_S);
UartPrintf("\r\n");
UartPrintf("Save_Data.longitude = ");
UartPrintf(Save_Data.longitude);
UartPrintf("\r\n");
UartPrintf("Save_Data.E_W = ");
UartPrintf(Save_Data.E_W);
UartPrintf("\r\n");
}
else
{
UartPrintf("GPS DATA is not useful!\r\n");
}
}
}