#include "main.h" #include #include #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 #include "wificom.h" #include #include #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); }*/ } }