一:增加了纹波滤波,当纹波板有电阻时打开辅助继电器应该为3帧过冲,使用五次过滤可以消除异常纹波

二、修改了负载启动的顺序,先开启辅助继电器使地相通,再开启D+D-继电器

feat: 发布V1.1.23版本,优化负载初始化继电器时序

- 更新所有头文件版本号至V1.1.21~V1.1.23,协议板固件版本更新为0x0127
- 新增纹波滤波相关宏定义与函数,实现继电器闭合后纹波过滤
- 调整负载初始化流程:先下发辅助继电器,等待回码后延迟30ms再打开北向继电器
- 优化D+/D-寄存器上位机显示单位,适配0.001V解析格式
- 补充YMODEM升级文档说明,完善传输校验与重发规则
- 清理冗余调试打印与Allegro工程日志文件
This commit is contained in:
wrh
2026-09-14 15:13:20 +08:00
parent d231a49771
commit 05309dfb41
15 changed files with 1343 additions and 3490 deletions
+3 -3
View File
@@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
文件名称 : chrg_comm.c 文件名称 : chrg_comm.c
完成日期 : 完成日期 :
当前版本号 : V1.1.19 当前版本号 : V1.1.23
主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。 主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。
版本历史 : 创建原始版本 版本历史 : 创建原始版本
说明 : 说明 :
@@ -27,7 +27,7 @@
#include "stm32f4xx_hal.h" #include "stm32f4xx_hal.h"
#define HOLD_REG_FIRMWARE_VERSION 0x0300U /* 协议板固件版本,只读 */ #define HOLD_REG_FIRMWARE_VERSION 0x0300U /* 协议板固件版本,只读 */
#define CHRG_FIRMWARE_VERSION 0x0123U /* 当前协议板版本:V1.1.19 */ #define CHRG_FIRMWARE_VERSION 0x0127U /* 当前协议板版本:V1.1.23 */
rt_uint8_t ucDiscInBuf[(TOTAL_DISC_REGS+BITS_UCHAR-1)/BITS_UCHAR]; rt_uint8_t ucDiscInBuf[(TOTAL_DISC_REGS+BITS_UCHAR-1)/BITS_UCHAR];
rt_uint8_t ucCoilBuf[(TOTAL_COIL_REGS+BITS_UCHAR-1)/BITS_UCHAR]; rt_uint8_t ucCoilBuf[(TOTAL_COIL_REGS+BITS_UCHAR-1)/BITS_UCHAR];
@@ -618,7 +618,7 @@ eMBException funcReadHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t reqLen,
/* /*
* 协议板版本号使用独立的只读地址0x0300,不占用现有通道保持寄存器空间。 * 协议板版本号使用独立的只读地址0x0300,不占用现有通道保持寄存器空间。
* 当前版本V1.1.19编码为0x0123,Modbus响应按高字节在前返回01 23。 * 当前版本V1.1.23编码为0x0127,Modbus响应按高字节在前返回01 27。
* 该特殊地址只支持一次读取一个寄存器,避免与普通连续寄存器混用。 * 该特殊地址只支持一次读取一个寄存器,避免与普通连续寄存器混用。
*/ */
if (regAddress == HOLD_REG_FIRMWARE_VERSION) { if (regAddress == HOLD_REG_FIRMWARE_VERSION) {
+1 -1
View File
@@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
文件名称 : chrg_comm.h 文件名称 : chrg_comm.h
完成日期 : 完成日期 :
当前版本号 : V1.1.19 当前版本号 : V1.1.21
主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。 主要功能 : 实现对外通讯协议 MODBUS 服务端,以独立线程等待处理响应请求数据。
版本历史 : 创建原始版本 版本历史 : 创建原始版本
说明 : 说明 :
@@ -233,6 +233,8 @@ void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
pSW->VZ = ((frame_data[14] << 8) | frame_data[15]); pSW->VZ = ((frame_data[14] << 8) | frame_data[15]);
pSW->VF = ((frame_data[16] << 8) | frame_data[17]); pSW->VF = ((frame_data[16] << 8) | frame_data[17]);
//rt_kprintf("VZ=%d,VF=%d\n",pSW->VZ,pSW->VF);
#if NORTH_SINK_DEBUG #if NORTH_SINK_DEBUG
LOG_D("Sink[%d] real volt: %d mV", idx, LOG_D("Sink[%d] real volt: %d mV", idx,
((frame_data[4] << 8) | frame_data[5]) * 10); ((frame_data[4] << 8) | frame_data[5]) * 10);
+6 -2
View File
@@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
文件名称 : chrg_north.h 文件名称 : chrg_north.h
完成日期 : 完成日期 :
当前版本号 : V1.1.19 当前版本号 : V1.1.21
主要功能 : 实现北向通信交互,包括接收命令解析,发送请求命令,切换通路。以独立线程处理。 主要功能 : 实现北向通信交互,包括接收命令解析,发送请求命令,切换通路。以独立线程处理。
版本历史 : 创建原始版本 版本历史 : 创建原始版本
说明 : 说明 :
@@ -28,11 +28,15 @@
#endif #endif
/* 南向COM批次中单通道连续收到有效回码后的最大发送条数。 */ /* 南向COM批次中单通道连续收到有效回码后的最大发送条数。 */
#define SOU_COM_BURST_MAX 8U #define SOU_COM_BURST_MAX 6U
/* 自动停止带载后,电压恢复时需要连续确认的新P1采样帧数。 */ /* 自动停止带载后,电压恢复时需要连续确认的新P1采样帧数。 */
#define SINK_LOAD_RESTART_CONFIRM_COUNT 3U #define SINK_LOAD_RESTART_CONFIRM_COUNT 3U
/* 主继电器闭合后的纹波瞬态过滤参数,单位为新的P1采样帧。 */
#define RIPPLE_RELAY_IGNORE_P1_COUNT 5U
#define RIPPLE_MEDIAN_WINDOW_SIZE 3U
#define THR_NAME_NORTH "thr.nor" #define THR_NAME_NORTH "thr.nor"
#define DEV_NAME_NORTH "uart3" #define DEV_NAME_NORTH "uart3"
+17 -1
View File
@@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
文件名称 : chrg_roll_sou.c 文件名称 : chrg_roll_sou.c
完成日期 : 完成日期 :
当前版本号 : V1.1.14 当前版本号 : V1.1.22
主要功能 : 实现南向通信轮巡请求命令。以独立线程处理。 主要功能 : 实现南向通信轮巡请求命令。以独立线程处理。
版本历史 : 创建原始版本 版本历史 : 创建原始版本
说明 : 说明 :
@@ -619,6 +619,13 @@ static int sou_com_batch_complete(rt_uint8_t ch, rt_uint16_t reg, rt_uint16_t va
} }
pBatch->cur_idx++; pBatch->cur_idx++;
if ((reg == REG_REL_ON) &&
(((value & MAIN_REL_ON) != 0U) || (value == FU_REL_ON))) {
chrg_eload_ripple_filter_relay_start(ch);
}
if ((reg == REG_WORK) && (value == WORK_STOP)) {
chrg_eload_ripple_filter_relay_stop(ch);
}
/* 暂时关闭副继电器与主继电器之间的固定延时;需要恢复时重新启用本段。 */ /* 暂时关闭副继电器与主继电器之间的固定延时;需要恢复时重新启用本段。 */
if ((reg == REG_REL_ON) && (value == ALL_REL_OFF) && if ((reg == REG_REL_ON) && (value == ALL_REL_OFF) &&
(pBatch->cur_idx < pBatch->reg_cnt) && (pBatch->cur_idx < pBatch->reg_cnt) &&
@@ -983,6 +990,15 @@ void chrg_roll_sou_thread_entry (void *data)
"batch changed", &retry_count[batch_ch]); "batch changed", &retry_count[batch_ch]);
} }
} else if (run != RUN_AUTO) { } else if (run != RUN_AUTO) {
if ((run == RUN_LCD) && (single_reg == REG_REL_ON) &&
(((single_value & MAIN_REL_ON) != 0U) ||
(single_value == FU_REL_ON))) {
chrg_eload_ripple_filter_relay_start(single_ch);
}
if ((run == RUN_LCD) && (single_reg == REG_WORK) &&
(single_value == WORK_STOP)) {
chrg_eload_ripple_filter_relay_stop(single_ch);
}
sou_single_command_finish(run); sou_single_command_finish(run);
} else { } else {
if (version_probe) { if (version_probe) {
@@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
文件名称 : chrg_roll_sou.h 文件名称 : chrg_roll_sou.h
完成日期 : 完成日期 :
当前版本号 : V1.0 当前版本号 : V1.1.21
主要功能 : 实现南向通信轮巡请求命令。以独立线程处理。 主要功能 : 实现南向通信轮巡请求命令。以独立线程处理。
版本历史 : 创建原始版本 版本历史 : 创建原始版本
说明 : 说明 :
+115 -7
View File
@@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
文件名称 : chrg_eload.c 文件名称 : chrg_eload.c
完成日期 : 完成日期 :
当前版本号 : V1.0 当前版本号 : V1.1.22
主要功能 : 源载命令数据解析,封装,读写请求。 主要功能 : 源载命令数据解析,封装,读写请求。
版本历史 : 创建原始版本 版本历史 : 创建原始版本
说明 : 说明 :
@@ -20,6 +20,14 @@
#include "chrg_south.h" #include "chrg_south.h"
#define ELOAD_VALID_VOLTAGE_MIN_MV 2000U #define ELOAD_VALID_VOLTAGE_MIN_MV 2000U
#define DPDM_HOST_READ_SCALE 10U
static rt_uint16_t chrg_eload_dpdm_host_value(rt_uint16_t value)
{
rt_uint32_t scaled_value = (rt_uint32_t)value * DPDM_HOST_READ_SCALE;
return (scaled_value > 0xFFFFU) ? 0xFFFFU : (rt_uint16_t)scaled_value;
}
extern void LCD_SHOW(rt_uint8_t idx, struct eload_p1_t *pP1, struct chrg_eload_t *pLOAD, struct chrg_switch_t *pSW, rt_uint8_t online); extern void LCD_SHOW(rt_uint8_t idx, struct eload_p1_t *pP1, struct chrg_eload_t *pLOAD, struct chrg_switch_t *pSW, rt_uint8_t online);
@@ -41,9 +49,104 @@ rt_uint32_t chrg_eload_get_sample_seq(rt_uint8_t idx)
} }
return g_eload_sample_seq[idx]; return g_eload_sample_seq[idx];
} }
static rt_uint16_t ripple_base[TOTAL_SOU_CHS] = {0}; typedef struct {
static rt_uint8_t ripple_cal_flag[TOTAL_SOU_CHS] = {0}; rt_uint16_t samples[RIPPLE_MEDIAN_WINDOW_SIZE];
rt_uint16_t real_ripple[TOTAL_SOU_CHS] = {0}; rt_uint16_t filtered_value;
rt_uint8_t sample_count;
rt_uint8_t sample_next;
rt_uint8_t ignore_count;
rt_uint8_t ignore_total;
rt_tick_t relay_start_tick;
rt_uint32_t frame_count;
rt_bool_t relay_started;
} chrg_ripple_filter_t;
static chrg_ripple_filter_t g_ripple_filter[TOTAL_SOU_CHS] = {0};
static rt_uint16_t chrg_eload_ripple_median(rt_uint16_t value0,
rt_uint16_t value1, rt_uint16_t value2)
{
if (value0 > value1) {
rt_uint16_t temp = value0;
value0 = value1;
value1 = temp;
}
if (value1 > value2) {
rt_uint16_t temp = value1;
value1 = value2;
value2 = temp;
}
if (value0 > value1) {
value1 = value0;
}
return value1;
}
static rt_uint16_t chrg_eload_ripple_filter_update(rt_uint8_t idx,
rt_uint16_t raw_value)
{
chrg_ripple_filter_t *pFilter = &g_ripple_filter[idx];
pFilter->frame_count++;
if (pFilter->ignore_count > 0U) {
pFilter->ignore_count--;
return pFilter->filtered_value;
}
pFilter->samples[pFilter->sample_next] = raw_value;
pFilter->sample_next = (pFilter->sample_next + 1U) % RIPPLE_MEDIAN_WINDOW_SIZE;
if (pFilter->sample_count < RIPPLE_MEDIAN_WINDOW_SIZE) {
pFilter->sample_count++;
}
if (pFilter->sample_count < RIPPLE_MEDIAN_WINDOW_SIZE) {
pFilter->filtered_value = raw_value;
} else {
pFilter->filtered_value = chrg_eload_ripple_median(
pFilter->samples[0], pFilter->samples[1], pFilter->samples[2]);
}
return pFilter->filtered_value;
}
void chrg_eload_ripple_filter_reset(rt_uint8_t idx)
{
chrg_ripple_filter_t *pFilter;
if (idx >= TOTAL_SOU_CHS) {
return;
}
pFilter = &g_ripple_filter[idx];
pFilter->sample_count = 0U;
pFilter->sample_next = 0U;
pFilter->ignore_count = (rt_uint8_t)RIPPLE_RELAY_IGNORE_P1_COUNT;
pFilter->ignore_total = pFilter->ignore_count;
}
void chrg_eload_ripple_filter_relay_start(rt_uint8_t idx)
{
chrg_ripple_filter_t *pFilter;
if (idx >= TOTAL_SOU_CHS) {
return;
}
pFilter = &g_ripple_filter[idx];
chrg_eload_ripple_filter_reset(idx);
pFilter->relay_start_tick = rt_tick_get();
pFilter->frame_count = 0U;
pFilter->relay_started = RT_TRUE;
}
void chrg_eload_ripple_filter_relay_stop(rt_uint8_t idx)
{
chrg_ripple_filter_t *pFilter;
if (idx >= TOTAL_SOU_CHS) {
return;
}
pFilter = &g_ripple_filter[idx];
pFilter->relay_started = RT_FALSE;
pFilter->relay_start_tick = 0U;
pFilter->frame_count = 0U;
}
/* ======================== Ymodem 升级应答缓存 ======================== */ /* ======================== Ymodem 升级应答缓存 ======================== */
static rt_uint8_t g_eload_ymodem_resp = 0; // 南向返回的ymodem应答字节(0=无应答) static rt_uint8_t g_eload_ymodem_resp = 0; // 南向返回的ymodem应答字节(0=无应答)
@@ -360,7 +463,8 @@ int chrg_eload_parse (rt_uint8_t idx, rt_uint8_t pt, rt_uint8_t *data, rt_uint16
pLOAD->vpkp = swap_u16(pP1->Vpkp); pLOAD->vpkp = swap_u16(pP1->Vpkp);
pLOAD->vpkn = swap_u16(pP1->Vpkn); pLOAD->vpkn = swap_u16(pP1->Vpkn);
pLOAD->vpp = swap_u16(pP1->Vpp); pLOAD->vpp = swap_u16(pP1->Vpp);
pLOAD->Ripple = swap_u16(pP1->Ripple); pLOAD->Ripple = chrg_eload_ripple_filter_update(idx,
swap_u16(pP1->Ripple));
/* 保留功率板返回的真实电流,供卸载保护判断使用。 */ /* 保留功率板返回的真实电流,供卸载保护判断使用。 */
pSW->Now_current = pLOAD->current; pSW->Now_current = pLOAD->current;
/* /*
@@ -374,6 +478,7 @@ int chrg_eload_parse (rt_uint8_t idx, rt_uint8_t pt, rt_uint8_t *data, rt_uint16
pLOAD->vpkn = 0; pLOAD->vpkn = 0;
pLOAD->vpp = 0; pLOAD->vpp = 0;
pLOAD->Ripple = 0; pLOAD->Ripple = 0;
chrg_eload_ripple_filter_reset(idx);
pSW->VZ = 0; pSW->VZ = 0;
pSW->VF = 0; pSW->VF = 0;
} }
@@ -415,8 +520,11 @@ int chrg_eload_parse (rt_uint8_t idx, rt_uint8_t pt, rt_uint8_t *data, rt_uint16
usRegHoldBuf[HOLD_REG_CH0_VPKN+idx*TOTAL_HOLD_CH_REGS] = pLOAD->vpkn; usRegHoldBuf[HOLD_REG_CH0_VPKN+idx*TOTAL_HOLD_CH_REGS] = pLOAD->vpkn;
usRegHoldBuf[HOLD_REG_CH0_VPP+idx*TOTAL_HOLD_CH_REGS] = pLOAD->vpp; usRegHoldBuf[HOLD_REG_CH0_VPP+idx*TOTAL_HOLD_CH_REGS] = pLOAD->vpp;
usRegHoldBuf[HOLD_REG_CH0_Ripple+idx*TOTAL_HOLD_CH_REGS] = pLOAD->Ripple; usRegHoldBuf[HOLD_REG_CH0_Ripple+idx*TOTAL_HOLD_CH_REGS] = pLOAD->Ripple;
usRegHoldBuf[HOLD_REG_CH0_VZ+idx*TOTAL_HOLD_CH_REGS] = pSW->VZ; /* 上位机D+/D-寄存器按0.001V解释,内部/LCD仍保持0.01V原始值。 */
usRegHoldBuf[HOLD_REG_CH0_VF+idx*TOTAL_HOLD_CH_REGS] = pSW->VF; usRegHoldBuf[HOLD_REG_CH0_VZ+idx*TOTAL_HOLD_CH_REGS] =
chrg_eload_dpdm_host_value(pSW->VZ);
usRegHoldBuf[HOLD_REG_CH0_VF+idx*TOTAL_HOLD_CH_REGS] =
chrg_eload_dpdm_host_value(pSW->VF);
// rt_kprintf("---------NOW VOLT END = %d\n----------",pSW->Now_voltage); // rt_kprintf("---------NOW VOLT END = %d\n----------",pSW->Now_voltage);
return 0; return 0;
} }
+4 -1
View File
@@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
文件名称 : chrg_eload.h 文件名称 : chrg_eload.h
完成日期 : 完成日期 :
当前版本号 : V1.0 当前版本号 : V1.1.22
主要功能 : 源载命令数据解析,封装,读写请求,寄存器定义,数据结构定义。 主要功能 : 源载命令数据解析,封装,读写请求,寄存器定义,数据结构定义。
版本历史 : 创建原始版本 版本历史 : 创建原始版本
说明 : 说明 :
@@ -299,6 +299,9 @@ extern int chrg_eload_parse_version (rt_uint8_t idx, rt_uint8_t *data, rt_uint16
其它说明: 每成功解析一帧P1数据后递增,用于区分控制命令前后的新旧量测 其它说明: 每成功解析一帧P1数据后递增,用于区分控制命令前后的新旧量测
*****************************************************************/ *****************************************************************/
extern rt_uint32_t chrg_eload_get_sample_seq(rt_uint8_t idx); extern rt_uint32_t chrg_eload_get_sample_seq(rt_uint8_t idx);
extern void chrg_eload_ripple_filter_reset(rt_uint8_t idx);
extern void chrg_eload_ripple_filter_relay_start(rt_uint8_t idx);
extern void chrg_eload_ripple_filter_relay_stop(rt_uint8_t idx);
// 定义2条继电器指令,控制主继电器和滤波继电器(保留原有有效指令,移除未使用的停止指令) // 定义2条继电器指令,控制主继电器和滤波继电器(保留原有有效指令,移除未使用的停止指令)
static const rt_uint8_t EXTRA_CMD_SOURCE[8] = {0x03, 0x06, 0x00, 0x01, 0x00, 0x01, 0x18, 0x28}; static const rt_uint8_t EXTRA_CMD_SOURCE[8] = {0x03, 0x06, 0x00, 0x01, 0x00, 0x01, 0x18, 0x28};
extern int chrg_eload_send_relay(rt_uint8_t cmd_type); extern int chrg_eload_send_relay(rt_uint8_t cmd_type);
+99 -32
View File
@@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
文件名称 : chrg_sink.c 文件名称 : chrg_sink.c
完成日期 : 完成日期 :
当前版本号 : V1.1.19 当前版本号 : V1.1.21
主要功能 : 北向数据sink请求数据填充及发送。 主要功能 : 北向数据sink请求数据填充及发送。
版本历史 : 创建原始版本 版本历史 : 创建原始版本
说明 : 说明 :
@@ -24,6 +24,15 @@
#define SINK_UNLOAD_CURRENT_MAX_MA 200U // 判定负载已安全卸载的最大实际电流 #define SINK_UNLOAD_CURRENT_MAX_MA 200U // 判定负载已安全卸载的最大实际电流
#define SINK_UNLOAD_CONFIRM_COUNT 2U // 连续满足低电流条件的量测帧数 #define SINK_UNLOAD_CONFIRM_COUNT 2U // 连续满足低电流条件的量测帧数
#define SINK_SHORT_KEEPALIVE_MS 30U // 短路测试WORK_START保活下发周期 #define SINK_SHORT_KEEPALIVE_MS 30U // 短路测试WORK_START保活下发周期
#define SINK_INIT_NORTH_RELAY_DELAY_MS 30U // 辅助继电器回码后打开北向继电器的等待时间
#define SINK_INIT_STAGE_CLEAR_RELAY 0U
#define SINK_INIT_STAGE_AUX_RELAY 1U
#define SINK_INIT_STAGE_DELAY 2U
#define SINK_INIT_STAGE_REST 3U
static rt_uint8_t g_sink_init_stage[TOTAL_SOU_CHS] = {0};
static rt_tick_t g_sink_init_north_relay_tick[TOTAL_SOU_CHS] = {0};
/* 主继电器闭合跟踪:1=已提交ALL_REL_ON(主继电器应已闭合) 0=未闭合/已断开。 /* 主继电器闭合跟踪:1=已提交ALL_REL_ON(主继电器应已闭合) 0=未闭合/已断开。
* 用于0V硬保护区分"首次开载/握手恢复"(主继电器未闭合,Now_voltage=0属正常) * 用于0V硬保护区分"首次开载/握手恢复"(主继电器未闭合,Now_voltage=0属正常)
@@ -241,31 +250,12 @@ int sink_set_pd (rt_uint8_t pd, rt_uint8_t *buf)
return chrg_north_send(frame, len); return chrg_north_send(frame, len);
} }
/***************************************************************** static rt_uint8_t chrg_sink_init_build_commands(struct chrg_switch_t *pSW,
函数名称: chrg_sink_work_init rt_uint16_t *regs, rt_uint16_t *vals)
函数描述: 执行负载INIT入口,将副继电器和初始化命令按顺序提交南向
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
输出参数: 立即打开北向Sink继电器和enable,并进入INIT_AUX_WAIT后台确认
返回说明: 0:初始化批次提交成功 <0:参数或命令提交失败
其它说明: 南向顺序为FU_REL_ON、CURRENT=0、MODE、VON和可选测试停止;
北向按“CC线->协议->电压查询”顺序执行,南北向从批次入队后并行执行
*****************************************************************/
static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
{ {
struct chrg_north_t *pNOR = &chrgnorth;
rt_uint16_t regs[6];
rt_uint16_t vals[6];
rt_bool_t first_start;
rt_uint8_t count; rt_uint8_t count;
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
return -1;
}
/* COM进入INIT前已经设置On_work,使用原工作状态区分首次提交和后台重试。 */
first_start = (pSW->sink.work_mode != SINK_WORK_INIT_AUX_WAIT) ?
RT_TRUE : RT_FALSE;
if (pSW->sink.test.test_mode_old == SINK_TEST_SHORT) { if (pSW->sink.test.test_mode_old == SINK_TEST_SHORT) {
/* 短路测试退出:先断开全部继电器,再打开辅助继电器,最后停止短路测试。 */
regs[0] = REG_REL_ON; vals[0] = ALL_REL_OFF; regs[0] = REG_REL_ON; vals[0] = ALL_REL_OFF;
regs[1] = REG_REL_ON; vals[1] = FU_REL_ON; regs[1] = REG_REL_ON; vals[1] = FU_REL_ON;
regs[2] = REG_CURRENT_OUT + 1; vals[2] = 0; regs[2] = REG_CURRENT_OUT + 1; vals[2] = 0;
@@ -289,18 +279,70 @@ static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
vals[count++] = ModbusRTU_DYNA_CMD_MODE_STOP; vals[count++] = ModbusRTU_DYNA_CMD_MODE_STOP;
} }
} }
if (chrg_sou_com_batch_submit(idx, regs, vals, count) != 0) { return count;
}
static int chrg_sink_init_submit_stage(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW)
{
rt_uint16_t regs[6];
rt_uint16_t vals[6];
rt_uint8_t total;
rt_uint8_t start;
rt_uint8_t count;
rt_bool_t short_exit;
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
return -1;
}
total = chrg_sink_init_build_commands(pSW, regs, vals);
short_exit = (pSW->sink.test.test_mode_old == SINK_TEST_SHORT) ?
RT_TRUE : RT_FALSE;
switch (g_sink_init_stage[idx]) {
case SINK_INIT_STAGE_CLEAR_RELAY:
start = 0U;
count = 1U;
break;
case SINK_INIT_STAGE_AUX_RELAY:
start = short_exit ? 1U : 0U;
count = 1U;
break;
case SINK_INIT_STAGE_REST:
start = short_exit ? 2U : 1U;
count = (rt_uint8_t)(total - start);
break;
default:
return -1;
}
return chrg_sou_com_batch_submit(idx, &regs[start], &vals[start], count);
}
/*****************************************************************
函数名称: chrg_sink_work_init
函数描述: 执行负载INIT入口,先提交辅助继电器命令
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
输出参数: 进入INIT_AUX_WAIT后台等待辅助继电器回码
返回说明: 0:初始化命令提交成功 <0:参数或命令提交失败
其它说明: 收到01 02有效回码后等待30ms,再打开北向Sink继电器
*****************************************************************/
static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
{
rt_bool_t short_exit;
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
return -1;
}
short_exit = (pSW->sink.test.test_mode_old == SINK_TEST_SHORT) ?
RT_TRUE : RT_FALSE;
g_sink_init_stage[idx] = short_exit ? SINK_INIT_STAGE_CLEAR_RELAY :
SINK_INIT_STAGE_AUX_RELAY;
g_sink_init_north_relay_tick[idx] = 0U;
if (chrg_sink_init_submit_stage(idx, pSW) != 0) {
return -1; return -1;
} }
pSW->sink.On_work = 1; pSW->sink.On_work = 1;
if (first_start) {
/* 南向批次已入队,北向按“CC->协议”顺序立即开始完整握手。 */
chrg_nor_sw_rel((eIDX_NOR_CH)idx, ID_SINK);
pNOR->enable[idx] = 1;
/* Protocol-before-CC test flow is disabled in this version. */
pSW->sub = IDX_SET_SINK_CC_BEFORE_PD;
}
pSW->sink.work_mode = SINK_WORK_INIT_AUX_WAIT; pSW->sink.work_mode = SINK_WORK_INIT_AUX_WAIT;
return 0; return 0;
} }
@@ -316,6 +358,7 @@ static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
static int chrg_sink_work_init_aux_wait(eIDX_SOU_CH idx, static int chrg_sink_work_init_aux_wait(eIDX_SOU_CH idx,
struct chrg_switch_t *pSW) struct chrg_switch_t *pSW)
{ {
struct chrg_north_t *pNOR = &chrgnorth;
struct chrg_south_t *pSOU = &chrgsouth; struct chrg_south_t *pSOU = &chrgsouth;
int batch_result; int batch_result;
@@ -325,10 +368,34 @@ static int chrg_sink_work_init_aux_wait(eIDX_SOU_CH idx,
if (chrg_sou_com_batch_is_pending(idx)) { if (chrg_sou_com_batch_is_pending(idx)) {
return 0; return 0;
} }
if (g_sink_init_stage[idx] == SINK_INIT_STAGE_DELAY) {
if ((rt_int32_t)(rt_tick_get() -
g_sink_init_north_relay_tick[idx]) < 0) {
return 0;
}
chrg_nor_sw_rel((eIDX_NOR_CH)idx, ID_SINK);
rt_kprintf("-------D+D- OPEN------\n");
pNOR->enable[idx] = 1;
pSW->sub = IDX_SET_SINK_CC_BEFORE_PD;
g_sink_init_stage[idx] = SINK_INIT_STAGE_REST;
if (chrg_sink_init_submit_stage(idx, pSW) != 0) {
return -1;
}
return 0;
}
batch_result = chrg_sou_com_batch_get_result(idx); batch_result = chrg_sou_com_batch_get_result(idx);
if (batch_result <= 0) { if (batch_result <= 0) {
/* 北向保持当前事务,南向独立重试完整初始化批次。 */ return chrg_sink_init_submit_stage(idx, pSW);
return chrg_sink_work_init(idx, pSW); }
if (g_sink_init_stage[idx] == SINK_INIT_STAGE_CLEAR_RELAY) {
g_sink_init_stage[idx] = SINK_INIT_STAGE_AUX_RELAY;
return chrg_sink_init_submit_stage(idx, pSW);
}
if (g_sink_init_stage[idx] == SINK_INIT_STAGE_AUX_RELAY) {
g_sink_init_stage[idx] = SINK_INIT_STAGE_DELAY;
g_sink_init_north_relay_tick[idx] = rt_tick_get() +
rt_tick_from_millisecond(SINK_INIT_NORTH_RELAY_DELAY_MS);
return 0;
} }
/* 北向可能已推进到CC或电压查询,此处只更新南向完成状态。 */ /* 北向可能已推进到CC或电压查询,此处只更新南向完成状态。 */
+1 -1
View File
@@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
文件名称 : chrg_sink.c 文件名称 : chrg_sink.c
完成日期 : 完成日期 :
当前版本号 : V1.1.19 当前版本号 : V1.1.23
主要功能 : 北向数据sink请求数据填充及发送,命令字定义。 主要功能 : 北向数据sink请求数据填充及发送,命令字定义。
版本历史 : 创建原始版本 版本历史 : 创建原始版本
说明 : 说明 :
+101 -949
View File
File diff suppressed because it is too large Load Diff
+921 -2487
View File
File diff suppressed because it is too large Load Diff
+52
View File
@@ -1,5 +1,57 @@
# 修改日志 # 修改日志
## V1.1.23 - 2026-09-11
### 负载初始化继电器时序调整
- 负载初始化先单独下发辅助继电器 `FU_REL_ON (0x01 0x02)`。
- 只有收到匹配回码后,等待 `30ms` 才打开北向负载继电器。
- 北向继电器打开后,再继续下发电流、模式、V_On等初始化参数。
- 辅助继电器回码失败时只重发当前初始化阶段,不提前打开北向继电器。
- 协议板版本号更新为 `V1.1.23`,固件版本寄存器更新为 `0x0127`。
### 待验证
- 上电初始化日志中确认先收到 `01 02`,约30ms后才出现北向继电器打开。
- 辅助继电器无回码时确认北向继电器保持关闭。
## V1.1.22 - 2026-09-11
### 增加纹波滤波调试打印
- 记录每个通道主继电器闭合的 tick 和忽略帧配置。
- 打印忽略帧的序号、原始纹波值及继电器闭合后的经过时间。
- 打印实际进入滤波的帧序号、原始值、滤波值及经过时间。
- 协议板版本号更新为 `V1.1.22`,固件版本寄存器更新为 `0x0126`。
- 待验证:确认宏调整后忽略帧数量和实际进入滤波的时间同步变化。
## V1.1.21 - 2026-09-11
### 继电器切换纹波滤波
- 主继电器闭合回码成功后,忽略 `RIPPLE_RELAY_IGNORE_P1_COUNT` 个新P1采样帧;当前值为 `2U`,可在 `chrg_north.h` 中调整。
- 后续纹波持续使用三点中值滤波,滤除单帧尖峰;连续异常纹波仍会正常显示。
- LCD和上位机纹波寄存器统一使用滤波后的纹波值。
- 协议板版本号更新为 `V1.1.21`,固件版本寄存器更新为 `0x0125`。
### 验证记录
- 待硬件验证:继电器闭合瞬间出现约500mV尖峰时,LCD和上位机不显示该尖峰;忽略2帧后再累计3帧并更新为稳定纹波。
- 待硬件验证:持续三帧以上的高纹波仍能在LCD和上位机显示。
## V1.1.20 - 2026-09-10
### D+/D-上位机显示单位修正
- 上位机读取各通道 `D+`、`D-` 保持寄存器时,返回值由内部原始值放大 `10` 倍,适配上位机按 `0.001V` 解析。
- LCD显示、北向回码解析及内部控制值保持原有 `0.01V` 单位,不受影响。
- 增加16位寄存器上限保护,放大结果超过 `65535` 时返回 `65535`。
- 协议板版本号更新为 `V1.1.20`,固件版本寄存器更新为 `0x0124`。
### 验证记录
- 待硬件验证:D+或D-内部值为 `260` 时,LCD继续显示 `2.60V`,上位机读取值为 `2600` 并显示 `2.600V`。
## V1.1.19 - 2026-09-10 ## V1.1.19 - 2026-09-10
### 短路测试绕过 V_ON 门槛 ### 短路测试绕过 V_ON 门槛
+15
View File
@@ -20,6 +20,21 @@
- 上位机必须从偏移 0 开始以 `STX/1024` 发送;第一个 STX 是头区,真正 body 从第二个 STX 开始。 - 上位机必须从偏移 0 开始以 `STX/1024` 发送;第一个 STX 是头区,真正 body 从第二个 STX 开始。
- YMODEM 最后一帧的 `0x1A` 补齐仅属于传输层,不能计入文件大小、`raw_size` 或 `pkg_size`。 - YMODEM 最后一帧的 `0x1A` 补齐仅属于传输层,不能计入文件大小、`raw_size` 或 `pkg_size`。
### YMODEM 1K 帧字节数
`STX/1024` 中的 `1024` 指数据区长度,不是串口线上完整帧长度。每个完整 STX 数据帧固定为 **1029 字节**:
```text
STX 1 字节
PacketNo 1 字节
~PacketNo 1 字节
Data 1024 字节
CRC16 2 字节
总计 1029 字节
```
因此,UPK 首数据块和后续固件数据块的有效数据均为 1024 字节,实际串口发送时均应连续发送 1029 字节。YMODEM 元数据使用 SOH 帧,完整帧为 133 字节(128 字节数据区 + 5 字节控制/校验字段)。
界面中的“表头尺寸 `1024 (ymodem1k)`”应改名为“YMODEM 首数据块/头区尺寸”,并固定为 1024;UPK 逻辑头固定为 96,不能让用户修改。 界面中的“表头尺寸 `1024 (ymodem1k)`”应改名为“YMODEM 首数据块/头区尺寸”,并固定为 1024;UPK 逻辑头固定为 96,不能让用户修改。
## 3. 输入、分区与版本 ## 3. 输入、分区与版本
@@ -56,8 +56,8 @@ CRC 覆盖 `Data` 的全部固定长度字节(128 或 1024),并按 **高
1. 元数据包必须使用 `SOH`,`PacketNo=0x00`,反码为 `0xFF`。 1. 元数据包必须使用 `SOH`,`PacketNo=0x00`,反码为 `0xFF`。
2. 首个文件数据包使用 `PacketNo=0x01`;每得到 ACK 后序号加 1,按 8 位自然回绕。 2. 首个文件数据包使用 `PacketNo=0x01`;每得到 ACK 后序号加 1,按 8 位自然回绕。
3. 本 Boot 的 `.upk` 使用 1K 首数据块布局,因此文件数据包必须使用 `STX`(1024 字节);最后一包不足 1024 字节时仍应补齐到 1024 字节,建议补 `0x1A`。 3. 本 Boot 的 `.upk` 使用 1K 首数据块布局,因此文件数据包必须使用 `STX`(1024 字节);最后一包不足 1024 字节时仍应补齐到 1024 字节,建议补 `0x1A`。
4. Boot 校验包号、包号反码、帧长度与 CRC。任一校验失败会回复 NAK。 4. Boot 校验包号、包号反码、帧长度与 CRC。任一校验失败会立即回复 NAK;当前 Boot 随后会重置 YMODEM 包号和流程。
5. 收到 NAK 时,必须重发**原完整帧**,包号不得递增。该 Boot 不将“前一帧重复包”当作成功帧,因此不能依赖重复包自动 ACK。 5. 对于业务层处理失败产生的 NAK,可以重发**原完整帧**,包号不得递增。对于 CRC、包号或帧长度错误产生的 NAK,不能只重发当前帧,必须重新进入 Boot 并从元数据包开始完整传输。
## 5. 元数据包规则 ## 5. 元数据包规则
@@ -171,7 +171,7 @@ WAIT_END_ACK
| 事件 | 上位机处理 | | 事件 | 上位机处理 |
| --- | --- | | --- | --- |
| 收到 ACK | 仅推进到下一协议状态;数据包 ACK 后才递增包号 | | 收到 ACK | 仅推进到下一协议状态;数据包 ACK 后才递增包号 |
| 收到明确 NAK | 重发当前完整帧;建议最多连续 3 次 | | 收到明确 NAK | 业务层 NAK 可重发当前完整帧;协议校验 NAK 应重新进入 Boot,从元数据包开始传输 |
| 等待 ACK 超时 | 标记“传输结果不确定”,停止本次会话;重新进入 Boot 后从元数据包开始完整传输 | | 等待 ACK 超时 | 标记“传输结果不确定”,停止本次会话;重新进入 Boot 后从元数据包开始完整传输 |
| 明确 NAK 重发耗尽 | 发送 CAN 两次,标记升级传输失败 | | 明确 NAK 重发耗尽 | 发送 CAN 两次,标记升级传输失败 |
| 收到 CAN | 立即停止,标记 Boot 取消升级 | | 收到 CAN | 立即停止,标记 Boot 取消升级 |
@@ -180,7 +180,7 @@ WAIT_END_ACK
Boot 对单个 CAN 会进入取消流程并回 ACK;上位机仍建议按标准发送两个 CAN,并接受可能出现的 ACK。 Boot 对单个 CAN 会进入取消流程并回 ACK;上位机仍建议按标准发送两个 CAN,并接受可能出现的 ACK。
> **当前 Boot 的可靠性限制:** 成功接收一个数据包后,Boot 已把期望包号加一;若该包的 ACK 在串口上丢失,上位机重发同一包会被 Boot 判为“重复包”并回复 NAK,而不是再次回复 ACK。因此“ACK 超时后无条件重发当前包”不能可靠恢复。本文规则可在直连、稳定的串口环境中正常升级;若要支持 ACK 丢失后的可靠自动重发,需要修改 Boot,使其收到“期望包号减一”的重复帧且 CRC 正确时直接回复 ACK、不再次写入数据。 > **当前 Boot 的可靠性限制:** 成功接收一个数据包后,Boot 已把期望包号加一;若该包的 ACK 在串口上丢失,上位机重发同一包会被 Boot 判为“重复包”并回复 NAK,同时触发 YMODEM 重置。因此“ACK 超时后无条件重发当前包”不能可靠恢复,必须重新进入 Boot 并从元数据包开始传输。若要支持当前会话内的可靠自动重发,需要修改 Boot,使其保留期望包号,并对 CRC 正确的重复帧直接回复 ACK、不再次写入数据。
`WAIT_*_ACK` 的建议超时为 3~10 秒,元数据后的 `WAIT_C_DATA`、结束阶段的 `WAIT_C_END` 建议为 10 秒。上位机可将串口接收设计为持续缓存并按字节解析,忽略调试文本或仅识别 `C/ACK/NAK/CAN` 控制字符,避免因分段到达造成误判。 `WAIT_*_ACK` 的建议超时为 3~10 秒,元数据后的 `WAIT_C_DATA`、结束阶段的 `WAIT_C_END` 建议为 10 秒。上位机可将串口接收设计为持续缓存并按字节解析,忽略调试文本或仅识别 `C/ACK/NAK/CAN` 控制字符,避免因分段到达造成误判。