/* * @Author : stark1898y 1658608470@qq.com * @Date : 2024-12-15 15:01:15 * @LastEditors : stark1898y 1658608470@qq.com * @LastEditTime : 2025-02-24 17:58:40 * @FilePath : \BLE_TYQ_CH584M\BSP\src\bsp_valve.c * @Description : * * Copyright (c) 2024 by yzy, All Rights Reserved. */ #include "bsp_valve.h" #include "bsp_flash.h" #include "bsp_beep_led_emv.h" // 0xAA CMD/DATA/ DATA_LEN (DATA) checksum 0x55 #include "bsp_uart.h" #include "log.h" #include "peripheral.h" #include "SLEEP.h" #include "bsp_adc.h" #undef LOG_ENABLE #define LOG_ENABLE 1 #undef LOG_TAG #define LOG_TAG "BSP_VALVE" TsValveData gValveData = {0}; TsRawFrameData RelyData; // 存储 当前task id 的全局变量 tmosTaskID vavle_task_id = INVALID_TASK_ID; #define ARRAY_SIZE(freq_arr) (sizeof(freq_arr) / sizeof((freq_arr)[0])) volatile uint8_t cap_flag = 0; __attribute__((aligned(4))) uint32_t cap_buf[20]; #define CAP_BUF_LEN (20) #define CAP_FREQ_MIN (2000U) #define CAP_FREQ_MAX (10000U) uint16_t valve_switch_on_freq = 6535; uint16_t valve_switch_off_freq = 7508; uint16_t valve_switch_freq = 0; volatile uint8_t valve_switch_dect_flag = 0; /** * @description: 从帧起始符开始到校验码之前所有字节的和的模256,即各字节不计超过255的溢出值的二进制算术和。 * @param {uint8_t} *data * @param {uint16_t} len * @return {*} */ uint8_t CheckSum(const uint8_t *data, size_t len) { uint8_t sum = 0; for (size_t i = 0; i < len; i++) { sum += data[i]; } return sum; } void VavleDect_Start(void) { BSP_BlockSleep(); BSP_RequestBoost(); DelayMs(1); tmos_memset(cap_buf, 0, sizeof(cap_buf)); TMR3_CapInit(FallEdge_To_FallEdge); TMR3_CAPTimeoutCfg(GetSysClock() / 100); // 设置捕捉超时时间 10ms // TMR3_CAPTimeoutCfg(0x3FFFFFF); // 设置捕捉超时时间 TMR3_DMACfg(ENABLE, (uint16_t)(uint32_t)&cap_buf[0], (uint16_t)(uint32_t)&cap_buf[CAP_BUF_LEN], Mode_Single); TMR3_ITCfg(ENABLE, TMR0_3_IT_DMA_END); // 开启DMA完成中断 PFIC_EnableIRQ(TMR3_IRQn); logDebug("VavleDect_Start"); } // 一个数组中,去掉最大最小值,计算平均值 uint16_t VavleDect_CalFreq(uint16_t freq_arr[], uint8_t n) { if (freq_arr == NULL || n <= 2) { logError("数组太小或为空,无法去除最大最小值"); return 0; } uint16_t min, max; double average = 0; for (uint8_t i = 0; i < n; i++) { average += freq_arr[i]; if (i == 0) { min = freq_arr[i]; max = freq_arr[i]; } min = ((min > freq_arr[i]) ? freq_arr[i] : min); // 软件滤波 max = ((max < freq_arr[i]) ? freq_arr[i] : max); } logDebug("min = %d, max = %d", min, max); average = (average - min - max) / (CAP_BUF_LEN - 2); return (uint16_t)average; } uint16_t VavleDect_GetFreq(void) { uint16_t freq = 0; if (cap_flag == 0) { // TMR3_ITCfg(DISABLE, TMR0_3_IT_DMA_END); // 使用单次DMA功能+中断,注意完成后关闭此中断使能,否则会一直上报中断。 // TMR3_ClearITFlag(TMR0_3_IT_DMA_END); // 清除中断标志 logError("cap err"); return 0; } cap_flag = 0; uint16_t t[CAP_BUF_LEN] = {0}; uint16_t f[CAP_BUF_LEN] = {0}; for (uint8_t i = 0; i < CAP_BUF_LEN; i++) { // logDebug("%08ld ", cap_buf[i] & 0x1ffffff); // 26bit, 最高位表示 高电平还是低电平 t[i] = ((cap_buf[i] & 0x1ffffff) * 1.0f) / FREQ_SYS * 1000000; f[i] = 1000000 / t[i]; logDebug("T = %04d us, f = %04d Hz", t[i], f[i]); BSP_UART1_TxLoop(); } freq = VavleDect_CalFreq(&f[0], CAP_BUF_LEN); return freq; } void VavleDect_Switch(void) { if (valve_switch_freq == 0) { gValveData.switch_status = kDisconnect; logError("valve_switch_freq err"); return; } if (valve_switch_freq >= (valve_switch_off_freq - 100)) { gValveData.switch_status = kOpened; logDebug("valve_switch_on"); } else if (valve_switch_freq <= (valve_switch_on_freq + 100)) { gValveData.switch_status = kClosed; logDebug("valve_switch_off"); } } #if 0 /** * @description: 从接收缓冲区中获取一帧有效数据 * @param {TsFrameData} *pFrameData 主机帧 * @param {uint8_t} *p_src 接收缓冲区 * @param {uint16_t} src_len 接收缓冲区长度 * @return {*} */ TsFrameData *HR_GetFrameData(const uint8_t *p_src, const uint8_t src_len) { uint8_t data_field_len = 0; uint8_t check_sum = 0; TsFrameData *get_buffer = NULL; for (uint8_t i = 0; i < src_len; i++) { // 找帧头 if (p_src[i] == FRAME_HEADER) { // 找数据长度 data_field_len = p_src[i + 2]; // 找帧尾 if (p_src[i + 2 + data_field_len + 2] == FRAME_TAIL) { check_sum = CheckSum(&p_src[i], (3 + data_field_len)); if (p_src[i + 2 + data_field_len + 1] == check_sum) { get_buffer = (TsFrameData *)tmos_msg_allocate(sizeof(TsFrameData) + sizeof(uint8_t) * data_field_len); if (get_buffer == NULL) { logError("tmos_msg_allocate fail"); return NULL; } get_buffer->cmd = p_src[i + 1]; get_buffer->len = data_field_len; if (data_field_len > 0) { tmos_memcmp(get_buffer->data, &p_src[i + 4], data_field_len); } logDebug("HR_GetDataFrame Success!"); return get_buffer; } } } } logError("HR_GetDataFrame Fail!"); return get_buffer; } #endif TsFrameData *BSP_VAVLE_GetFrameData(uint8_t *data, uint8_t len) { int ret = 0; uint16_t index = 0; TsFrameData *get_buffer = NULL; // 解析接收到的数据帧,先寻找AA开头,然后再找AA下一个字节,其代表了数据长度,然后找到代表长度的值的长度的下一位,其为校验码,校验码后为结束码0x55, // 如果数据正确,则提取数据,不正确,则不处理 if (len < 4) { // 至少需要 4 个字节:起始码、长度、校验码、结束码 logError("数据帧长度不足"); // logHexDumpAll(data, len); // return 1; return NULL; } while (index < len && data[index] != FRAME_HEADER) // 寻找起始码 0xAA { index++; } if (index >= len - 3) // 不够空间容纳长度、校验码和结束码 { logError("数据帧起始码错误"); // logHexDumpAll(data, len); return NULL; // return 2; } uint16_t data_len = data[index + 2]; // 读取数据长度 if (index + 3 + data_len + 1 >= len) // 检查数据长度是否合理 数据长度 + 校验码 + 结束码 { logError("数据帧长度错误"); // logHexDumpAll(data, len); return NULL; // return 3; } uint8_t check_sum = data[index + 3 + data_len]; // 读取校验码 uint8_t calculated_sum = CheckSum(&data[index], data_len + 3); // 计算校验码 if (check_sum != calculated_sum) { logError("数据帧校验码错误 check_sum = %02X, calculated_sum = %02X", check_sum, calculated_sum); // logHexDumpAll(data, len); return NULL; // return 4; } if (data[index + 3 + data_len + 1] != FRAME_TAIL) // 检查结束码 { logError("数据帧结束码错误"); // logHexDumpAll(data, len); return NULL; // return 5; } logDebug("数据帧校验通过"); get_buffer = (TsFrameData *)tmos_msg_allocate(sizeof(TsFrameData) + sizeof(uint8_t) * data_len); if (get_buffer == NULL) { logError("tmos_msg_allocate fail"); return NULL; } get_buffer->cmd = data[index + 1]; get_buffer->len = data_len; // get_buffer->data = data; if (data_len > 0) { tmos_memcpy(get_buffer->data, &data[index + 3], data_len); return get_buffer; } // //有效数据长度 // size_t data_len = (data_len + 5); // //到这一步说明数据没问题,将接收到的数据通过中心任务发送出去 // uint8_t *p_data; // p_data = tmos_msg_allocate(data_len); // if (p_data) // { // tmos_memcpy(p_data, data, data_len); // tmos_msg_send(BtRxTaskId, p_data); // tmos_start_task(BtRxTaskId, SYS_EVENT_MSG, 0); // } } uint8_t GenerateRawFrame(TsRawFrameData *pRawData, uint8_t cmd, const uint8_t *p_src, uint8_t src_len) { // 0xAA CMD/DATA/ DATA_LEN (DATA) checksum 0x55 pRawData->len = src_len + 5; tmos_memset(pRawData->buf, 0, sizeof(pRawData->buf)); pRawData->buf[0] = FRAME_HEADER; pRawData->buf[1] = cmd; pRawData->buf[2] = src_len; tmos_memcpy(&pRawData->buf[3], p_src, src_len); // 从帧起始符开始到校验码之前所有字节的和的模256 // ,即各字节不计超过255的溢出值的二进制算术和。 pRawData->buf[pRawData->len - 2] = CheckSum(&pRawData->buf[0], pRawData->len - 2); pRawData->buf[pRawData->len - 1] = FRAME_TAIL; // logHexDumpAll(&pRawData->buf[0], pRawData->len); return 0; } void BSP_VALVE_Generate_UploadData(TsRawFrameData *pRawData) { GenerateRawFrame(pRawData, kCmdData, (uint8_t *)&gValveData, sizeof(gValveData)); // logHexDumpAll(&pRawData->buf[0], pRawData->len); } void BSP_VALVE_Generate_Data(TsRawFrameData *pRawData, uint8_t switch_status, uint8_t bat, int8_t temp, uint8_t humi) { TsValveData ValveData; ValveData.switch_status = 0; ValveData.temp = temp; // 阀门温度 有符号整数 25 ℃ ValveData.in_pressure = 0; ValveData.out_pressure = 0; ValveData.atm_pressure = 0; ValveData.type = kTyq; // 阀门类型 ValveData.bat = bat; // 电池电压 30=3V,18=1.8V ValveData.humi = humi; // 阀门湿度 %RH ValveData.rssi = 0; GenerateRawFrame(pRawData, kCmdData, (uint8_t *)&ValveData, sizeof(ValveData)); // logHexDumpAll(&pRawData->buf[0], pRawData->len); } void BSP_VALVE_Generate_ValveResponse(TsRawFrameData *pRawData, TeFrameCmd cmd, uint8_t status) { uint8_t data = 0; data = status; GenerateRawFrame(pRawData, cmd, &data, 1); // logHexDumpAll(&pRawData->buf[0], pRawData->len); } void BSP_CloseValve(void) { DelayMs(100); } static void VAVLE_Task_ProcessTmosMsg(uint8_t *p_rev_msg) { if (p_rev_msg) { #if 1 TsFrameData *HostFrameData = BSP_VAVLE_GetFrameData(&p_rev_msg[1], p_rev_msg[0]); if (HostFrameData != NULL) { // logHexDumpAll(&HostFrameData->data[0], HostFrameData->len); // 数据段 switch (HostFrameData->cmd) { case kCmdCfg: // uint8_t data_buf[64] = {0}; // tmos_memset(data_buf, 0, sizeof(data_buf)); // 处理数据帧 logDebug("kCmdCfg"); break; case kCmdCloseVavle: logDebug("kCmdCloseVavle"); tmos_set_event(vavle_task_id, VAVLE_CLOSE_START_EVT); // TODO:注意这里 // tmos_set_event(vavle_task_id, VAVLE_CLOSE_START_EVT); // // TODO: 关阀动作 // peripheralChar4Notify((uint8_t *)&RawData.buf[0], RawData.len); break; case kCmdOpenVavle: logDebug("kCmdOpenVavle"); // BSP_UART1_TxLoop(); break; default: logError("无效的命令"); // logHexDumpAll(data, len); break; } } else { logError("数据帧解析失败"); } tmos_msg_deallocate((uint8_t *)HostFrameData); HostFrameData = NULL; #endif } else { logError("pMsg is NULL"); } } // task的event处理回调函数,需要在注册task时候,传进去 static uint16_t VAVLE_Task_ProcessEvent(uint8_t task_id, uint16_t events) { if (events & SYS_EVENT_MSG) { uint8_t *p_rev_msg; if ((p_rev_msg = tmos_msg_receive(vavle_task_id)) != NULL) { VAVLE_Task_ProcessTmosMsg(p_rev_msg); // Release the TMOS message tmos_msg_deallocate(p_rev_msg); } // return unprocessed events return (events ^ SYS_EVENT_MSG); } if (events & VAVLE_RX_DATA_EVT) { logDebug("VAVLE_RX_DATA_EVT"); return (events ^ VAVLE_RX_DATA_EVT); } if (events & VAVLE_TX_DATA_EVT) { logDebug("VAVLE_TX_DATA_EVT"); return (events ^ VAVLE_TX_DATA_EVT); } if (events & VAVLE_CLOSE_START_EVT) { logDebug("VAVLE_CLOSE_START_EVT"); BSP_BlockSleep(); BSP_RequestBoost(); DelayUs(200); // EMV_CHARGE // EMV_CHARGE_EN; // DelayUs(500); // EMV_CHARGE_OFF_DEINIT; // DelayUs(200); // DelayUs(500); // EMV_CHARGE_OFF_DEINIT; // DelayUs(200); EMV_CHARGE_EN; logDebug("EMV_CHARGE_EN"); // 开始一个定时event,1s后产生,当前语句只会产生一次event // 可以在event产生后去开启event,可以是别的task的,也可以是当前task的event tmos_start_task(vavle_task_id, VAVLE_CLOSE_ACTION_EVT, MS1_TO_SYSTEM_TIME(CHARGE_TIME_MS)); return (events ^ VAVLE_CLOSE_START_EVT); } if (events & VAVLE_CLOSE_ACTION_EVT) { BSP_BlockSleep(); BSP_RequestBoost(); logDebug("VAVLE_CLOSE_ACTION_EVT"); BOOST_EN; // EMV_CHARGE_EN; // 关阀动作,一定要先关充电的,防止其他12V用电 EMV_CHARGE_OFF_DEINIT; BEEP_ON; logDebug("EMV_CHARGE_OFF_DEINIT"); // DelayMs(10); // EMV_CTRL EMV_ON; // DelayMs(50); // {BEEP_OFF_DEINIT; // EMV_CHARGE_OFF_DEINIT; // EMV_OFF_DEINIT; // BSP_NoNeedBoost(); // gValveData.switch_status = kClosed; // tmos_memset(&RelyData, 0, sizeof(RelyData)); // BSP_VALVE_Generate_ValveResponse(&RelyData, kCmdCloseVavle, 1); // tmos_set_event(Peripheral_TaskID, SBP_REPLY_CMD_EVT);} logDebug("EMV_ON"); tmos_start_task(vavle_task_id, VAVLE_CLOSE_END_EVT, MS1_TO_SYSTEM_TIME(100)); return (events ^ VAVLE_CLOSE_ACTION_EVT); } if (events & VAVLE_CLOSE_END_EVT) { BEEP_OFF_DEINIT; EMV_CHARGE_OFF_DEINIT; EMV_OFF_DEINIT; LED_ALL_OFF_DEINIT; BSP_NoNeedBoost(); gValveData.switch_status = kClosed; tmos_memset(&RelyData, 0, sizeof(RelyData)); BSP_VALVE_Generate_ValveResponse(&RelyData, kCmdCloseVavle, 1); tmos_set_event(Peripheral_TaskID, SBP_REPLY_CMD_EVT); logDebug("VAVLE_CLOSE_END_EVT"); return (events ^ VAVLE_CLOSE_END_EVT); } // 开始测量电磁铁电感 if (events & VAVLE_DECT_SWITCH_START_EVT) { valve_switch_dect_flag = 0; logDebug("VAVLE_DECT_SWITCH_START_EVT"); VavleDect_Start(); tmos_start_task(vavle_task_id, VAVLE_DECT_SWITCH_END_EVT, MS1_TO_SYSTEM_TIME(12)); return (events ^ VAVLE_DECT_SWITCH_START_EVT); } if (events & VAVLE_DECT_SWITCH_END_EVT) { logDebug("VAVLE_DECT_SWITCH_END_EVT"); valve_switch_freq = VavleDect_GetFreq(); logDebug("valve_switch_freq = 04%d Hz", valve_switch_freq); VavleDect_Switch(); valve_switch_dect_flag = 1; // logDebug("LED显示状态"); // // tmos_set_event(led_task_id, LED_SHOW_START_EVT); // BSP_BlockSleep(); // BSP_RequestBoost(); // DelayMs(1); // ShowLed(); return (events ^ VAVLE_DECT_SWITCH_END_EVT); } if (events & VAVLE_DECT_SWITCH_CALIB_EVT) { logDebug("VAVLE_DECT_SWITCH_CALIB_EVT"); return (events ^ VAVLE_DECT_SWITCH_CALIB_EVT); } if (events & VAVLE_LOW_VBAT_ALARM_EVT) { logDebug("VAVLE_LOW_VBAT_ALARM_EVT"); // BSP_BlockSleep(); // BSP_RequestBoost(); // LED_ALL_OFF_DEINIT; // LED_Y_ON; // BEEP_ON; // DelayMs(10); // LED_ALL_OFF_DEINIT; // BEEP_OFF_DEINIT; // BSP_NoNeedBoost(); // BSP_RequestSleep(); // tmos_set_event(vavle_task_id, VAVLE_CLOSE_START_EVT); // tmos_start_task(vavle_task_id, VAVLE_LOW_VBAT_ALARM_EVT, MS1_TO_SYSTEM_TIME(VALVE_LOW_VBAT_ALARM_PERIOD_MS)); return (events ^ VAVLE_LOW_VBAT_ALARM_EVT); } if (events & VAVLE_LOOP_DECT_EVT) { logDebug("VAVLE_LOOP_DECT_EVT"); gValveData.bat = BSP_ReadVbat(); // 电压过低就关阀 if (gValveData.bat <= LOW_VABAT_CLOSE_VALUE) { gValveData.switch_status = kClosed; tmos_set_event(vavle_task_id, VAVLE_CLOSE_START_EVT); } else if (gValveData.bat <= LOW_VABAT_ALARM_VALUE) { tmos_set_event(vavle_task_id, VAVLE_LOW_VBAT_ALARM_EVT); } tmos_start_task(vavle_task_id, VAVLE_LOOP_DECT_EVT, MS1_TO_SYSTEM_TIME(VALVE_DECT_PERIOD_MS)); return (events ^ VAVLE_LOOP_DECT_EVT); } // Discard unknown events return 0; } void BSP_VAVLE_Init(void) { vavle_task_id = TMOS_ProcessEventRegister(VAVLE_Task_ProcessEvent); tmos_memset(&gValveData, 0, sizeof(gValveData)); gValveData.switch_status = kClosed; gValveData.temp = -100; gValveData.in_pressure = 0; gValveData.out_pressure = 0; gValveData.atm_pressure = 0; gValveData.type = kTyq; gValveData.bat = BSP_ReadVbat(); // //立即开始一个event // tmos_set_event(vavle_task_id, VAVLE_RX_DATA_EVT); // PA2 /* 定时器3,CAP捕捉, */ GPIOA_ResetBits(GPIO_Pin_2); GPIOA_ModeCfg(GPIO_Pin_2, GPIO_ModeIN_PU); // TMR3功能引脚映射选择位: // 1:TMR3_/PWM3_/CAP3_映射到PA[2]; R16_PIN_ALTERNATE |= (1 << 3); // TMR3_CapInit(FallEdge_To_FallEdge); // // (1 / 62.4MHz) * 2的26次方 = 0.01602564102564102564102564102564 us * 67108864 约等于 1.0754625641025641025641025641025 S // // TMR3_CAPTimeoutCfg(FREQ_SYS ); // 设置捕捉超时时间 // TMR3_CAPTimeoutCfg(GetSysClock() / 100); // 设置捕捉超时时间 10ms tmos_start_task(vavle_task_id, VAVLE_LOOP_DECT_EVT, MS1_TO_SYSTEM_TIME(VALVE_DECT_PERIOD_MS)); logInfo("BSP_Valve_Init"); } /********************************************************************* * @fn TMR3_IRQHandler * * @brief TMR3中断函数 * * @return none */ __INTERRUPT __HIGH_CODE void TMR3_IRQHandler(void) // TMR3 定时中断 { if (TMR3_GetITFlag(TMR0_3_IT_DMA_END)) { TMR3_ITCfg(DISABLE, TMR0_3_IT_DMA_END); // 使用单次DMA功能+中断,注意完成后关闭此中断使能,否则会一直上报中断。 TMR3_ClearITFlag(TMR0_3_IT_DMA_END); // 清除中断标志 cap_flag = 1; } }