1403 lines
44 KiB
C
1403 lines
44 KiB
C
|
#include "main.h"
|
|||
|
#include <math.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include "key.h"
|
|||
|
#include "cJSON.h"
|
|||
|
// #include "nnom.h" //神经网络的函数调用,不需要改动
|
|||
|
#include "cal_sleep_stage.h" //计算睡眠周期
|
|||
|
#include "myMalloc.h"
|
|||
|
// #include "image.h"
|
|||
|
// #include "ppg_data.h" //测试用到的数据集,这个文件是用py文件生成的,不需要改,已更新
|
|||
|
// 保存了网络结构的参数,这个文件是用py文件生成的,不需要改
|
|||
|
// #include "breath_heart.h" //预测呼吸心跳的模型
|
|||
|
// #include "pre_stage.h" //预测睡眠阶段的模型
|
|||
|
#include "stmflash.h"
|
|||
|
#include <stdlib.h>
|
|||
|
#include "wificom.h"
|
|||
|
#include <stdio.h>
|
|||
|
#include <time.h>
|
|||
|
#include "find_peaks.h"
|
|||
|
#include "queue_mem.h" //分配内存的函数
|
|||
|
#include "sleepReport.h"
|
|||
|
#include "drv_SGM58031.h"
|
|||
|
// DSP 相关
|
|||
|
#include "MyTool.h"
|
|||
|
#include "arm_math.h"
|
|||
|
#include "MyAlgorithm.h"
|
|||
|
#include "MyBandFitter.h"
|
|||
|
|
|||
|
#if THE_VERSION
|
|||
|
unsigned char version[8] = {0xA5, 0x5A, 0x08, 0x00, 0xBB, 0x01, 0x00, 0x1a}; // 版本号E.1.0.26 -> 养老版本
|
|||
|
#else
|
|||
|
unsigned char version[8] = {0xA5, 0x5A, 0x08, 0x00, 0xBB, 0x01, 0x01, 0x05}; // 版本号M.1.1.5 -> BCS版本
|
|||
|
#endif
|
|||
|
|
|||
|
/**********************
|
|||
|
* 魔术棒选用IROM
|
|||
|
* IROM1:0x8010000--0x40000(初始程序,用来放置old版本)
|
|||
|
* IROM2:0x8080000--0x40000(升级程序,需要选用这个编译的bin文件给服务器)
|
|||
|
***********************/
|
|||
|
// 设置一个模型运行的内存空间,40Kb,
|
|||
|
// 后续会在main函数中对它初始化。
|
|||
|
// 如果定义了NNOM_USING_STATIC_MEMORY,就是使用静态内存,
|
|||
|
// 如果没有定义,修改NNOM_USING_STATIC_MEMORY的方法在nnom_port.h中,
|
|||
|
// 这部分不需要改动,使用静态内存比较稳定,而且空间也小。
|
|||
|
|
|||
|
/**********************
|
|||
|
report_get_buf
|
|||
|
* 0~99数据存入
|
|||
|
* 0~9:总天数+当前天数
|
|||
|
* 10~29:当前天数+当前多少个数据+时间戳+效率,以后同理
|
|||
|
* 200~200+1024*9 第一天数据
|
|||
|
* 200+1024*9~200+1024*(9*2) 第二天数据
|
|||
|
***********************/
|
|||
|
/**********************
|
|||
|
* report_abnormal_buf
|
|||
|
* 0~7:时间数据存入
|
|||
|
* 8~9:长度
|
|||
|
* 10~11:起始时间,以后同理
|
|||
|
* 12~13:结束时间,以后同理
|
|||
|
***********************/
|
|||
|
struct Sleep_report
|
|||
|
{
|
|||
|
// uint8_t report_save_buf[1200]; //存储buf
|
|||
|
// uint8_t report_send_buf[1200]; //读取buf
|
|||
|
uint8_t report_get_buf[200]; // 前期介绍
|
|||
|
// uint8_t report_abnormal_buf[2000]; //异常存储
|
|||
|
uint8_t time_num[8]; // 时间buf
|
|||
|
int report_save_len; // 存储长度
|
|||
|
int report_send_len; // 读取长度
|
|||
|
char breathe_abnormal_flg; // 呼吸异常标志
|
|||
|
uint16_t breathe_abnormal_length; // 呼吸异常长度
|
|||
|
uint16_t breathe_abnormal_time; // 呼吸异常长度
|
|||
|
char all_num; // 总天数1~7
|
|||
|
char report_num; // 当前天数1~7
|
|||
|
char circle_num; // 当前循环条数
|
|||
|
char report_time_flg; // 更新时间标志位
|
|||
|
uint32_t storage_location_num; // 当前存储数量--地址等于
|
|||
|
uint8_t storage_location_buf[4]; // 存储数量转换buf
|
|||
|
int equipment_status_time; // 判断离床时间
|
|||
|
char sleep_stage_flg; // 出睡眠报告的标志位
|
|||
|
} Sleep;
|
|||
|
|
|||
|
uint32_t FlashPtr = 0X08004000; // 呼吸心率上下限存储地址
|
|||
|
int currentSize_num = 0; // 进行睡眠计算时间
|
|||
|
char OffBed_Flag = 0;
|
|||
|
uint16_t number0 = 0;
|
|||
|
int BH_time = 0;
|
|||
|
int stage_time = 0;
|
|||
|
char start_calculate_flg = 0;
|
|||
|
char start_stage_flg = 0;
|
|||
|
char led_flg = 0;
|
|||
|
char uart_flg = 0;
|
|||
|
int uart_time = 0;
|
|||
|
int led_num = 0;
|
|||
|
char stage_len = 0;
|
|||
|
float ppg_data2_buf[2] = {0};
|
|||
|
float Local_ON_BED_Threshold = 0.0f;
|
|||
|
float Local_OFF_BED_Threshold = 0.0f;
|
|||
|
char ppg_stage_index = 0;
|
|||
|
int led_time = 200;
|
|||
|
char OffBed_Time = 0;
|
|||
|
char queue_flg = 0;
|
|||
|
char FFT_Count_State_Flag = 0;
|
|||
|
char FFT_Calculate_State_Flag = 0;
|
|||
|
char start_ConnectNet_flg = 0;
|
|||
|
char Breathe_H = 0x19;
|
|||
|
char Breathe_L = 0x08;
|
|||
|
char HeartRate_H = 0x64;
|
|||
|
char HeartRate_L = 0x37;
|
|||
|
float Diff = 0.0f;
|
|||
|
float Diff_Detail = 0.0f;
|
|||
|
|
|||
|
extern uint8_t BreathRate;
|
|||
|
extern uint8_t HeartBeatRate;
|
|||
|
extern uint8_t BreathRate_Record;
|
|||
|
extern uint8_t HeartBeatRate_Record;
|
|||
|
|
|||
|
extern int FitterCount_Heart;
|
|||
|
extern int FitterCount_Breath;
|
|||
|
extern int FitterCount_CheckBed;
|
|||
|
extern char FitterCollectDoneFlag_Heart;
|
|||
|
extern char FitterCollectDoneFlag_Breath;
|
|||
|
extern char FitterCollectDoneFlag_CheckBed;
|
|||
|
|
|||
|
extern char WarnConfigDoneFlag;
|
|||
|
extern warning_config_t warning_config;
|
|||
|
|
|||
|
WarningMsg_t WarningMsg; // 告警消息
|
|||
|
uint8_t g_mon, g_day, g_hour, g_min, g_sec = 0;
|
|||
|
|
|||
|
uint16_t Roll_Over_Count = 0; // 翻身计数
|
|||
|
uint16_t Sleep_Report_Start_Flag = 0; // 睡眠报告开始
|
|||
|
uint16_t TimeClock_Recalibrate_Count = 0; // 重新校准时间避免时间戳错误
|
|||
|
// 睡眠报告的存储--15天
|
|||
|
typedef struct SleepRecord_T
|
|||
|
{
|
|||
|
char SleepReport_Directory[REPORT_SAVE_SIZE]; // 存储字典
|
|||
|
char SleepReport_CurrentSaveNum; // 当前值
|
|||
|
char SleepReport_CurrentIndex; // 当前角标
|
|||
|
uint8_t SleepReport_TimeStamp[8]; // 时间戳
|
|||
|
uint8_t SleepReport_Score; // 得分
|
|||
|
uint8_t SleepReport_Efficiency; // 效率
|
|||
|
} SleepRecord_t;
|
|||
|
|
|||
|
SleepRecord_t SleepRecord;
|
|||
|
uint32_t Calibration_Template = 0;
|
|||
|
uint32_t Calibration_Template_2 = 0;
|
|||
|
|
|||
|
float Optical_Calibration_Value = 0.0f;
|
|||
|
float Optical_Calibration_Value_OffBed = 0.0f;
|
|||
|
float Optical_Calibration_Value_OnBed = 0.0f;
|
|||
|
|
|||
|
char Calibration_Off_Bed_Done_Flag = 0;
|
|||
|
char Calibration_In_Bed_Done_Flag = 0;
|
|||
|
|
|||
|
char PowerOn_NetStatusFlg = 0; // 上电状态标志位
|
|||
|
char PowerOn_OneMinuteCount = 0; // 上电一分钟计次
|
|||
|
char PowerOn_OneMinuteCount_Start = 0; // 上电一分钟启动标志
|
|||
|
char PowerOn_StartConfigFlg = 0; // 上电配网启动标志位
|
|||
|
|
|||
|
struct struct_stage get_sleep_stage;
|
|||
|
int score_eff_buff[2] = {0};
|
|||
|
float ppg_data_500_buf[500] = {0}; // 500发送数据集
|
|||
|
unsigned short int ppg_stage_buf[10] = {0}; // stage 的数据,是一秒钟10个
|
|||
|
unsigned short int BH_data_500[500] = {0};
|
|||
|
// unsigned short int sdst[3000] = {0}; // 接收呼吸心跳中间值
|
|||
|
|
|||
|
signed long int max_min2[2] = {-500, 50000}; // 数据集中的最大值和最小值
|
|||
|
|
|||
|
unsigned short int c_BH_max = 0;
|
|||
|
unsigned short int c_BH_index = 0;
|
|||
|
unsigned short int c_BH_num = 0;
|
|||
|
// unsigned char que_static_buf[1024 * 18] = {0}; // 18*300=
|
|||
|
|
|||
|
#ifdef NNOM_USING_STATIC_MEMORY
|
|||
|
// uint8_t BH_static_buf[1024 * 41] = {0}; // 呼吸心跳 模型 内存
|
|||
|
|
|||
|
#ifndef NOT_PRE_STAGE
|
|||
|
uint8_t Stage_static_buf[1024 * 28] = {0}; // 失眠分期 模型内存
|
|||
|
#endif
|
|||
|
|
|||
|
#endif
|
|||
|
char wifi_json_flg = 0;
|
|||
|
// char info[512] = {0};
|
|||
|
// uint8_t s[256] = {0};
|
|||
|
|
|||
|
char MovementBuffer[REPORT_BUFFER_MAX]; // 12小时的体动数据 __attribute__((at(0x080E0000)))
|
|||
|
char HeartRateBuffer[REPORT_BUFFER_MAX]; // 12小时的心率数据__attribute__((at(0x080E0000 + (0x400))))
|
|||
|
char BreathRateBuffer[REPORT_BUFFER_MAX]; // 12小时的呼吸数据__attribute__((at(0x080E0000 + (0x400))))
|
|||
|
char sleepStatusBuffer[REPORT_BUFFER_MAX]; // 12小时的睡眠阶段数据__attribute__((at(0x080E0000 + (0x800))))
|
|||
|
char sleepTempBuffer[REPORT_BUFFER_MAX + 20] = {0}; // 12小时的缓存数据(包括上报)
|
|||
|
|
|||
|
extern warning_config_t warning_config;
|
|||
|
#define FLASH_SAVE_ADDR 0X080C0000 // 代码用了126K,地址需要大于它
|
|||
|
// void c_BH_stage(nnom_model_t *BH_model, nnom_model_t *stage_model);
|
|||
|
// void pre_bh(nnom_model_t *BH_model);
|
|||
|
int MyDSP_Init(void);
|
|||
|
void MyFitter(void);
|
|||
|
|
|||
|
/**
|
|||
|
* @function: IWDG_Init
|
|||
|
* @brief: None
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
void IWDG_Init(void)
|
|||
|
{
|
|||
|
// 1、 取消寄存器写保护:
|
|||
|
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
|
|||
|
// 2、设置独立看门狗的预分频系数,确定时钟:125HZ
|
|||
|
IWDG_SetPrescaler(IWDG_Prescaler_256);
|
|||
|
// 3、设置看门狗重装载值,确定溢出时间:32s
|
|||
|
IWDG_SetReload(4000);
|
|||
|
// 4、重新载入计数器
|
|||
|
IWDG_ReloadCounter();
|
|||
|
// 5、使能
|
|||
|
IWDG_Enable(); // 使能看门狗 打开看门狗好像会导致光功率值跳动?
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: IWDG_Feed
|
|||
|
* @brief: 喂狗
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
void IWDG_Feed(void)
|
|||
|
{
|
|||
|
// 把重装载寄存器的值放到计数器中,喂狗,防止IWDG复位
|
|||
|
// 当计数器的值减到0的时候会产生系统复位
|
|||
|
IWDG_ReloadCounter();
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: SleepReportSend
|
|||
|
* @brief: None
|
|||
|
* @param {unsigned char} *buf
|
|||
|
* @param {int} size
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
char LastSleepReportPacket_Flag = 0;
|
|||
|
char SleepReportSend(unsigned char *buf, int size, int circle_num)
|
|||
|
{
|
|||
|
int PacketLength = 17;
|
|||
|
char Header[2] = {0xA5, 0x5A};
|
|||
|
char FrameLength[2] = {0};
|
|||
|
char FrameType[1] = {0x02};
|
|||
|
char TimeStamp[8] = {0};
|
|||
|
char TestScoreBuffer[2] = {0x27, 0x40};
|
|||
|
char TestPackets[2] = {0x01, 0x01};
|
|||
|
char TestPacketBuffer[17] = {0};
|
|||
|
char TestDataSend[321] = {0}; // 最大 1H 的数据
|
|||
|
uint16_t Length = size + 17;
|
|||
|
|
|||
|
FrameLength[1] = Length >> 8;
|
|||
|
FrameLength[0] = Length & 0xff;
|
|||
|
memcpy(TimeStamp, Sleep.time_num, sizeof(TimeStamp));
|
|||
|
|
|||
|
// 将帧头赋值
|
|||
|
strcat(TestPacketBuffer, Header);
|
|||
|
// 长度
|
|||
|
TestPacketBuffer[2] = FrameLength[0];
|
|||
|
TestPacketBuffer[3] = FrameLength[1];
|
|||
|
// 将帧类型赋值
|
|||
|
TestPacketBuffer[4] = FrameType[0];
|
|||
|
// 将时间赋值
|
|||
|
TestPacketBuffer[5] = TimeStamp[0];
|
|||
|
TestPacketBuffer[6] = TimeStamp[1];
|
|||
|
TestPacketBuffer[7] = TimeStamp[2];
|
|||
|
TestPacketBuffer[8] = TimeStamp[3];
|
|||
|
TestPacketBuffer[9] = TimeStamp[4];
|
|||
|
TestPacketBuffer[10] = TimeStamp[5];
|
|||
|
TestPacketBuffer[11] = TimeStamp[6];
|
|||
|
TestPacketBuffer[12] = TimeStamp[7];
|
|||
|
// 得分 + 效率
|
|||
|
TestPacketBuffer[13] = get_sleep_stage.score; // 将得分和效率传递给数组;
|
|||
|
TestPacketBuffer[14] = get_sleep_stage.eff;
|
|||
|
// 数据包数
|
|||
|
TestPacketBuffer[16] = circle_num + 1;
|
|||
|
if (LastSleepReportPacket_Flag == 1)
|
|||
|
TestPacketBuffer[15] = circle_num + 1;
|
|||
|
else
|
|||
|
TestPacketBuffer[15] = 24;
|
|||
|
// 数据拷贝
|
|||
|
memcpy(TestDataSend, TestPacketBuffer, sizeof(TestPacketBuffer));
|
|||
|
// memcpy(TestDataSend + 17, buf, size);
|
|||
|
memcpy(TestDataSend + 17, buf + (REPORT_SEND_COUNTS * circle_num), size);
|
|||
|
// WIFI 发送的Buffer
|
|||
|
wifi_crc_send((uint8_t *)TestDataSend, PacketLength + size);
|
|||
|
// 清空buffer
|
|||
|
memset(TestDataSend, 0, sizeof(TestDataSend));
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: BaseParmReport
|
|||
|
* @brief 参数发送
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
// TODO: 增加夜间翻身次数的统计以及上报
|
|||
|
void BaseParmReport(void)
|
|||
|
{
|
|||
|
int PacketLength = 32 - 4;
|
|||
|
char Header[2] = {0xA5, 0x5A};
|
|||
|
char FrameLength[2] = {0};
|
|||
|
char FrameType[1] = {0x04};
|
|||
|
char TimeStamp[8] = {0};
|
|||
|
char ParmSendBuffer[32] = {0};
|
|||
|
|
|||
|
FrameLength[1] = PacketLength >> 8;
|
|||
|
FrameLength[0] = PacketLength & 0xff;
|
|||
|
memcpy(TimeStamp, &timeClockCount, sizeof(timeClockCount));
|
|||
|
// 将帧头赋值
|
|||
|
strcat(ParmSendBuffer, Header);
|
|||
|
// 长度
|
|||
|
ParmSendBuffer[2] = FrameLength[0];
|
|||
|
ParmSendBuffer[3] = FrameLength[1];
|
|||
|
// 将帧类型赋值
|
|||
|
ParmSendBuffer[4] = FrameType[0];
|
|||
|
// 将时间赋值
|
|||
|
ParmSendBuffer[5] = TimeStamp[0];
|
|||
|
ParmSendBuffer[6] = TimeStamp[1];
|
|||
|
ParmSendBuffer[7] = TimeStamp[2];
|
|||
|
ParmSendBuffer[8] = TimeStamp[3];
|
|||
|
ParmSendBuffer[9] = TimeStamp[4];
|
|||
|
ParmSendBuffer[10] = TimeStamp[5];
|
|||
|
ParmSendBuffer[11] = TimeStamp[6];
|
|||
|
ParmSendBuffer[12] = TimeStamp[7];
|
|||
|
// 将参数正常赋值
|
|||
|
ParmSendBuffer[13] = Roll_Over_Count; // 翻身次数计数
|
|||
|
// WIFI 发送的Buffer
|
|||
|
if (OffBed_Flag == 4) // 在床才会发送数据
|
|||
|
#if SLEEP_DEBUG_MODE
|
|||
|
;
|
|||
|
#else
|
|||
|
|
|||
|
// 每天早上8:30 报一次夜间的翻身次数
|
|||
|
// if ((g_hour == 8 && g_min == 30 && g_sec == 0) && Roll_Over_Count != 0)
|
|||
|
// {
|
|||
|
// wifi_crc_send((uint8_t *)ParmSendBuffer, 28);
|
|||
|
// Roll_Over_Count = 0; // 翻身次数清除
|
|||
|
// }
|
|||
|
#endif
|
|||
|
// 清空buffer
|
|||
|
memset(ParmSendBuffer, 0, sizeof(ParmSendBuffer));
|
|||
|
}
|
|||
|
|
|||
|
#define NumberToWrite 1200
|
|||
|
/**
|
|||
|
* @function:SleepReportSave
|
|||
|
* @brief 睡眠报告存储
|
|||
|
* @param {unsigned char} *buf:原始数据
|
|||
|
* @param {char} SaveIndex:保存的起始地址,计算偏移
|
|||
|
* @param {unsigned char} *TimeStamp_buf :时间戳
|
|||
|
* @param {char} Score:得分
|
|||
|
* @param {char} Efficiency:效率
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
char SleepReportSave(unsigned char *buf, char SaveIndex, unsigned char *TimeStamp_buf, char Score, char Efficiency)
|
|||
|
{
|
|||
|
uint8_t Result = 0;
|
|||
|
uint8_t Error_cnt = 0;
|
|||
|
uint32_t Report_Offset = 0;
|
|||
|
Report_Offset += (0x4000 * SaveIndex);
|
|||
|
// 由于buffer大小为7200同时扇区最大为4KB,需要存储两次,存满两个扇区
|
|||
|
// 第一个扇区存储时间戳以及一些其他东西
|
|||
|
unsigned char TimeStamp[8] = {0}; // 时间戳
|
|||
|
unsigned char Sleep_Score_Eff[2] = {0}; // 睡眠得分和效率
|
|||
|
// 用于比较
|
|||
|
unsigned char cmp_Buffer[8] = {0}; // 时间戳
|
|||
|
unsigned char cmp_Score_Eff_Buffer[2] = {0}; // 睡眠得分和效率
|
|||
|
|
|||
|
// 第二个扇区存储第一块的数据,第三个存储后面的
|
|||
|
unsigned char temp_Buffer[NumberToWrite] = {0}; // 原始数据的缓存
|
|||
|
// unsigned char SleepReport_Length[4] = {0}; // 睡眠报告数据长度
|
|||
|
|
|||
|
// 复制时间戳以及得分和效率
|
|||
|
Sleep_Score_Eff[0] = (unsigned char)Score;
|
|||
|
Sleep_Score_Eff[1] = (unsigned char)Efficiency;
|
|||
|
memcpy(TimeStamp, TimeStamp_buf, sizeof(TimeStamp));
|
|||
|
|
|||
|
// 先擦除INFO位置的扇区
|
|||
|
EN25QXX_Erase_Sector(FLASH_SLEEP_REPORT_INFO_ADDRESS + Report_Offset);
|
|||
|
// // NOTE: 存储时间戳
|
|||
|
do
|
|||
|
{
|
|||
|
EN25QXX_Write(TimeStamp, (FLASH_SLEEP_REPORT_TIMESTAMP_ADDRESS + Report_Offset), sizeof(TimeStamp));
|
|||
|
memset(cmp_Buffer, 0, sizeof(cmp_Buffer));
|
|||
|
EN25QXX_Read(cmp_Buffer, (FLASH_SLEEP_REPORT_TIMESTAMP_ADDRESS + Report_Offset), sizeof(cmp_Buffer));
|
|||
|
Result = memcmp(TimeStamp, cmp_Buffer, sizeof(TimeStamp));
|
|||
|
} while (Result != 0);
|
|||
|
memset(TimeStamp, 0, sizeof(TimeStamp));
|
|||
|
memset(cmp_Buffer, 0, sizeof(cmp_Buffer));
|
|||
|
// NOTE: 存储得分&&效率
|
|||
|
do
|
|||
|
{
|
|||
|
EN25QXX_Write(Sleep_Score_Eff, (FLASH_SLEEP_REPORT_SCORE_EFFICIENCY_ADDRESS + Report_Offset), sizeof(Sleep_Score_Eff));
|
|||
|
memset(cmp_Score_Eff_Buffer, 0, sizeof(cmp_Score_Eff_Buffer));
|
|||
|
EN25QXX_Read(cmp_Score_Eff_Buffer, (FLASH_SLEEP_REPORT_SCORE_EFFICIENCY_ADDRESS + Report_Offset), sizeof(cmp_Score_Eff_Buffer));
|
|||
|
Result = memcmp(Sleep_Score_Eff, cmp_Score_Eff_Buffer, sizeof(Sleep_Score_Eff));
|
|||
|
} while (Result != 0);
|
|||
|
memset(Sleep_Score_Eff, 0, sizeof(Sleep_Score_Eff));
|
|||
|
memset(cmp_Score_Eff_Buffer, 0, sizeof(cmp_Score_Eff_Buffer));
|
|||
|
|
|||
|
// 再擦除数据块1 的扇区
|
|||
|
EN25QXX_Erase_Sector(FLASH_SLEEP_REPORT_DATA_1_ADDRESS + Report_Offset);
|
|||
|
// 每一块扇区存3600字节
|
|||
|
for (int i = 0; i < 3; i++)
|
|||
|
{
|
|||
|
// 拷贝数据
|
|||
|
memcpy(temp_Buffer, buf + (NumberToWrite * i), NumberToWrite);
|
|||
|
// 写块1的数据
|
|||
|
EN25QXX_Write(temp_Buffer, (FLASH_SLEEP_REPORT_DATA_1_ADDRESS + Report_Offset + (NumberToWrite * i)), NumberToWrite);
|
|||
|
// 清除数据
|
|||
|
memset(temp_Buffer, 0, NumberToWrite);
|
|||
|
// 读取做校验
|
|||
|
EN25QXX_Read(temp_Buffer, (FLASH_SLEEP_REPORT_DATA_1_ADDRESS + Report_Offset + (NumberToWrite * i)), NumberToWrite);
|
|||
|
// 比较
|
|||
|
Result = memcmp(temp_Buffer, buf + (NumberToWrite * i), NumberToWrite);
|
|||
|
if (Result != 0)
|
|||
|
{
|
|||
|
i--;
|
|||
|
Error_cnt++;
|
|||
|
}
|
|||
|
if (Error_cnt >= 10)
|
|||
|
{
|
|||
|
Error_cnt = 0;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
// 清除数据
|
|||
|
memset(temp_Buffer, 0, NumberToWrite);
|
|||
|
// 再擦除数据块2 的扇区
|
|||
|
EN25QXX_Erase_Sector(FLASH_SLEEP_REPORT_DATA_2_ADDRESS + Report_Offset);
|
|||
|
// 每一块扇区存3600字节
|
|||
|
for (int i = 0; i < 3; i++)
|
|||
|
{
|
|||
|
// 拷贝数据
|
|||
|
memcpy(temp_Buffer, buf + (3 * NumberToWrite) + (NumberToWrite * i), NumberToWrite);
|
|||
|
// 写块2的数据
|
|||
|
EN25QXX_Write(temp_Buffer, (FLASH_SLEEP_REPORT_DATA_2_ADDRESS + Report_Offset + (NumberToWrite * i)), NumberToWrite);
|
|||
|
// 清除数据
|
|||
|
memset(temp_Buffer, 0, NumberToWrite);
|
|||
|
// 读取做校验
|
|||
|
EN25QXX_Read(temp_Buffer, (FLASH_SLEEP_REPORT_DATA_2_ADDRESS + Report_Offset + (NumberToWrite * i)), NumberToWrite);
|
|||
|
// 比较
|
|||
|
Result = memcmp(temp_Buffer, buf + (3 * NumberToWrite) + (NumberToWrite * i), NumberToWrite);
|
|||
|
if (Result != 0)
|
|||
|
{
|
|||
|
i--;
|
|||
|
Error_cnt++;
|
|||
|
}
|
|||
|
if (Error_cnt >= 10)
|
|||
|
break;
|
|||
|
}
|
|||
|
// 清除数据
|
|||
|
memset(temp_Buffer, 0, sizeof(temp_Buffer));
|
|||
|
// 再擦除保留数据块的扇区
|
|||
|
EN25QXX_Erase_Sector(FLASH_SLEEP_REPORT_RETAIN_ADDRESS + Report_Offset);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: SleepReportGet
|
|||
|
* @brief 获取睡眠报告
|
|||
|
* @param {unsigned char} *buf
|
|||
|
* @param {char} Index
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
char SleepReportGet(unsigned char *buf, char Index)
|
|||
|
{
|
|||
|
uint8_t Result = 0;
|
|||
|
uint8_t Error_cnt = 0;
|
|||
|
char FlashDataBuffer[7200] = {0};
|
|||
|
unsigned char temp_Buffer[NumberToWrite] = {0}; // 原始数据的缓存
|
|||
|
uint32_t Report_Offset = 0;
|
|||
|
Report_Offset += (0x4000 * Index);
|
|||
|
// 每一块扇区存3600字节
|
|||
|
for (int i = 0; i < 3; i++)
|
|||
|
{
|
|||
|
// 清除数据
|
|||
|
memset(temp_Buffer, 0, NumberToWrite);
|
|||
|
// 读取块1的数据
|
|||
|
EN25QXX_Read(temp_Buffer, (FLASH_SLEEP_REPORT_DATA_1_ADDRESS + Report_Offset + (NumberToWrite * i)), NumberToWrite);
|
|||
|
// 复制数据
|
|||
|
memcpy(FlashDataBuffer + (NumberToWrite * i), temp_Buffer, NumberToWrite);
|
|||
|
}
|
|||
|
// 每一块扇区存3600字节
|
|||
|
for (int i = 0; i < 3; i++)
|
|||
|
{
|
|||
|
// 清除数据
|
|||
|
memset(temp_Buffer, 0, NumberToWrite);
|
|||
|
// 读取块2的数据
|
|||
|
EN25QXX_Read(temp_Buffer, (FLASH_SLEEP_REPORT_DATA_2_ADDRESS + Report_Offset + (NumberToWrite * i)), NumberToWrite);
|
|||
|
// 复制数据
|
|||
|
memcpy(FlashDataBuffer + (NumberToWrite * i) + (3 * NumberToWrite), temp_Buffer, NumberToWrite);
|
|||
|
}
|
|||
|
memcpy(buf, FlashDataBuffer, sizeof(FlashDataBuffer));
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: get_flash_init
|
|||
|
* @brief: 获取Flash
|
|||
|
* @return {*}
|
|||
|
* @author: wt
|
|||
|
*/
|
|||
|
void get_flash_init(void)
|
|||
|
{
|
|||
|
Sleep.breathe_abnormal_flg = 0;
|
|||
|
EN25QXX_Read((u8 *)Sleep.report_get_buf, 0, 200); // 前200个数据等于整体介绍
|
|||
|
|
|||
|
Sleep.all_num = Sleep.report_get_buf[0]; // 总天数
|
|||
|
Sleep.report_num = Sleep.report_get_buf[1]; // 当前天数
|
|||
|
|
|||
|
// Sleep.report_get_buf[0] = 0; //总天数
|
|||
|
// Sleep.report_get_buf[1] = 0; //当前天数
|
|||
|
// EN25QXX_Write((u8 *)Sleep.report_get_buf, 0, 200); //存储
|
|||
|
|
|||
|
if (Sleep.all_num == 0) // 还没有数据
|
|||
|
{
|
|||
|
Sleep.report_num = 1;
|
|||
|
Sleep.all_num = 1;
|
|||
|
}
|
|||
|
else if ((Sleep.all_num >= 7) && (Sleep.report_num >= 7)) // 已经满了
|
|||
|
{
|
|||
|
Sleep.report_num = 1;
|
|||
|
}
|
|||
|
else if (Sleep.all_num >= 7) // 已经一轮了
|
|||
|
{
|
|||
|
Sleep.report_num++;
|
|||
|
}
|
|||
|
else // 不到一轮
|
|||
|
{
|
|||
|
Sleep.all_num++;
|
|||
|
Sleep.report_num++;
|
|||
|
}
|
|||
|
Sleep.storage_location_num = 200 + 1024 * (9 * (Sleep.report_num - 1)); // 当前存储数量--地址等于
|
|||
|
|
|||
|
Sleep.report_time_flg = 1; // 更新时间戳
|
|||
|
OffBed_Flag = 0; // 离床
|
|||
|
Sleep.equipment_status_time = 0; // 初始离床时间0
|
|||
|
Sleep.sleep_stage_flg = 0; // 不出睡眠报告
|
|||
|
Sleep.circle_num = 0; // 当前循环为0
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: SleepRecord_SaveDirectory
|
|||
|
* @brief: 保存目录
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
void SleepRecord_SaveDirectory(char *buffer)
|
|||
|
{
|
|||
|
// 判断是否是空的
|
|||
|
int Counter = 0;
|
|||
|
char index = 0;
|
|||
|
char Value = 0;
|
|||
|
for (Counter = 0; Counter < REPORT_SAVE_SIZE; Counter++)
|
|||
|
{
|
|||
|
if (buffer[Counter] != DEFAULT_FF)
|
|||
|
break;
|
|||
|
}
|
|||
|
// 第一次做记录
|
|||
|
if (Counter == REPORT_SAVE_SIZE)
|
|||
|
{
|
|||
|
buffer[0] = 0;
|
|||
|
index++;
|
|||
|
Value++;
|
|||
|
SleepRecord.SleepReport_CurrentIndex = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// 先遍历一次
|
|||
|
for (Counter = 0; Counter < REPORT_SAVE_SIZE; Counter++)
|
|||
|
{
|
|||
|
// 找到了空余区域
|
|||
|
if (buffer[Counter] == DEFAULT_FF)
|
|||
|
{
|
|||
|
SleepRecord.SleepReport_CurrentIndex = Counter;
|
|||
|
buffer[Counter] = Counter;
|
|||
|
index = Counter + 1;
|
|||
|
Value++;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (Counter == REPORT_SAVE_SIZE)
|
|||
|
{
|
|||
|
// 已经存储完成,需要顶替
|
|||
|
for (Counter = 0; Counter < REPORT_SAVE_SIZE; Counter++)
|
|||
|
{
|
|||
|
if (buffer[Counter] != 0)
|
|||
|
{
|
|||
|
buffer[Counter] -= 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SleepRecord.SleepReport_CurrentIndex = Counter;
|
|||
|
buffer[Counter] = REPORT_SAVE_SIZE - 1;
|
|||
|
index = Counter;
|
|||
|
Value = buffer[Counter];
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
SleepRecord.SleepReport_CurrentSaveNum = Value;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function:cjson_ReInitHook
|
|||
|
* @brief 重新初始化钩子函数(采用自己的内存分配)
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
void cjson_ReInitHook(void)
|
|||
|
{
|
|||
|
static cJSON_Hooks m_iot_hooks;
|
|||
|
m_iot_hooks.malloc_fn = mymalloc;
|
|||
|
m_iot_hooks.free_fn = myfree;
|
|||
|
cJSON_InitHooks(&m_iot_hooks);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: MattressFunctionInit
|
|||
|
* @brief: 体征垫参数初始化
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
char bootResult = 0;
|
|||
|
RCC_ClocksTypeDef get_RCC_Clock;
|
|||
|
void MattressParameterInit(void)
|
|||
|
{
|
|||
|
System_Init();
|
|||
|
// NOTE: 将静态数组的指针传入,以其作为队列的存储
|
|||
|
// node_set_static_buf(que_static_buf, sizeof(que_static_buf));
|
|||
|
// NOTE: 初始化队列,设置个数
|
|||
|
// InitQueue(&Stage_q, 301, 1); // 300秒,5分钟
|
|||
|
// NOTE: 此处用于清空睡眠阶段的结构体
|
|||
|
// init_struct_stage(&get_sleep_stage);
|
|||
|
wait(5); // 等待一段时间避免ESP32的串口数据有影响
|
|||
|
get_flash_init(); // flash初始化
|
|||
|
cjson_ReInitHook();
|
|||
|
if ((*(__IO uint16_t *)0X08004000) != 0x1111) // 没有存储 写入默认值
|
|||
|
{
|
|||
|
FLASH_Unlock();
|
|||
|
FLASH_EraseSector(FLASH_Sector_1, VoltageRange_3);
|
|||
|
flashWrite(get_breathe_buf, 6); // 写入flash,固定一包写6个字节
|
|||
|
FLASH_Lock();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Breathe_H = (*(__IO uint8_t *)0X08004002);
|
|||
|
Breathe_L = (*(__IO uint8_t *)0X08004003);
|
|||
|
HeartRate_H = (*(__IO uint8_t *)0X08004004);
|
|||
|
HeartRate_L = (*(__IO uint8_t *)0X08004005);
|
|||
|
}
|
|||
|
if (EN25QXX_ReadID() != EN25Q64) // 检测不到EN25Q64
|
|||
|
{
|
|||
|
printf("EN25Q64 Check Failed!\r\n");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
printf("EN25Q64 Check right!\r\n");
|
|||
|
}
|
|||
|
// 读取复位原因
|
|||
|
if ((RCC->CSR & 0X80000000) != 0) // 1 低功耗复位
|
|||
|
{
|
|||
|
bootResult = Low_Power_Reset;
|
|||
|
printf("[Reset]: Low Power Reset\r\n");
|
|||
|
}
|
|||
|
else if ((RCC->CSR & 0X40000000) != 0) // 2 窗口看门狗复位
|
|||
|
{
|
|||
|
bootResult = WWDG_Reset;
|
|||
|
printf("[Reset]: WWDG Reset\r\n");
|
|||
|
}
|
|||
|
else if ((RCC->CSR & 0X20000000) != 0) // 3 独立看门狗复位
|
|||
|
{
|
|||
|
bootResult = IWDG_Reset;
|
|||
|
printf("[Reset]: IWDG Reset\r\n");
|
|||
|
}
|
|||
|
else if ((RCC->CSR & 0X10000000) != 0) // 4 软件复位
|
|||
|
{
|
|||
|
bootResult = SoftWare_Reset;
|
|||
|
printf("[Reset]: SoftWare Reset\r\n");
|
|||
|
}
|
|||
|
else if ((RCC->CSR & 0X08000000) != 0) // 5 上电复位
|
|||
|
{
|
|||
|
bootResult = PowerOn_Reset;
|
|||
|
printf("[Reset]: PowerOn Reset\r\n");
|
|||
|
}
|
|||
|
else if ((RCC->CSR & 0X04000000) != 0) // 6 PIN复位
|
|||
|
{
|
|||
|
bootResult = Pin_Reset;
|
|||
|
printf("[Reset]: Pin Reset\r\n");
|
|||
|
}
|
|||
|
RCC->CSR = 0X01000000;
|
|||
|
// 读取时钟
|
|||
|
RCC_GetClocksFreq(&get_RCC_Clock); /**/
|
|||
|
printf("-----------------------------------------------\r\n");
|
|||
|
printf("[System Clock]: HCLK_Frequency %d\r\n", get_RCC_Clock.HCLK_Frequency);
|
|||
|
printf("[System Clock]: PCLK1_Frequency %d\r\n", get_RCC_Clock.PCLK1_Frequency);
|
|||
|
printf("[System Clock]: PCLK2_Frequency %d\r\n", get_RCC_Clock.PCLK2_Frequency);
|
|||
|
printf("[System Clock]: SYSCLK_Frequency %d\r\n", get_RCC_Clock.SYSCLK_Frequency);
|
|||
|
printf("-----------------------------------------------\r\n");
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: Storage_Initialization
|
|||
|
* @brief: 存储初始化
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
extern float OPM_Original;
|
|||
|
void Storage_Initialization(void)
|
|||
|
{
|
|||
|
// DONE::获取光功阈值存储数据,如果没有使用默认值
|
|||
|
EN25QXX_Read((uint8_t *)&OPM_Original, FLASH_IN_OFF_BED_OPM_RECORD_ADDRESS, sizeof(float32_t));
|
|||
|
EN25QXX_Read((u8 *)&Calibration_Template, FLASH_IN_BED_THRESHOLD_ADDRESS, sizeof(Calibration_Template));
|
|||
|
EN25QXX_Read((u8 *)&Calibration_Template_2, FLASH_OFF_BED_THRESHOLD_ADDRESS, sizeof(Calibration_Template_2));
|
|||
|
// 如果读取数据错误则写入默认值
|
|||
|
if (OPM_Original >= WEAK_OPM && OPM_Original <= -10.0f)
|
|||
|
{
|
|||
|
printf("\r\n OPM_Original : %f\r\n", OPM_Original);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
OPM_Original = -10.0f;
|
|||
|
EN25QXX_Write((uint8_t *)&OPM_Original,
|
|||
|
FLASH_IN_OFF_BED_OPM_RECORD_ADDRESS,
|
|||
|
sizeof(float32_t));
|
|||
|
printf("\r\n OPM_Original Empty\r\n");
|
|||
|
}
|
|||
|
// 如果获取的数据不是空数据
|
|||
|
if (Calibration_Template != 0xffffffff &&
|
|||
|
Calibration_Template_2 != 0xffffffff)
|
|||
|
{
|
|||
|
// 增加LED灯的指示,会闪一下浅色LED
|
|||
|
LED_G = 0;
|
|||
|
LED_B = 0;
|
|||
|
delay_ms(500);
|
|||
|
LED_R = 1;
|
|||
|
LED_G = 1;
|
|||
|
LED_B = 1;
|
|||
|
EN25QXX_Read((u8 *)&ON_BED_Threshold, FLASH_IN_BED_THRESHOLD_ADDRESS, sizeof(ON_BED_Threshold));
|
|||
|
EN25QXX_Read((u8 *)&OFF_BED_Threshold, FLASH_OFF_BED_THRESHOLD_ADDRESS, sizeof(OFF_BED_Threshold));
|
|||
|
}
|
|||
|
// TODO: 增加读取睡眠报告的目录参数
|
|||
|
// 睡眠报告的配置结构--清空配置
|
|||
|
SleepRecord.SleepReport_CurrentIndex = 0;
|
|||
|
SleepRecord.SleepReport_CurrentSaveNum = 0;
|
|||
|
// 读取
|
|||
|
EN25QXX_Read((u8 *)&SleepRecord.SleepReport_Directory,
|
|||
|
FLASH_SLEEP_REPORT_DIRECTORY_ADDRESS,
|
|||
|
sizeof(SleepRecord.SleepReport_Directory));
|
|||
|
Key_Cal_Flag = 0; // 此处不能删除,删除会导致上电黑掉的情况
|
|||
|
// 设置随机种子
|
|||
|
MySetRandom(AIN_1310);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: OPM_MattressCalibration
|
|||
|
* @brief: 体征垫的光功校准
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
void OPM_MattressCalibration(void)
|
|||
|
{
|
|||
|
if (opm_cal_flag == 1) // 需要进行校准
|
|||
|
{
|
|||
|
IWDG_Feed(); // // NOTE:喂狗 超时 32s 就复位(防止硬件设备错误以及卡死)
|
|||
|
// 青色LED = G + B
|
|||
|
// 紫色LED = R + B
|
|||
|
float Optical_Sum = 0.0f;
|
|||
|
// 修正值为空,且没有进行空床校准
|
|||
|
if (Optical_Calibration_Value == 0.0f &&
|
|||
|
((Calibration_Off_Bed_Done_Flag == 0) ||
|
|||
|
(Calibration_In_Bed_Done_Flag == 1)))
|
|||
|
{
|
|||
|
for (char i = 0; i < 10; i++)
|
|||
|
{
|
|||
|
LED_G = 0;
|
|||
|
LED_B = 0;
|
|||
|
delay_ms(8000);
|
|||
|
LED_G = 1;
|
|||
|
LED_B = 1;
|
|||
|
delay_ms(8000);
|
|||
|
get_optical_power(); // 获取光功
|
|||
|
Optical_Sum += dbm_value_1310;
|
|||
|
}
|
|||
|
Optical_Calibration_Value = Optical_Sum / 10.0f; // 作均值
|
|||
|
// 记录以及计算阈值
|
|||
|
Optical_Calibration_Value_OffBed = Optical_Calibration_Value;
|
|||
|
// 更新阈值
|
|||
|
OFF_BED_Threshold = Optical_Calibration_Value_OffBed - (float)2.0;
|
|||
|
// 更新阈值
|
|||
|
ON_BED_Threshold = OFF_BED_Threshold - 10;
|
|||
|
// 喂狗 超时 32s 就复位(防止硬件设备错误以及卡死)
|
|||
|
IWDG_Feed(); // NOTE:喂狗
|
|||
|
// 空床也进行保存
|
|||
|
EN25QXX_Write((u8 *)&ON_BED_Threshold, FLASH_IN_BED_THRESHOLD_ADDRESS, sizeof(ON_BED_Threshold));
|
|||
|
EN25QXX_Write((u8 *)&OFF_BED_Threshold, FLASH_OFF_BED_THRESHOLD_ADDRESS, sizeof(OFF_BED_Threshold));
|
|||
|
Key_Cal_Flag = 0;
|
|||
|
opm_cal_flag = 0;
|
|||
|
Local_ON_BED_Threshold = ON_BED_Threshold;
|
|||
|
Local_OFF_BED_Threshold = OFF_BED_Threshold;
|
|||
|
TIM_Cmd(TIM3, ENABLE); // 使能定时器3
|
|||
|
Calibration_In_Bed_Done_Flag = 0;
|
|||
|
Calibration_Off_Bed_Done_Flag = 1;
|
|||
|
}
|
|||
|
else if (Optical_Calibration_Value == 0.0f &&
|
|||
|
Calibration_Off_Bed_Done_Flag == 1)
|
|||
|
{
|
|||
|
for (char i = 0; i < 10; i++)
|
|||
|
{
|
|||
|
LED_R = 0;
|
|||
|
LED_B = 0;
|
|||
|
delay_ms(8000);
|
|||
|
LED_R = 1;
|
|||
|
LED_B = 1;
|
|||
|
delay_ms(8000);
|
|||
|
get_optical_power(); // 获取光功
|
|||
|
Optical_Sum += dbm_value_1310;
|
|||
|
printf("Calibration\r\n");
|
|||
|
}
|
|||
|
Optical_Calibration_Value = Optical_Sum / 10.0f; // 作均值
|
|||
|
// 记录以及计算阈值
|
|||
|
Optical_Calibration_Value_OnBed = Optical_Calibration_Value;
|
|||
|
// 更新阈值
|
|||
|
ON_BED_Threshold = Optical_Calibration_Value_OnBed - 10;
|
|||
|
Key_Cal_Flag = 0;
|
|||
|
opm_cal_flag = 0;
|
|||
|
Local_ON_BED_Threshold = ON_BED_Threshold;
|
|||
|
Local_OFF_BED_Threshold = OFF_BED_Threshold;
|
|||
|
TIM_Cmd(TIM3, ENABLE); // 使能定时器3
|
|||
|
Calibration_In_Bed_Done_Flag = 1;
|
|||
|
// 喂狗 超时 32s 就复位(防止硬件设备错误以及卡死)
|
|||
|
IWDG_Feed(); // NOTE:喂狗
|
|||
|
// TODO: 做记录之后再次进行存储,之后直接复位。
|
|||
|
EN25QXX_Write((u8 *)&ON_BED_Threshold, FLASH_IN_BED_THRESHOLD_ADDRESS, sizeof(ON_BED_Threshold));
|
|||
|
EN25QXX_Write((u8 *)&OFF_BED_Threshold, FLASH_OFF_BED_THRESHOLD_ADDRESS, sizeof(OFF_BED_Threshold));
|
|||
|
CalValue_Upload();
|
|||
|
NVIC_SystemReset(); // 复位
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: KalmarFilter
|
|||
|
* @brief: None
|
|||
|
* @param {float} inData
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
float KalmarFilter(float inData)
|
|||
|
{
|
|||
|
static float prevData = 0; // 上一个数据
|
|||
|
static float p = 10, q = 0.005, r = 0.005, kGain = 0.5; // q 控制误差 r 控制响应速度
|
|||
|
p = p + q;
|
|||
|
kGain = p / (p + r); // 计算卡尔曼增益
|
|||
|
inData = prevData + (kGain * (inData - prevData)); // 计算本次滤波估计值
|
|||
|
p = (1 - kGain) * p; // 更新测量方差
|
|||
|
prevData = inData;
|
|||
|
return inData; // 返回估计值
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: main
|
|||
|
* @brief: 主函数
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
uint16_t Chip_ID_Data = 0;
|
|||
|
uint16_t fft_HeartBeatRate_Hi = 0;
|
|||
|
uint16_t fft_HeartBeatRate_Lo = 0;
|
|||
|
uint16_t fft_HeartBeatRate_Result = 0;
|
|||
|
uint16_t time_HeartBeatRate_Result = 0;
|
|||
|
|
|||
|
float fft_HeartBeatRate_StashBuffer[15] = {0};
|
|||
|
int main(void)
|
|||
|
{
|
|||
|
VectorTableReInit();
|
|||
|
// nnom_model_t *BH_model, *stage_model; // 两个预测模型的指针
|
|||
|
|
|||
|
// 睡眠报告的原始数据 可存储一天的数据 24h*60min*60sec = 7200 ;
|
|||
|
// unsigned char SleepReportSendDataBuffer[7200] = {0};
|
|||
|
// unsigned char SleepReportReadDataBuffer[7200] = {0};
|
|||
|
float new_data_0,
|
|||
|
new_data_1, new_data_2, new_data_3, new_data_4, new_data;
|
|||
|
char index, max = 0;
|
|||
|
int m = 0, num, it, add_g;
|
|||
|
float md_u, md_d, md;
|
|||
|
char FirstPowerON_Flag = 1;
|
|||
|
struct tm *time;
|
|||
|
time_t timestamp = 0; /* 时间戳 */
|
|||
|
char Send_Once = 1;
|
|||
|
int ReSendStartCommand_Count = 0;
|
|||
|
MattressParameterInit(); // 床垫 初始化
|
|||
|
// 初始化IIC
|
|||
|
IIC_Init();
|
|||
|
// 一分钟开启BLE启动状态
|
|||
|
PowerOn_OneMinuteBLEScan();
|
|||
|
#if 1
|
|||
|
// 初始化看门狗
|
|||
|
IWDG_Init();
|
|||
|
#ifdef NNOM_USING_STATIC_MEMORY
|
|||
|
// nnom_set_static_buf(BH_static_buf, sizeof(BH_static_buf)); // 对运行内存进行初始化
|
|||
|
#endif
|
|||
|
// BH_model = nnom_model_create_BH_KC(); // 调用预测睡眠和呼吸的模型函数,初始化 //显示内存使用情况。
|
|||
|
#ifndef NOT_PRE_STAGE
|
|||
|
#ifdef NNOM_USING_STATIC_MEMORY
|
|||
|
nnom_set_static_buf(Stage_static_buf, sizeof(Stage_static_buf)); // 对运行内存进行初始化
|
|||
|
#endif
|
|||
|
stage_model = nnom_model_create(); // 调用预测睡眠周期模型函数,初始化。该函数的h文件还没有加到这个工程里 //显示内存使用情况。
|
|||
|
#endif
|
|||
|
// 用于测试
|
|||
|
if (TEST_SEND_BH_STAGE || TEST_SEND_SINGAL)
|
|||
|
{
|
|||
|
TIM_Cmd(TIM3, ENABLE); //
|
|||
|
Key_Cal_Flag = 1;
|
|||
|
}
|
|||
|
Storage_Initialization(); // 存储初始化
|
|||
|
Local_ON_BED_Threshold = ON_BED_Threshold;
|
|||
|
Local_OFF_BED_Threshold = OFF_BED_Threshold;
|
|||
|
// 读取ID
|
|||
|
Chip_ID_Data = SGM58031_ReadData(ChipID_Reg, 0x90, 2);
|
|||
|
if (SGM58031_WriteConfig(0x40e3))
|
|||
|
printf("ADC Successfully initialized");
|
|||
|
MyDSP_Init();
|
|||
|
while (1)
|
|||
|
{
|
|||
|
// 用于测试
|
|||
|
if (TEST_SEND_BH_STAGE)
|
|||
|
{
|
|||
|
#ifndef NOT_PRE_STAGE
|
|||
|
c_BH_stage(BH_model, stage_model);
|
|||
|
#else
|
|||
|
// pre_bh(BH_model);
|
|||
|
#endif
|
|||
|
}
|
|||
|
key_optical(); // 按键检测
|
|||
|
if (USART_DealFlag)
|
|||
|
{
|
|||
|
USART_DealFlag = 0;
|
|||
|
wifi_cmd_exe(); // 通讯交流
|
|||
|
// 串口接收完毕时使能计算定时器
|
|||
|
TIM_Cmd(TIM5, ENABLE);
|
|||
|
}
|
|||
|
else
|
|||
|
CheckOverTimeValueClear();
|
|||
|
if (Key_Cal_Flag == 0) // 配网成功
|
|||
|
{
|
|||
|
// 时间戳下发成功
|
|||
|
if (TimeClock_Flag == 1)
|
|||
|
{
|
|||
|
TIM_Cmd(TIM2, ENABLE);
|
|||
|
get_optical_power(); // 获取光功
|
|||
|
MyFitter(); // 滤波器
|
|||
|
// 第一次上电上报校准值
|
|||
|
if (FirstPowerON_Flag)
|
|||
|
{
|
|||
|
FirstPowerON_Flag = 0;
|
|||
|
CalValue_Upload();
|
|||
|
delay_ms(50);
|
|||
|
// 版本号上报
|
|||
|
version_upload();
|
|||
|
BreathRate = 0;
|
|||
|
HeartBeatRate = 0;
|
|||
|
// MySetRandom(AIN_1310);
|
|||
|
// 生成随机值 心率和呼吸
|
|||
|
// BreathRate = rand() % 11 + 14; // 产生14~24的随机数
|
|||
|
// HeartBeatRate = rand() % 11 + 54; // 产生54~64的随机数
|
|||
|
}
|
|||
|
// 发送json数据
|
|||
|
if (wifi_json_flg == 1)
|
|||
|
{
|
|||
|
// 喂狗 超时 32s 就复位(防止硬件设备错误以及卡死)
|
|||
|
IWDG_Feed();
|
|||
|
// TIM_Cmd(TIM2, DISABLE);
|
|||
|
wifi_json_send();
|
|||
|
// TIM_Cmd(TIM2, ENABLE);
|
|||
|
wifi_json_flg = 0;
|
|||
|
}
|
|||
|
// 发送数据
|
|||
|
if (wifi_len_500_flg == 1)
|
|||
|
{
|
|||
|
wifi_len_500_flg = 0;
|
|||
|
// TIM_Cmd(TIM2, DISABLE);
|
|||
|
wifi_send();
|
|||
|
// TIM_Cmd(TIM2, ENABLE);
|
|||
|
// 延时50ms
|
|||
|
delay_ms(500);
|
|||
|
}
|
|||
|
// 计算睡眠周期框架
|
|||
|
if (start_stage_flg == 1) // 12秒钟算一次睡眠分期
|
|||
|
{
|
|||
|
start_stage_flg = 0;
|
|||
|
// NOTE: 增加睡眠部分代码
|
|||
|
// 睡眠报告测试
|
|||
|
if (Send_Once)
|
|||
|
{
|
|||
|
Send_Once = 0;
|
|||
|
// SleepReportGenerate(timeClockCount, 720);
|
|||
|
}
|
|||
|
}
|
|||
|
// 计算呼吸心跳框架
|
|||
|
if (start_calculate_flg == 1)
|
|||
|
{
|
|||
|
start_calculate_flg = 0;
|
|||
|
//------------------------------ 算法验证 ---------------------------------------//
|
|||
|
/*
|
|||
|
printf("\n--------------------- Start --------------------------------\n");
|
|||
|
fft_heartDataPostProcessing(round(fft_Output(outPutFitterOPMData_Heart,
|
|||
|
HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART)));
|
|||
|
fft_breathDataPostProcessing(round(fft_Output(outPutFitterOPMData_Breath,
|
|||
|
BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH, TYPE_BREATH)));
|
|||
|
printf("Heart Rate: %d Breath Rate: %d\n", HeartBeatRate, BreathRate);
|
|||
|
printf("\n--------------------- End --------------------------------\n");
|
|||
|
*/
|
|||
|
//------------------------------ FFT算法 ---------------------------------------//
|
|||
|
if (equipment_status_value == InBed_Status)
|
|||
|
{
|
|||
|
/*
|
|||
|
// 心率相关
|
|||
|
fft_HeartBeatRate_Hi = (round(fft_Output(outPutFitterOPMData_Heart,
|
|||
|
HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART)));
|
|||
|
fft_HeartBeatRate_Lo = (round(fft_Output(outPutFitterOPMData_Heart_Lo,
|
|||
|
HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART)));
|
|||
|
if (abs(fft_HeartBeatRate_Lo - fft_HeartBeatRate_Hi) < 15 ||
|
|||
|
fft_HeartBeatRate_Hi <= 120 || fft_HeartBeatRate_Lo > 120)
|
|||
|
fft_HeartBeatRate_Result = fft_HeartBeatRate_Lo;
|
|||
|
else
|
|||
|
fft_HeartBeatRate_Result = (fft_HeartBeatRate_Hi / 2);
|
|||
|
fft_heartDataPostProcessing(fft_HeartBeatRate_Result);
|
|||
|
// 呼吸相关
|
|||
|
fft_breathDataPostProcessing(round(fft_Output(outPutFitterOPMData_Breath,
|
|||
|
BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH, TYPE_BREATH)));
|
|||
|
// 记录
|
|||
|
BreathRate_Record = BreathRate;
|
|||
|
HeartBeatRate_Record = HeartBeatRate;
|
|||
|
*/
|
|||
|
switch (FFT_Calculate_State_Flag)
|
|||
|
{
|
|||
|
// 启动计算
|
|||
|
case FFT_Start_Calculate:
|
|||
|
#if 0
|
|||
|
// 心率相关
|
|||
|
fft_HeartBeatRate_Hi = (round(fft_Output(outPutFitterOPMData_Heart,
|
|||
|
HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART)));
|
|||
|
fft_HeartBeatRate_Lo = (round(fft_Output(outPutFitterOPMData_Heart_Lo,
|
|||
|
HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART)));
|
|||
|
if (abs(fft_HeartBeatRate_Lo - fft_HeartBeatRate_Hi) < 15 ||
|
|||
|
fft_HeartBeatRate_Hi <= 120 || fft_HeartBeatRate_Lo > 120)
|
|||
|
fft_HeartBeatRate_Result = fft_HeartBeatRate_Lo;
|
|||
|
else
|
|||
|
fft_HeartBeatRate_Result = (fft_HeartBeatRate_Hi / 2);
|
|||
|
fft_heartDataPostProcessing(fft_HeartBeatRate_Result);
|
|||
|
// 呼吸相关
|
|||
|
fft_breathDataPostProcessing(round(fft_Output(outPutFitterOPMData_Breath,
|
|||
|
BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH, TYPE_BREATH)));
|
|||
|
// 记录
|
|||
|
BreathRate_Record = BreathRate;
|
|||
|
HeartBeatRate_Record = HeartBeatRate;
|
|||
|
if (FFT_Count_State_Flag == FFT_No_breath)
|
|||
|
{
|
|||
|
#if THE_VERSION
|
|||
|
BreathRate = 0;
|
|||
|
#else
|
|||
|
; // BreathRate = 0;
|
|||
|
#endif
|
|||
|
}
|
|||
|
#else
|
|||
|
fft_HeartBeatCurrentFilter = FILTER_HI_TYPE;
|
|||
|
fft_Output(outPutFitterOPMData_Heart, HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART);
|
|||
|
memcpy(HeartValueRes2Peaks, FFT_HeartRateRes, sizeof(FFT_HeartRateRes));
|
|||
|
|
|||
|
fft_HeartBeatCurrentFilter = FILTER_LO_TYPE;
|
|||
|
fft_Output(outPutFitterOPMData_Heart_Lo, HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH, TYPE_HEART);
|
|||
|
memcpy(HeartValueRes2Peaks + 2, FFT_HeartRateRes, sizeof(FFT_HeartRateRes));
|
|||
|
|
|||
|
time_HeartBeatRate_Result = time_domain_heart_rate(outPutFitterOPMData_Heart_Lo);
|
|||
|
fft_HeartBeatRate_Result = MyToolSelectHp(HeartValueRes2Peaks, stash_Ratio,
|
|||
|
fft_HeartBeatRate_StashBuffer, time_HeartBeatRate_Result);
|
|||
|
|
|||
|
fft_heartDataPostProcessing(fft_HeartBeatRate_Result);
|
|||
|
// 呼吸相关
|
|||
|
fft_breathDataPostProcessing(round(fft_Output(outPutFitterOPMData_Breath,
|
|||
|
BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH, TYPE_BREATH)));
|
|||
|
// 更新数据
|
|||
|
MyToolMoveUpdate((float *)fft_HeartBeatRate_StashBuffer, 15, HeartBeatRate);
|
|||
|
// 记录
|
|||
|
BreathRate_Record = BreathRate;
|
|||
|
HeartBeatRate_Record = HeartBeatRate;
|
|||
|
#endif
|
|||
|
break;
|
|||
|
// 停止计算
|
|||
|
case FFT_Stop_Calculate:
|
|||
|
// 有体动情况下尽快上报数据
|
|||
|
if ((BreathRate == 0) && (HeartBeatRate == 0))
|
|||
|
{
|
|||
|
BreathRate_Record = 15;
|
|||
|
HeartBeatRate_Record = 75;
|
|||
|
}
|
|||
|
BreathRate = BreathRate_Record;
|
|||
|
HeartBeatRate = HeartBeatRate_Record;
|
|||
|
break;
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
timestamp = timeClockCount_Send / 1000;
|
|||
|
/* 时间补偿 */
|
|||
|
timestamp = timestamp + ((signed char)warning_config.timeZone) * 60 * 60;
|
|||
|
/* 调用系统函数 */
|
|||
|
time = localtime(×tamp);
|
|||
|
g_mon = time->tm_mon; /* 月份 */
|
|||
|
g_day = time->tm_mday; /* 日期 */
|
|||
|
g_hour = time->tm_hour; /* 小时:0-23点,UTC+0时间*/
|
|||
|
g_min = time->tm_min; /* 分钟:0-60 ,UTC+0时间 */
|
|||
|
g_sec = time->tm_sec; /* 秒 :0-60,UTC+0时间 */
|
|||
|
// 重新获取时间戳 (超过1小时或者每天的中午更新时间)
|
|||
|
if (TimeClock_Recalibrate_Count >= TIME_CLOCK_MAX_TIMES)
|
|||
|
{
|
|||
|
TimeClock_Flag = 0;
|
|||
|
TIM_ClearITPendingBit(TIM5, TIM_IT_Update); // 清除标志位
|
|||
|
TIM_Cmd(TIM5, DISABLE); // 失能定时器5
|
|||
|
TimeClock_Recalibrate_Count = TIME_CLOCK_MAX_TIMES;
|
|||
|
// printf("\r\n!!!Recalibrate!!!\r\n");
|
|||
|
}
|
|||
|
// 超时或者联网成功则复位 同时发送清除BLE信息的指令
|
|||
|
if (PowerOn_OneMinuteCount >= ONE_MINUTES_COUNT &&
|
|||
|
PowerOn_OneMinuteCount_Start)
|
|||
|
{
|
|||
|
PowerOn_OneMinuteCount_Start = 0;
|
|||
|
USART1_SendData(myReset, 5); // 清除指令
|
|||
|
delay_ms(1500);
|
|||
|
if (Key_Cal_Flag != 0) // 没有联网成功
|
|||
|
NVIC_SystemReset(); // 复位
|
|||
|
}
|
|||
|
else if (PowerOn_OneMinuteCount < ONE_MINUTES_COUNT)
|
|||
|
{
|
|||
|
// 如果配网开始则count清除
|
|||
|
if (PowerOn_StartConfigFlg)
|
|||
|
PowerOn_OneMinuteCount = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
static int Value = 0;
|
|||
|
Value++;
|
|||
|
// LED_B=!LED_B;
|
|||
|
LED_R = 1;
|
|||
|
if (TimeClock_Recalibrate_Count >= TIME_CLOCK_MAX_TIMES)
|
|||
|
{
|
|||
|
TimeClock_Recalibrate_Count = 0;
|
|||
|
LED_G = 0;
|
|||
|
LED_B = 0; // 重新校准时间戳的时候青色LED闪一下
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LED_G = 1;
|
|||
|
LED_B = !LED_B;
|
|||
|
}
|
|||
|
TIM_Cmd(TIM2, DISABLE);
|
|||
|
printf("Wait TimeStamp...\r\n");
|
|||
|
wifi_crc_send(get_time_buf, 13);
|
|||
|
delay_ms(500);
|
|||
|
// 喂狗 超时 32s 就复位(防止硬件设备错误以及卡死)
|
|||
|
IWDG_Feed();
|
|||
|
}
|
|||
|
}
|
|||
|
// 等待配网
|
|||
|
else
|
|||
|
{
|
|||
|
ReSendStartCommand_Count++;
|
|||
|
// printf("Wait Net...\r\n");
|
|||
|
// AP = 1; BLE = 0
|
|||
|
if (!NetworkConnectionWay)
|
|||
|
LED_R = 1;
|
|||
|
else
|
|||
|
LED_R = 0;
|
|||
|
LED_G = 1;
|
|||
|
LED_B = 0;
|
|||
|
if (start_ConnectNet_flg)
|
|||
|
{
|
|||
|
delay_ms(2000);
|
|||
|
start_ConnectNet_flg = 0;
|
|||
|
USART1_SendData(Start_Cmd, 5); // 启动配网指令
|
|||
|
}
|
|||
|
// 配网超时重发机制
|
|||
|
if (ReSendStartCommand_Count >= 1000 && start_ConnectNet_flg == 0)
|
|||
|
{
|
|||
|
start_ConnectNet_flg = 1;
|
|||
|
ReSendStartCommand_Count = 0;
|
|||
|
}
|
|||
|
IWDG_Feed();
|
|||
|
}
|
|||
|
OPM_MattressCalibration();
|
|||
|
// printf("Key_Cal_Flag is %d TimeClock_Flag is %d\n", Key_Cal_Flag,TimeClock_Flag);
|
|||
|
IWDG_Feed();
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: three_avg
|
|||
|
* @brief: 平均计算
|
|||
|
* @param {unsigned short int} data
|
|||
|
* @param {unsigned short int} max
|
|||
|
* @param {unsigned short int} min
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
float three_avg(unsigned short int data, unsigned short int max, unsigned short int min)
|
|||
|
{
|
|||
|
float md_u, md_d, md;
|
|||
|
md_u = data - min;
|
|||
|
md_d = max - min;
|
|||
|
md_d = md_d + 1;
|
|||
|
md = (md_u / md_d) * 128;
|
|||
|
return md;
|
|||
|
}
|
|||
|
/**
|
|||
|
* @function:itoa_my
|
|||
|
* @brief 整形转字符串
|
|||
|
* @param {int} value
|
|||
|
* @param {char} *string
|
|||
|
* @param {int} radix
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
char *itoa_my(long value, char *string, int radix)
|
|||
|
{
|
|||
|
char zm[37] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|||
|
char aa[100] = {0};
|
|||
|
long sum = value;
|
|||
|
char *cp = string;
|
|||
|
int i = 0;
|
|||
|
if (radix < 2 || radix > 36) // 增加了对错误的检测
|
|||
|
{
|
|||
|
return string;
|
|||
|
}
|
|||
|
if (value < 0)
|
|||
|
{
|
|||
|
return string;
|
|||
|
}
|
|||
|
while (sum > 0)
|
|||
|
{
|
|||
|
aa[i++] = zm[sum % radix];
|
|||
|
sum /= radix;
|
|||
|
}
|
|||
|
for (int j = i - 1; j >= 0; j--)
|
|||
|
{
|
|||
|
*cp++ = aa[j];
|
|||
|
}
|
|||
|
*cp = '\0';
|
|||
|
return string;
|
|||
|
}
|
|||
|
|
|||
|
float32_t IIRStateF32_Breath[4 * numStages]; /* 状态缓存 */
|
|||
|
float32_t IIRStateF32_Heart[4 * numStages]; /* 状态缓存 */
|
|||
|
float32_t IIRStateF32_Heart_NoCut[4 * numStages]; /* 状态缓存 */
|
|||
|
|
|||
|
extern BandFitterConfig_t BandFitterConfig;
|
|||
|
// static float32_t FitterOutputData[LENGTH_SAMPLES]; /* 滤波后的输出 */
|
|||
|
/**
|
|||
|
* @function: MyDSP_Init
|
|||
|
* @brief 测试DSP库
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
int MyDSP_Init(void)
|
|||
|
{
|
|||
|
/* 实现IIR滤波,这里每次处理1个点 */
|
|||
|
arm_biquad_cascade_df1_init_f32(&BreathPart, numStages, (float32_t *)&IIRCoeffs32BP_Breath,
|
|||
|
(float32_t *)&IIRStateF32_Breath[0]);
|
|||
|
/* 实现IIR滤波,这里每次处理1个点 */
|
|||
|
arm_biquad_cascade_df1_init_f32(&HeartPart, numStages, (float32_t *)&IIRCoeffs32BP_Heart,
|
|||
|
(float32_t *)&IIRStateF32_Heart[0]);
|
|||
|
/* 实现IIR滤波,这里每次处理1个点 */
|
|||
|
arm_biquad_cascade_df1_init_f32(&HeartPart_NoCut, numStages, (float32_t *)&IIRCoeffs32BP_Heart_NoCut,
|
|||
|
(float32_t *)&IIRStateF32_Heart_NoCut[0]);
|
|||
|
/* 实现IIR滤波,这里每次处理1个点 */
|
|||
|
arm_biquad_cascade_df1_init_f32(&CheckPart, numStages, (float32_t *)&IIRCoeffs32BP_Breath,
|
|||
|
(float32_t *)&IIRStateF32_Breath[0]);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
void MyFitter(void)
|
|||
|
{
|
|||
|
float32_t CopyHrBuffer[HEART_FITTER_LENGTH] = {0};
|
|||
|
float32_t ResultBuffer[HEART_FITTER_LENGTH - HEART_IGNORE_LENGTH] = {0};
|
|||
|
if (FitterCollectDoneFlag_Heart)
|
|||
|
{
|
|||
|
FitterCount_Heart = HEART_FITTER_LENGTH - 50;
|
|||
|
// 高频版本滤波
|
|||
|
memset(ResultBuffer, 0, sizeof(ResultBuffer));
|
|||
|
arm_iir_f32_bp_stream_Heart_Output(FitterOPMData_Heart, outPutFitterOPMData_Heart);
|
|||
|
arm_iir_f32_bp_stream_Heart_Output_NoCut(outPutFitterOPMData_Heart, ResultBuffer);
|
|||
|
arm_iir_f32_bp_stream_Heart_Output_NoCut(ResultBuffer, outPutFitterOPMData_Heart);
|
|||
|
// 低频版本滤波
|
|||
|
memset(ResultBuffer, 0, sizeof(ResultBuffer));
|
|||
|
arm_iir_f32_bp_stream_Heart_Output(FitterOPMData_Heart, outPutFitterOPMData_Heart_Lo);
|
|||
|
arm_iir_f32_bp_stream_Heart_Output_NoCut_2(outPutFitterOPMData_Heart_Lo, ResultBuffer);
|
|||
|
arm_iir_f32_bp_stream_Heart_Output_NoCut_2(ResultBuffer, outPutFitterOPMData_Heart_Lo);
|
|||
|
memcpy(FitterOPMData_Heart, FitterOPMData_Heart + 50,
|
|||
|
sizeof(float32_t) * (LENGTH_SAMPLES_HEART - 50));
|
|||
|
|
|||
|
FitterCollectDoneFlag_Heart = 0;
|
|||
|
}
|
|||
|
if (FitterCollectDoneFlag_Breath)
|
|||
|
{
|
|||
|
FitterCount_Breath = LENGTH_SAMPLES_BREATH - 50;
|
|||
|
arm_iir_f32_bp_stream_Breath_Output(FitterOPMData_Breath, outPutFitterOPMData_Breath);
|
|||
|
memcpy(FitterOPMData_Breath, FitterOPMData_Breath + 50,
|
|||
|
sizeof(float32_t) * (LENGTH_SAMPLES_BREATH - 50));
|
|||
|
FitterCollectDoneFlag_Breath = 0;
|
|||
|
memcpy(ResultBuffer, outPutFitterOPMData_Breath + HEART_IGNORE_LENGTH, sizeof(ResultBuffer));
|
|||
|
Diff = MyToolFindMaxValue(ResultBuffer, BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH - HEART_IGNORE_LENGTH) -
|
|||
|
MyToolFindMinValue(ResultBuffer, BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH - HEART_IGNORE_LENGTH);
|
|||
|
Diff_Detail = MyToolFindMaxValue(ResultBuffer + 400, BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH - HEART_IGNORE_LENGTH - 400) -
|
|||
|
MyToolFindMinValue(ResultBuffer + 400, BREATH_FITTER_LENGTH - BREATH_IGNORE_LENGTH - HEART_IGNORE_LENGTH - 400);
|
|||
|
// 如果小于0.5开始计算
|
|||
|
if (Diff_Detail < 0.3f)
|
|||
|
FFT_Count_State_Flag = FFT_Still_state;
|
|||
|
else if (Diff_Detail < 1.2f)
|
|||
|
FFT_Count_State_Flag = FFT_Mild_body_motion;
|
|||
|
else if (Diff_Detail <= 4.0f)
|
|||
|
FFT_Count_State_Flag = FFT_Medium_body_motion;
|
|||
|
else if (Diff_Detail > 4.0f)
|
|||
|
FFT_Count_State_Flag = FFT_Large_body_motion;
|
|||
|
if (Diff < 0.5f)
|
|||
|
{
|
|||
|
FFT_Count_State_Flag = FFT_Still_state;
|
|||
|
FFT_Calculate_State_Flag = FFT_Start_Calculate;
|
|||
|
//---------------------------------------------
|
|||
|
// if (Diff < 0.06f)
|
|||
|
// // if (i_count_No_Breath == 5)
|
|||
|
// FFT_Count_State_Flag = FFT_No_breath;
|
|||
|
// else if (Diff < 0.5f)
|
|||
|
// FFT_Count_State_Flag = FFT_Still_state;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
FFT_Calculate_State_Flag = FFT_Stop_Calculate;
|
|||
|
}
|
|||
|
}
|
|||
|
if (FitterCollectDoneFlag_CheckBed)
|
|||
|
{
|
|||
|
FitterCollectDoneFlag_CheckBed = 0;
|
|||
|
breathInBedCheck(FitterOPMData_CheckBed);
|
|||
|
// memcpy(FitterOPMData_CheckBed, FitterOPMData_CheckBed + 50,
|
|||
|
// sizeof(float32_t) * (LENGTH_SAMPLES_IN_OFF_BED - 50));
|
|||
|
FitterCount_CheckBed = LENGTH_SAMPLES_IN_OFF_BED - 50;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @function: PowerOn_OneMinuteBLEScan
|
|||
|
* @brief: 上电一分钟蓝牙发送数据 可以被找到
|
|||
|
* @return {*}
|
|||
|
* @author: lzc
|
|||
|
*/
|
|||
|
void PowerOn_OneMinuteBLEScan(void)
|
|||
|
{
|
|||
|
// 上电复位才进去 其他情况不会进去
|
|||
|
if (bootResult == PowerOn_Reset)
|
|||
|
{
|
|||
|
PowerOn_OneMinuteCount_Start = 1;
|
|||
|
// 发送对应的指令进入1分钟蓝牙启动
|
|||
|
USART1_SendData(myScan, 5); // 寻网指令
|
|||
|
for (int i = 0; i < 10; i++)
|
|||
|
{
|
|||
|
LED_B = !LED_B;
|
|||
|
delay_ms(500);
|
|||
|
}
|
|||
|
USART1_SendData(Start_Cmd, 5); // 启动配网指令
|
|||
|
delay_ms(500);
|
|||
|
Key_Cal_Flag = 1;
|
|||
|
PowerOn_OneMinuteCount = 0;
|
|||
|
// 启动60秒倒计时
|
|||
|
/*
|
|||
|
while (PowerOn_OneMinuteCount < ONE_MINUTES_COUNT)
|
|||
|
{
|
|||
|
if (USART_DealFlag)
|
|||
|
{
|
|||
|
USART_DealFlag = 0;
|
|||
|
wifi_cmd_exe(); // 通讯交流
|
|||
|
}
|
|||
|
// 如果配网开始则count清除
|
|||
|
if (PowerOn_StartConfigFlg)
|
|||
|
PowerOn_OneMinuteCount = 0;
|
|||
|
if (Key_Cal_Flag == 0)
|
|||
|
break;
|
|||
|
LED_B = !LED_B;
|
|||
|
delay_ms(500);
|
|||
|
}*/
|
|||
|
}
|
|||
|
}
|