Job_SignsPads/STM32/Code/STM32F405/USER/main.c
2025-04-22 10:29:37 +08:00

1403 lines
44 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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
// 每天早上830 报一次夜间的翻身次数
// 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(&timestamp);
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);
}*/
}
}