BLE_DCF_TYQ_CH592F/BSP/src/bsp_valve.c

682 lines
19 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.

/*
* @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
/* 定时器3CAP捕捉 */
GPIOA_ResetBits(GPIO_Pin_2);
GPIOA_ModeCfg(GPIO_Pin_2, GPIO_ModeIN_PU);
// TMR3功能引脚映射选择位
// 1TMR3_/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;
}
}