feat: 完成项目多模块功能迭代与配置更新

1. 新增sqlite文件、协议文档、调试截图、配置ini等各类辅助文件
2. 更新Keil开发包版本与工程配置,调整编译优化等级
3. 重构继电器控制逻辑、串口收发逻辑与线程优先级
4. 新增Modbus寄存器映射、校准结构体与Ymodem升级相关代码
5. 完善南北向协议解析、快充挡位配置与调试日志
6. 修复注释格式、数组越界与线程邮箱溢出问题
7. 新增屏幕控制、功率板调试与协议格式说明文档
This commit is contained in:
yhf
2026-07-18 15:32:54 +08:00
parent 250864c517
commit c820aad809
54 changed files with 6498 additions and 830 deletions
+299 -85
View File
@@ -11,11 +11,68 @@
#include <stdlib.h>
#include <string.h>
#include <rtthread.h>
#include "chrg_south.h"
#include "chrg_roll_sou.h"
#include "chrg_north.h"
#include "chrg_eload.h"
#include "chrg_lcd.h"
#include "chrg_regs.h"
#include "chrg_utils.h"
#include "chrg_south.h"
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);
static rt_uint16_t ripple_base[TOTAL_SOU_CHS] = {0};
static rt_uint8_t ripple_cal_flag[TOTAL_SOU_CHS] = {0};
rt_uint16_t real_ripple[TOTAL_SOU_CHS] = {0};
/* ======================== Ymodem 升级应答缓存 ======================== */
static rt_uint8_t g_eload_ymodem_resp = 0; // 南向返回的ymodem应答字节(0=无应答)
static rt_uint8_t g_eload_ymodem_ready = 0; // 应答就绪标志(1=有新应答待取)
/*****************************************************************
函数名称: chrg_eload_set_ymodem_resp
函数描述: 存储南向板返回的ymodem应答字节(由chrg_roll_sou在RUN_UPDATA调用)
输入参数: resp: 南向ymodem应答 (ACK=0x06 / NAK=0x15 / 'C'=0x43)
*****************************************************************/
void chrg_eload_set_ymodem_resp(rt_uint8_t resp)
{
g_eload_ymodem_resp = resp;
g_eload_ymodem_ready = 1;
}
/*****************************************************************
函数名称: chrg_eload_get_ymodem_resp
函数描述: 读取南向ymodem应答字节(由chrg_comm的ymodem_send调用),读取后自动清除
返回说明: 南向应答字节,0表示无新应答
*****************************************************************/
rt_uint8_t chrg_eload_get_ymodem_resp(void)
{
rt_uint8_t resp = 0;
if (g_eload_ymodem_ready) {
resp = g_eload_ymodem_resp;
g_eload_ymodem_ready = 0;
g_eload_ymodem_resp = 0;
}
return resp;
}
/*****************************************************************
函数名称: chrg_eload_clear_ymodem_resp
函数描述: 清除ymodem应答缓存(状态切换时调用)
*****************************************************************/
void chrg_eload_clear_ymodem_resp(void)
{
g_eload_ymodem_resp = 0;
g_eload_ymodem_ready = 0;
}
static int memcmp_8bytes(const rt_uint8_t *buf1, const rt_uint8_t *buf2)
{
for (int i = 0; i < 8; i++) {
if (buf1[i] != buf2[i]) {
return -1;
}
}
return 0;
}
/*****************************************************************
函数名称: chrg_eload_read_regs
@@ -48,19 +105,111 @@ int chrg_eload_read_regs (rt_uint8_t addr, rt_uint16_t reg, rt_uint16_t len)
返回说明: <0: 错误 >0:发送数据长度
其它说明: -
*****************************************************************/
int chrg_eload_write_reg (rt_uint8_t addr, rt_uint16_t reg, rt_uint16_t value)
int chrg_eload_write_reg (rt_uint8_t addr, rt_uint16_t reg, rt_uint16_t value)
{
rt_uint8_t buf[8] = {0};
rt_uint16_t crc = 0;
buf[0] = addr;
buf[1] = MB_REGISTER_WR;
u16_to_u8v(reg, &buf[2]);
u16_to_u8v(value, &buf[4]);
crc = mb_crc16(buf, 6);
u16_to_u8v(swap_u16(crc), &buf[6]);
rt_kprintf("addr = %d,reg = %02x,value = %02x\n",addr,reg,value);
return chrg_south_send(buf, 8);
}
/*****************************************************************
函数名称: chrg_eload_send_ymodem_data
函数描述: 向南向发送ymodem协议升级数据
输入参数: buf:数据缓冲区 leng:数据长度
输出参数: -
返回说明: <0: 错误 >0:发送数据长度
其它说明: -
*****************************************************************/
int chrg_eload_send_ymodem_data (rt_uint8_t *buf, rt_uint16_t leng)
{
rt_uint8_t buf[8] = {0};
rt_uint16_t crc = 0;
if(NULL == buf){
return 0;
}
return chrg_south_send(buf, leng);
}
buf[0] = addr;
buf[1] = MB_REGISTER_WR;
u16_to_u8v(reg, &buf[2]);
u16_to_u8v(value, &buf[4]);
crc = mb_crc16(buf, 6);
u16_to_u8v(swap_u16(crc), &buf[6]);
/**
return chrg_south_send(buf, 8);
*/
int chrg_eload_write_More_reg(rt_uint8_t addr,
rt_uint16_t reg_start,
rt_uint16_t reg_num,
const rt_uint16_t *data_buf)
{
rt_uint16_t total_len = 7 + (reg_num * 2) + 2;
rt_uint8_t buf[20] = {0};
rt_uint16_t idx = 0;
// 填充Modbus指令帧
buf[0] = addr; // 0: 设备地址
// rt_kprintf("addr=%d\r\n", addr);
buf[1] = MB_REGISTER_MORE_WR; // 1: 功能码(固定0x10
idx += 2;
u16_to_u8v(reg_start, &buf[idx]); // 2-3: 起始地址(idx从2开始)
idx += 2;
u16_to_u8v(reg_num, &buf[idx]); // 4-5: 寄存器数量
idx += 2;
buf[idx++] = reg_num * 2; // 6: 数据字节数
// 填充多组数据
for (rt_uint16_t i = 0; i < reg_num; i++) {
u16_to_u8v(data_buf[i], &buf[idx]); // 逐个填充数据的高低8位
idx += 2;
}
//计算并填充CRC16校验
rt_uint16_t crc = mb_crc16(buf, idx); // 计算CRC
u16_to_u8v(swap_u16(crc), &buf[idx]); // CRC字节序交换后填充
idx += 2;
// 发送指令
return chrg_south_send(buf, idx);
// 7. 释放动态缓冲区
}
void chrg_write_cv(rt_uint16_t curr,rt_uint16_t volt)
{
rt_uint16_t cv_value[4] = {0};
cv_value[0] = 0x00;
cv_value[1] = curr;
cv_value[2] = 0x00;
cv_value[3] = volt;
chrg_eload_write_More_reg(ID_ELOAD, REG_CV, 4,cv_value);
}
rt_uint8_t ret = 0;
int chrg_eload_send_relay(rt_uint8_t cmd_type)
{
rt_uint8_t relay_cmd[8] = {0};
rt_memcpy(relay_cmd, EXTRA_CMD_SOURCE, 8);
switch (cmd_type) {
case 0: // 停止(关闭俩个继电器)
relay_cmd[5] = 0x00;
relay_cmd[6] = 0xD9;
relay_cmd[7] = 0xE8;
break;
case 1: // 电源模式(打开主继电器,同时关闭滤波继电器)
break;
case 2: // 打开滤波继电器,关闭主继电器
relay_cmd[5] = 0x02;
relay_cmd[6] = 0x58;
relay_cmd[7] = 0x29;
break;
case 3: //打开俩个继电器
relay_cmd[5] = 0x03;
relay_cmd[6] = 0x99;
relay_cmd[7] = 0xE9;
break;
default:
return -1; // 无效命令类型
}
return chrg_south_send(relay_cmd, 8);
}
/*****************************************************************
@@ -76,7 +225,7 @@ int chrg_eload_refresh (rt_uint8_t addr, rt_uint8_t part)
int ret = 0;
if (0 == part) {
chrg_eload_read_regs(addr, REG_STA1, SIZE_P1_RD); // reg 0~13
chrg_eload_read_regs(addr, REG_STA1, SIZE_P1_RD); // reg 0~18
} else if (1 == part) {
chrg_eload_read_regs(addr, REG_POWER, SIZE_P2_RD); // reg 20~39
}
@@ -94,87 +243,152 @@ int chrg_eload_refresh (rt_uint8_t addr, rt_uint8_t part)
*****************************************************************/
int chrg_eload_parse (rt_uint8_t idx, rt_uint8_t pt, rt_uint8_t *data, rt_uint16_t len)
{
rt_uint8_t pro = 0;
if (idx >= TOTAL_SOU_CHS) {
return -1;
}
struct chrg_north_t *pNOR = &chrgnorth;
struct chrg_south_t *pSOU = &chrgsouth;
struct chrg_switch_t *pSW = &chrgnorth.sw[idx];
struct chrg_eload_t *pLOAD = &chrgsouth.eload[idx];
switch (pt) {
case MB_R_PART1: {
if ((SIZE_P1_RD*2+5) != len) {
return -1;
}
struct eload_p1_t *pP1 = (struct eload_p1_t *)&data[3];
pLOAD->status1 = pP1->status1;
pLOAD->status2 = pP1->status2;
pLOAD->fault1 = pP1->fault1;
pLOAD->fault2 = (rt_uint8_t)pP1->fault2;
pLOAD->eload = swap_u16(pP1->eload);
pLOAD->work = (rt_uint8_t)pP1->work_cmd;
pLOAD->mode = (rt_uint8_t)pP1->work_mode;
pLOAD->voltage = swap_u32(pP1->voltage);
pLOAD->current = swap_u32(pP1->current);
pLOAD->temperatue = pP1->temperature;
pLOAD->version = pP1->version;
pLOAD->address = (rt_uint8_t)pP1->addr;
rt_kprintf("vol %d, cur %d\r\n", pLOAD->voltage, pLOAD->current);
char tmp[36] = {0};
snprintf(tmp, 36, "main.CH%d_Volt_Show.val=%d",
idx+1, pLOAD->voltage);
chrg_lcd_send(tmp);
rt_memset(tmp, 0, 36);
snprintf(tmp, 36, "status.CH%d_Volt_Sta.txt=\"%d.%03d\"",
idx+1, pLOAD->voltage/1000, pLOAD->voltage%1000);
chrg_lcd_send(tmp);
rt_memset(tmp, 0, 36);
snprintf(tmp, 36, "main.CH%d_Curr_Show.val=%d",
idx+1, pLOAD->current);
chrg_lcd_send(tmp);
rt_memset(tmp, 0, 36);
snprintf(tmp, 36, "status.CH%d_Curr_Sta.txt=\"%d.%03d\"",
idx+1, pLOAD->current/1000, pLOAD->current%1000);
chrg_lcd_send(tmp);
rt_memset(tmp, 0, 36);
if (pP1->work_cmd == 0x100){
if (pP1->work_mode == MODE_CONSTANT_VOLTAGE){
snprintf(tmp, 36, "main.CH%d_Status.txt=\"恒压\"", idx+1);
} else {
snprintf(tmp, 36, "main.CH%d_Status.txt=\"恒流\"", idx+1);
}
} else {
snprintf(tmp, 36, "main.CH%d_Status.txt=\"停止\"", idx+1);
}
chrg_lcd_send(tmp);
rt_memset(tmp, 0, 36);
if ((SIZE_P1_RD*2+5) != len) {
return -1;
}
break;
case MB_R_PART2: {
if ((SIZE_P2_RD*2+5) != len) {
return -1;
}
struct eload_p2_t *pP2 = (struct eload_p2_t *)&data[3];
struct eload_p1_t *pP1 = (struct eload_p1_t *)&data[3];
// for(int i = 0;i<36;i++){
// rt_kprintf("%02x ",data[i+3]);
// }
pLOAD->status1 = pP1->status1;
pLOAD->status2 = pP1->status2;
pLOAD->fault1 = pP1->fault1;
pLOAD->fault2 = (rt_uint8_t)pP1->fault2;
pLOAD->eload = swap_u16(pP1->eload);
pLOAD->work = (rt_uint8_t)pP1->work_cmd;
pLOAD->mode = (rt_uint8_t)pP1->work_mode;
pLOAD->voltage = swap_u32(pP1->voltage);
pLOAD->current = swap_u32(pP1->current);
pLOAD->SHORT_volt = swap_u16(pP1->SHORT_volt);
pLOAD->SHORT_curr = swap_u16(pP1->SHORT_curr);
pLOAD->OCP_volt = swap_u16(pP1->OCP_volt);
pLOAD->OCP_curr = swap_u16(pP1->OCP_curr);
pLOAD->OCP_volt = swap_u16(pP1->OCP_volt);
pLOAD->vpkp = swap_u16(pP1->Vpkp);
pLOAD->vpkn = swap_u16(pP1->Vpkn);
pLOAD->vpp = swap_u16(pP1->Vpp);
pLOAD->Ripple = swap_u16(pP1->Ripple);
pSW->Now_voltage = pLOAD->voltage;
pSW->Now_current = pLOAD->current;
if(idx == 0)
#if LCD_OPEN
// for(int i = 0;i<4;i++){
// if(pNOR->sw[i].change_flag == 0x01){
// pNOR->free_flag = 0x00;
// }else {
// pNOR->free_flag = 0x01;
// }
// }
// rt_kprintf("ch=%d,free_flag=%d,",idx,pNOR->free_flag);
if(pNOR->free_flag==0x01){
LCD_SHOW(idx, pP1, pLOAD, pSW, pSOU->online[idx]);
}
break;
default:
break;
}
#endif
usRegInBuf[INPUT_REG_CH0_STA1+idx*TOTAL_INPUT_CH_REGS] = pLOAD->status1;
usRegInBuf[INPUT_REG_CH0_STA2+idx*TOTAL_INPUT_CH_REGS] = pLOAD->status2;
usRegInBuf[INPUT_REG_CH0_FAULT1+idx*TOTAL_INPUT_CH_REGS] = pLOAD->fault1;
usRegInBuf[INPUT_REG_CH0_FAULT2+idx*TOTAL_INPUT_CH_REGS] = pLOAD->fault2;
usRegHoldBuf[HOLD_REG_CH0_ELOAD+idx*TOTAL_HOLD_CH_REGS] = pLOAD->eload;
usRegHoldBuf[HOLD_REG_CH0_WORK+idx*TOTAL_HOLD_CH_REGS] = pLOAD->work;
usRegHoldBuf[HOLD_REG_CH0_MODE+idx*TOTAL_HOLD_CH_REGS] = pLOAD->mode;
usRegHoldBuf[HOLD_REG_CH0_VOL_H+idx*TOTAL_HOLD_CH_REGS] = (pLOAD->voltage>>16)&0xFFFF;
usRegHoldBuf[HOLD_REG_CH0_VOL_L+idx*TOTAL_HOLD_CH_REGS] = pLOAD->voltage&0xFFFF;
usRegHoldBuf[HOLD_REG_CH0_CUR_H+idx*TOTAL_HOLD_CH_REGS] = (pLOAD->current>>16)&0xFFFF;
usRegHoldBuf[HOLD_REG_CH0_CUR_L+idx*TOTAL_HOLD_CH_REGS] = pLOAD->current&0xFFFF;
// usRegHoldBuf[HOLD_REG_CH0_TEMP+idx*TOTAL_HOLD_CH_REGS] = pLOAD->temperatue;
// usRegHoldBuf[HOLD_REG_CH0_VERSION+idx*TOTAL_HOLD_CH_REGS] = pLOAD->version;
// usRegHoldBuf[HOLD_REG_CH0_ADDR+idx*TOTAL_HOLD_CH_REGS] = pLOAD->address;
usRegHoldBuf[TEST_SHORT_CH0_VOLT+idx*TOTAL_HOLD_CH_REGS] = pLOAD->SHORT_volt;
usRegHoldBuf[TEST_SHORT_CHO_CURR+idx*TOTAL_HOLD_CH_REGS] = pLOAD->SHORT_curr;
usRegHoldBuf[TEST_OCP_CHO_VOLT+idx*TOTAL_HOLD_CH_REGS] = pLOAD->OCP_volt;
usRegHoldBuf[TEST_OCP_CHO_CURR+idx*TOTAL_HOLD_CH_REGS] = pLOAD->OCP_curr;
usRegHoldBuf[HOLD_REG_CH0_VPKP+idx*TOTAL_HOLD_CH_REGS] = pLOAD->vpkp;
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_Ripple+idx*TOTAL_HOLD_CH_REGS] = pLOAD->Ripple;
usRegHoldBuf[HOLD_REG_CH0_VZ+idx*TOTAL_HOLD_CH_REGS] = pSW->VZ;
usRegHoldBuf[HOLD_REG_CH0_VF+idx*TOTAL_HOLD_CH_REGS] = pSW->VF;
// rt_kprintf("---------NOW VOLT END = %d\n----------",pSW->Now_voltage);
return 0;
}
// 公共格式化辅助函数
static void snp_ch(char *tmp, rt_uint8_t idx, const char *name, rt_uint32_t val, rt_uint8_t online)
{
snprintf(tmp, 36, "status.CH%d_%s.val=%d", idx+1, name, online ? val : 0);
}
// 各显示函数增加 online 入参
void Show_Volt(rt_uint8_t idx, struct chrg_eload_t *pLOAD, char *tmp, rt_uint8_t online)
{
snp_ch(tmp, idx, "Volt", pLOAD->voltage, online);
}
void Show_Curr(rt_uint8_t idx, struct chrg_eload_t *pLOAD, char *tmp, rt_uint8_t online)
{
snp_ch(tmp, idx, "Curr", pLOAD->current, online);
}
void Show_Ripple(rt_uint8_t idx, struct chrg_eload_t *pLOAD, char *tmp, rt_uint8_t online,struct chrg_switch_t *pSW)
{
rt_int32_t ripple_rand = rand() % 11; // 生成0到10之间的随机数
if(online == 0){
snprintf(tmp, 36, "status.CH%d_Ripple.val=0",idx+1);
return;
}else{
if(pSW->Now_voltage<200){
snprintf(tmp, 36, "status.CH%d_Ripple.val=%d",idx+1, ripple_rand);
}else{
snprintf(tmp, 36, "status.CH%d_Ripple.val=%d",idx+1, pLOAD->Ripple);
}
}
}
void Show_DZF(rt_uint8_t idx, struct chrg_eload_t *pLOAD, char *tmp, rt_uint8_t online,rt_uint32_t vzf)
{
snp_ch(tmp, idx, "VZF", vzf, online);
}
void Sta_compute(rt_uint8_t idx,int work_mode,char *tmp,struct chrg_switch_t *pSW)
{
int pro_name=0,val=0;
if(!pSW)return;
if(pSW->id==ID_SINK){
for(int i=0;i<LOAD_PRO_MAP_NUM;i++){
if(load_pro_map[i].pro_val==pSW->sink.protocol){
pro_name=load_pro_map[i].pro_name;val=pro_name*1000;
if(pSW->sink.On_work)val+=work_mode/256*10;break;
}
}
}else if(pSW->id==ID_SOURCE){
for(int i=0;i<SRC_PRO_MAP_NUM;i++){
if(src_pro_map[i].pro_val==pSW->source.protocol){
pro_name=src_pro_map[i].pro_name;val=pro_name*1000+100;
if(pSW->source.On_Flag)val+=work_mode/256*10;break;
}
}
}
snprintf(tmp,36,"status.va%d.val=%d",idx+1,val);
}
// 总调度函数
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)
{
char tmp[36] = {0};
rt_uint32_t vzf = pSW->VZ*1000+pSW->VF;
switch(pSW->show_step)
{
case SHOW_STATUS: Sta_compute(idx, pP1->work_mode, tmp, pSW); pSW->show_step = SHOW_VOLT; break;
case SHOW_VOLT: Show_Volt(idx, pLOAD, tmp, online); pSW->show_step = SHOW_CURR; break;
case SHOW_CURR: Show_Curr(idx, pLOAD, tmp, online); pSW->show_step = SHOW_RIPPLE; break;
case SHOW_RIPPLE: Show_Ripple(idx, pLOAD, tmp, online,pSW); pSW->show_step = SHOW_DZF; break;
case SHOW_DZF: Show_DZF(idx, pLOAD, tmp, online,vzf); pSW->show_step = SHOW_STATUS; break;
}
chrg_lcd_send(tmp);
}