Преглед на файлове

清理部分冗余设计

dev3
hanyongwei преди 2 седмици
родител
ревизия
5deb2ab693
променени са 9 файла, в които са добавени 1781 реда и са изтрити 1246 реда
  1. +10
    -9
      app/main.c
  2. +1673
    -966
      iar/plsr.dep
  3. +8
    -8
      modbus/modbus_rtu.c
  4. +35
    -36
      plsr/command/plsr_command.c
  5. +17
    -35
      plsr/command/plsr_command.h
  6. +22
    -131
      plsr/param/plsr_param.c
  7. +10
    -37
      plsr/param/plsr_param.h
  8. +4
    -9
      plsr/plsr.c
  9. +2
    -15
      plsr/plsr.h

+ 10
- 9
app/main.c Целия файл

@@ -75,15 +75,16 @@ int main(void)
PlsrParamBlockInit();

/* Modbus 从站任务:解析 FC03/06/10,维护保持寄存器映像 */
OSTaskCreateExt(ModbusSlaveTask,
NULL,
&ModbusTaskStk[MODBUS_TASK_STACK_SIZE - 1],
MODBUS_TASK_PRIO,
MODBUS_TASK_PRIO,
&ModbusTaskStk[0],
MODBUS_TASK_STACK_SIZE,
NULL,
OSTaskCreateExt(ModbusSlaveTask,//任务函数入口,任务实体函数
NULL,//传递给任务函数的入口参数
&ModbusTaskStk[MODBUS_TASK_STACK_SIZE - 1],//栈向下增长,栈从高地址往低地址生长
MODBUS_TASK_PRIO,//任务优先级
MODBUS_TASK_PRIO,//任务id,一般直接等于优先级;可以不等于优先级,但不能冲突
&ModbusTaskStk[0],//栈数组的起始地址,数组下标 0 的地址
MODBUS_TASK_STACK_SIZE,//栈的元素数量,不是字节数
NULL,//TCB 扩展指针
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR | OS_TASK_OPT_SAVE_FP);
//开启栈用量统计;任务创建的时候,把整个栈内存全部清零;保存 FPU 浮点寄存器

/* PLSR 主任务:TickMs / CommandPoll / 监控发布 */
OSTaskCreateExt(PlsrTask,
@@ -95,7 +96,7 @@ int main(void)
PLSR_TASK_STACK_SIZE,
NULL,
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR | OS_TASK_OPT_SAVE_FP);
//开启栈用量统计;任务创建的时候,把整个栈内存全部清零;保存 FPU 浮点寄存器
/*
* 参数块任务:Pend → ApplyFromHold(校验)→ 通过则 SaveParamsFromHold。
* 分帧写完后由 OnHoldWrite Post;Save 落 BKP,Export 仅供读回钳位结果。


+ 1673
- 966
iar/plsr.dep
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 8
- 8
modbus/modbus_rtu.c Целия файл

@@ -47,7 +47,7 @@ static void FlushUartRx(void);
static void RestartReceive(void);
static uint16_t ModbusCrc16(uint8_t *data, uint16_t len);
static void SendData(uint8_t *buf, uint16_t len);
static void ModbusDataInit(void);
//static void ModbusDataInit(void);
static uint16_t ModbusMapRegAddr(uint16_t addr);
static uint8_t ModbusIsRegRangeValid(uint16_t addr, uint16_t qty);
static uint16_t ReadU16Be(const uint8_t *data);
@@ -70,10 +70,10 @@ void ModbusSlaveTask(void *pArg)

/*
* ModbusDataInit 会清零 g_hold_reg;上电后仅从 BKP 恢复参数/监控到 hold,
* 不再把运行结构体 Export 回寄存器(非法参数保留在上位机写入值 + 0x2006)
* 不有点多此一举,直接不初始化g_hold_reg
*/
ModbusDataInit();
PlsrPersistLoad();
// ModbusDataInit();
// PlsrPersistLoad();
ModbusPortInit();

while (1)
@@ -129,10 +129,10 @@ void ModbusSlaveTask(void *pArg)
* @brief 初始化保持寄存器映像
* @retval None
*/
void ModbusDataInit(void)
{
memset(g_hold_reg, 0, sizeof(g_hold_reg));
}
//void ModbusDataInit(void)
//{
// memset(g_hold_reg, 0, sizeof(g_hold_reg));
//}

/*============================================================================*/
/* 地址映射与区间校验 */


+ 35
- 36
plsr/command/plsr_command.c Целия файл

@@ -35,10 +35,9 @@ static volatile uint8_t s_live_freq_req;
static volatile uint32_t s_live_freq_hz;

/**
* @brief 写 32 位值到相邻两个保持寄存器(低字在前)
* @brief 写 32 位值到相邻两个modbus保持寄存器
* @param addr 低字寄存器地址
* @param value 32 位值
* @note 副作用:WriteHoldReg 两次
*/
static void PlsrCommandWriteDWord(uint16_t addr, uint32_t value)
{
@@ -47,9 +46,9 @@ static void PlsrCommandWriteDWord(uint16_t addr, uint32_t value)
}

/**
* @brief 刷新全部监控寄存器 0x2000~0x2006
* @brief 刷新全部监控寄存器 0x2000~0x2006到modbus保持寄存器
* @note 调用时机:Init 末、Poll 每周期末
* @note 数据源:RunControl / Plsr 门面 API + s_fault 镜像
* @note 数据源:RunControl / Plsr 任务 + s_fault 镜像
*/
static void PlsrCommandPublishMonitor(void)
{
@@ -71,27 +70,27 @@ static void PlsrCommandPublishMonitor(void)
}
}

/** @brief 置故障(见 plsr_command.h) */
/** @brief 置故障 */
void PlsrCommandSetFault(uint16_t code)
{
s_fault = code;
WriteHoldReg(PLSR_MON_ERR, code);
}

/** @brief 清故障(见 plsr_command.h) */
/** @brief 清故障 */
void PlsrCommandClearFault(void)
{
s_fault = PLSR_ERR_NONE;
WriteHoldReg(PLSR_MON_ERR, PLSR_ERR_NONE);
}

/** @brief 读故障镜像(见 plsr_command.h) */
/** @brief persist模块读故障码 */
uint16_t PlsrCommandGetFault(void)
{
return s_fault;
}

/** @brief 参数/重复启动类故障是否禁止 START(见 plsr_command.h) */
/** @brief 参数/重复启动类故障是否禁止 START */
uint8_t PlsrCommandIsStartBlocked(void)
{
if ((s_fault >= PLSR_ERR_PARAM_BLOCK_MIN) &&
@@ -102,7 +101,7 @@ uint8_t PlsrCommandIsStartBlocked(void)
return 0U;
}

/** @brief 指令模块初始化(见 plsr_command.h) */
/** @brief 指令模块初始化 */
void PlsrCommandInit(void)
{
WriteHoldReg(PLSR_CTRL_REG, 0U);
@@ -113,16 +112,16 @@ void PlsrCommandInit(void)
}

/**
* @brief 运行中 FC10 写段频率钩子(见 plsr_command.h)
* @note 门禁:quantity==2、Busy、地址对齐 FREQ_L、seg0==当前
* @brief 运行中 FC10 写段频率
* @note 限制:quantity==2、Busy、地址对齐 FREQ_L、当前改频段,当前运行
* @note 频率非法写 0x04 且不更新段表、不请求 ChangeFreq
*/
void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity)
{
uint16_t cur1;
uint16_t seg0;
uint16_t off;
uint32_t f;
uint16_t current_seg;//当前运行段
uint16_t seg;//当前改频段
uint16_t offset;//偏移量
uint32_t freqency;

if (quantity != 2U)
{
@@ -137,48 +136,48 @@ void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity)
return;
}

off = (uint16_t)(start_addr - PLSR_REG_SEG1_BASE);
if ((off % PLSR_SEG_STRIDE) != PLSR_SEG_OFF_FREQ_L)
offset = (uint16_t)(start_addr - PLSR_REG_SEG1_BASE);
if ((offset % PLSR_SEG_STRIDE) != PLSR_SEG_OFF_FREQ_L)
{
return;
}
seg0 = (uint16_t)(off / PLSR_SEG_STRIDE);
if (seg0 >= PLSR_SEG_MAX)
seg = (uint16_t)(offset / PLSR_SEG_STRIDE);
if (seg >= PLSR_SEG_MAX)
{
return;
}

cur1 = (uint16_t)(g_plsr_current_segment_index + 1U);
if ((cur1 < 1U) || ((uint16_t)(cur1 - 1U) != seg0))
current_seg = (uint16_t)(g_plsr_current_segment_index + 1U);
if ((current_seg < 1U) || ((uint16_t)(current_seg - 1U) != seg))
{
return;
}

f = (uint32_t)ReadHoldReg(start_addr) |
freqency = (uint32_t)ReadHoldReg(start_addr) |
((uint32_t)ReadHoldReg((uint16_t)(start_addr + 1U)) << 16);
/* 运行中写频也做 0x04 门禁:非法不改段表、不请求 ChangeFreq */
if ((f < 1U) || (f > 100000U))
/* 运行中改频非法不改段表、不请求 ChangeFreq */
if ((freqency < 1U) || (freqency > 100000U))
{
PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL);
return;
}

g_plsr_segments[seg0].freq_hz = (int32_t)f;
/* 运行中改频:立即只把该段频率双字写入 BKP,不等整包参数落盘 */
PlsrPersistSaveSegFreqToBkp(seg0, f);
g_plsr_segments[seg].freq_hz = (int32_t)freqency;
/* 运行中改频只把该段频率写入 BKP */
PlsrPersistSaveSegFreqToBkp(seg, freqency);

s_live_freq_hz = f;
s_live_freq_hz = freqency;
s_live_freq_req = 1U;
}

/**
* @brief 周期轮询(见 plsr_command.h)
* @brief 周期轮询
*
* 控制位处理顺序(同周期多 bit 时):
* 1. 读 ctrl 后立即写 0(避免重复触发)
* 2. STOP — 急停
* 3. CLR — 清累计 + ClearFault
* 4. START — 忙则 0x0C;否则 Apply 校验 → 0x04~0x0C 门禁则拒启 → Stop+Start
* 4. START — 忙则 0x0C;否则 Apply 校验 → 0x04~0x0C 故障码则拒启 → Stop+Start
* 动态改频在控制位之后、PublishMonitor 之前执行。
*/
void PlsrCommandPoll(void)
@@ -188,7 +187,7 @@ void PlsrCommandPoll(void)

if (ctrl != 0U)
{
WriteHoldReg(PLSR_CTRL_REG, 0U); /* 从站「读-改-清」协议:处理后清零 */
WriteHoldReg(PLSR_CTRL_REG, 0U);

if ((ctrl & PLSR_CTRL_BIT_STOP) != 0U)
{
@@ -198,7 +197,7 @@ void PlsrCommandPoll(void)
if ((ctrl & PLSR_CTRL_BIT_CLR) != 0U)
{
PlsrClearAccPulse();
PlsrCommandClearFault(); /* 清零累计时同步清 0x2006 */
PlsrCommandClearFault(); /* 清零累计时同步清故障码 */
}

/* 同时有停止位时不启动 */
@@ -212,11 +211,11 @@ void PlsrCommandPoll(void)
}
else if (PlsrParamBlockApplyFromHold() == 0U)
{
/* Apply 失败:故障码已由参数块写入 0x2006,不落 BKP */
/* 如果从modbus保持寄存器写入plsr结构体失败,暂不处理 */
}
else if (PlsrCommandIsStartBlocked() != 0U)
{
/* 0x04~0x0B 等门禁故障:禁止启动 */
/* 0x04~0x0B 故障:禁止启动 */
}
else
{
@@ -233,9 +232,9 @@ void PlsrCommandPoll(void)
/* 动态改频:标志置位后按新目标重规划剩余脉冲 */
if (s_live_freq_req != 0U)
{
uint32_t f = s_live_freq_hz;
uint32_t freq = s_live_freq_hz;
s_live_freq_req = 0U;
(void)PlsrChangeFreq(f);
(void)PlsrChangeFreq(freq);
}

if (skip_monitor == 0U)


+ 17
- 35
plsr/command/plsr_command.h Целия файл

@@ -44,40 +44,24 @@

/*
* 故障码定义(写入 0x2006,须经 PlsrCommandSetFault,勿直接只写寄存器)
*
* 码 | 宏名 | 含义 | 等级 | 处理策略
* ----|-------------------------|--------------------------------|------|------------------
* 0 | PLSR_ERR_NONE | 无故障 | — | 启动/CLR 时写入
* 1 | PLSR_ERR_PULSE_CNT | 实际脉冲数与段目标不一致 | 告警 | 继续跑,不中断
* 2 | PLSR_ERR_FREQ_UNREACH | 规划峰值达不到设定目标(三角) | 告警 | 按压后规划继续
* 3 | PLSR_ERR_CURVE_MISMATCH | 加减速相内脉冲与规划预算不符 | 告警 | 继续跑
* 4 | PLSR_ERR_FREQ_ILLEGAL | 段频率 ∉ [1, 100000] Hz(非 0) | 门禁 | 禁止启动/改频
* 5 | PLSR_ERR_PULSE_RANGE | 脉冲个数 ∉ int32 合法范围 | 门禁 | 禁止启动
* 6 | PLSR_ERR_SEG_COUNT | 总段数 ∉ [1, 10] | 门禁 | 禁止启动
* 7 | PLSR_ERR_START_SEG | 起始段 ∉ [1, 总段数] | 门禁 | 禁止启动
* 8 | PLSR_ERR_START_END_SPD | 起/止速非0且 ∉ [1, 100000] Hz | 门禁 | 禁止启动(0=合法)
* 9 | PLSR_ERR_PULSE_Y | 脉冲端子 ∉ {Y0,Y1,Y2} | 门禁 | 禁止启动
* 10 | PLSR_ERR_DIR_Y | 方向端子 ≠ Y3 | 门禁 | 禁止启动
* 11 | PLSR_ERR_DEFAULT_SPD | 默认速度 ∉ [1, 100000] Hz | 门禁 | 禁止启动
* 12 | PLSR_ERR_DUP_START | 运行中重复 START | 告警 | 启动无效
*/
#define PLSR_ERR_NONE 0x00U
#define PLSR_ERR_PULSE_CNT 0x01U
#define PLSR_ERR_FREQ_UNREACH 0x02U
#define PLSR_ERR_CURVE_MISMATCH 0x03U
#define PLSR_ERR_FREQ_ILLEGAL 0x04U
#define PLSR_ERR_PULSE_RANGE 0x05U
#define PLSR_ERR_SEG_COUNT 0x06U
#define PLSR_ERR_START_SEG 0x07U
#define PLSR_ERR_START_END_SPD 0x08U
#define PLSR_ERR_PULSE_Y 0x09U
#define PLSR_ERR_DIR_Y 0x0AU
#define PLSR_ERR_DEFAULT_SPD 0x0BU
#define PLSR_ERR_DUP_START 0x0CU
#define PLSR_ERR_NONE 0x00U //无故障
#define PLSR_ERR_PULSE_CNT 0x01U //实际脉冲数与段目标不一致
#define PLSR_ERR_FREQ_UNREACH 0x02U //规划峰值达不到设定目标(三角)
#define PLSR_ERR_CURVE_MISMATCH 0x03U //加减速相内脉冲与规划预算不符
#define PLSR_ERR_FREQ_ILLEGAL 0x04U //段频率 ∉ [1, 100000] Hz(非 0)
#define PLSR_ERR_PULSE_RANGE 0x05U //脉冲个数 ∉ int32 合法范围
#define PLSR_ERR_SEG_COUNT 0x06U //总段数 ∉ [1, 10]
#define PLSR_ERR_START_SEG 0x07U //起始段 ∉ [1, 10]
#define PLSR_ERR_START_END_SPD 0x08U //起/止速非0且 ∉ [1, 100000] Hz
#define PLSR_ERR_PULSE_Y 0x09U //脉冲端子 ∉ {Y0,Y1,Y2}
#define PLSR_ERR_DIR_Y 0x0AU //方向端子 ≠ Y3
#define PLSR_ERR_DEFAULT_SPD 0x0BU //默认速度 ∉ [1, 100000] Hz
#define PLSR_ERR_DUP_START 0x0CU //运行中重复 START

/** 参数类门禁故障码下限(含) */
/** 参数类门禁故障码下限 */
#define PLSR_ERR_PARAM_BLOCK_MIN PLSR_ERR_FREQ_ILLEGAL
/** 参数类门禁故障码上限(含 0x0C 重复启动) */
/** 参数类门禁故障码上限 */
#define PLSR_ERR_PARAM_BLOCK_MAX PLSR_ERR_DUP_START

/**
@@ -98,7 +82,7 @@ void PlsrCommandPoll(void);
* @brief 置故障码并立即写 0x2006
* @param code PLSR_ERR_* 之一
* @note 调用时机:run_control 诊断点;PublishMonitor 也会重发 s_fault
* @note 副作用:更新 s_fault 镜像,告警码不自动清除(须 START 或 CLR)
* @note 注意:更新 s_fault 镜像,告警码不自动清除(须 START 或 CLR)
*/
void PlsrCommandSetFault(uint16_t code);

@@ -113,7 +97,7 @@ uint16_t PlsrCommandGetFault(void);

/**
* @brief 是否因参数/重复启动类故障禁止 START
* @return 1=0x2006 为 0x04~0x0C(门禁/重复启动);0=可尝试启动
* @return 1=故障码为 0x04~0x0C;0=可尝试启动
*/
uint8_t PlsrCommandIsStartBlocked(void);

@@ -121,8 +105,6 @@ uint8_t PlsrCommandIsStartBlocked(void);
* @brief FC10 写段频率双字后的钩子
* @param start_addr 写入起始保持寄存器地址
* @param quantity 写入字数,须为 2
* @note 调用时机:Modbus 从站 FC10 应答路径;仅运行中且地址为「当前段 FREQ_L」有效
* @note 副作用:更新段表 freq_hz,置 s_live_freq_req 由 Poll 调 ChangeFreq
*/
void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity);



+ 22
- 131
plsr/param/plsr_param.c Целия файл

@@ -4,20 +4,11 @@
*
* @details 模块职责
* 维护公共参数 g_plsr_config 和段参数 g_plsr_segments[],实现寄存器与
* 运行参数之间的双向转换,以及
* 「5+N 分帧」收齐后的异步 Apply(信号量唤醒本任务)。
*
* 静态状态说明
* g_plsr_config — 公共运行参数
* g_plsr_segments[] — 10 段运行参数
* s_param_sem — 收齐分帧后 Post,Task Pend 后 Apply
* s_expect_frames — 期望总帧 = 5 + 公共帧1 中的段数
* s_recv_frames — 已收帧计数(公共帧1 起算)
* s_xfer_active — 正在接收一批分帧传输
* 运行参数之间的双向转换,以及「5+N 分帧」收齐后的异步导入
*
* 与其它模块关系
* Modbus FC10 应答路径调用 OnHoldWrite;Command START 也会同步 ApplyFromHold;
* Persist:校验全部通过才 SaveParamsFromHold;失败只写故障码,不BKP;
* Modbus FC10 应答路径调用 OnHoldWrite;START 也会同步 ApplyFromHold;
* Persist:校验全部通过才 SaveParamsFromHold;失败只写故障码,不存BKP;
* 非上电不再 ExportToHold(hold 保留上位机写入值,由故障码提示修正)。
*/
#include "plsr_param.h"
@@ -34,7 +25,7 @@ static volatile uint16_t s_expect_frames; /* 本批期望总帧数 = 5 + 段数
static volatile uint16_t s_recv_frames; /* 已收帧计数 */
static volatile uint8_t s_xfer_active; /* 1=正在接收一批分帧 */

/** @return 有效段数,钳制到 [0, PLSR_SEG_MAX](见 plsr_param.h) */
/** @return 有效段数,须在[0, PLSR_SEG_MAX]之间 */
uint16_t PlsrParamGetSegCount(void)
{
if (g_plsr_config.seg_count < 1U)
@@ -49,8 +40,7 @@ uint16_t PlsrParamGetSegCount(void)
}

/**
* @brief 启动段 1-based(见 plsr_param.h)
* @note 非法起始段当前仅裁剪,TODO 可报故障码
* @brief 启动段 1-based
*/
uint16_t PlsrParamGetStartSeg(void)
{
@@ -64,7 +54,6 @@ uint16_t PlsrParamGetStartSeg(void)
{
return 1U;
}
/* TODO:起始段非法时输出故障码 */
if (g_plsr_config.start_seg > n)
{
return n;
@@ -72,10 +61,6 @@ uint16_t PlsrParamGetStartSeg(void)
return g_plsr_config.start_seg;
}

/*============================================================================*/
/* 寄存器双字读写辅助 */
/*============================================================================*/

/** 读相邻两寄存器拼成无符号 32 位(低地址=低 16 位) */
static uint32_t PlsrParamReadDWord(uint16_t addr)
{
@@ -84,15 +69,8 @@ static uint32_t PlsrParamReadDWord(uint16_t addr)
return ((uint32_t)high << 16) | (uint32_t)low;
}

/** 写无符号 32 位到相邻两寄存器 */
static void PlsrParamWriteDWord(uint16_t addr, uint32_t value)
{
WriteHoldReg(addr, (uint16_t)(value & 0xFFFFU));
WriteHoldReg((uint16_t)(addr + 1U), (uint16_t)((value >> 16) & 0xFFFFU));
}

/**
* @brief 判断本次 FC10 是否为公共帧 2~5(双字速度/加减速)
* @brief 判断本次 FC10 是否为公共帧 2~5
* @return 1=是;0=否
*/
static uint8_t PlsrParamIsCommonTailFrameWrite(uint16_t start_addr, uint16_t quantity)
@@ -112,7 +90,7 @@ static uint8_t PlsrParamIsCommonTailFrameWrite(uint16_t start_addr, uint16_t qua
}

/**
* @brief 判断本次 FC10 是否为「整段 8 字写到某段基址」
* @brief 判断本次 FC10 是否为段参数
* @return 1=是段帧;0=否
*/
static uint8_t PlsrParamIsSegFrameWrite(uint16_t start_addr, uint16_t quantity)
@@ -135,20 +113,8 @@ static uint8_t PlsrParamIsSegFrameWrite(uint16_t start_addr, uint16_t quantity)
return 0U;
}

/**
* @brief 更新分帧状态三寄存器,供上位机诊断
* @param st PLSR_PARAM_XFER_*
* @param fail_frame 失败帧序号(成功时写 0)
*/
static void PlsrParamSetXferStatus(uint16_t st, uint16_t fail_frame)
{
WriteHoldReg(PLSR_PARAM_XFER_STATUS_REG, st);
WriteHoldReg(PLSR_PARAM_XFER_FAIL_FRAME_REG, fail_frame);
WriteHoldReg(PLSR_PARAM_XFER_RECV_REG, s_recv_frames);
}

/*============================================================================*/
/* 参数校验辅助 */
/* 参数校验辅助 */
/*============================================================================*/

#define PLSR_PARAM_SPD_MIN_HZ 1U
@@ -160,7 +126,7 @@ static uint8_t PlsrParamIsSpeedHzValid(uint32_t hz)
}

/**
* 起速/止速:0 合法(运行层 ResolveStartHz / ResolveEndHz 处理)
* 起速/止速:0 合法;
* 非 0 须在 1~100kHz。
*/
static uint8_t PlsrParamIsStartEndSpeedValid(uint32_t hz)
@@ -202,11 +168,11 @@ static uint8_t PlsrParamIsPulseCntValid(int32_t pulse_cnt)
/*============================================================================*/

/**
* @brief 保持寄存器 → 运行映像,边拷贝边校验(见 plsr_param.h)
* @brief 保持寄存器 → 运行映像,边拷贝边校验
*
* @details 校验失败时仍完成拷贝(保留上位机原始值),故障码写入 0x2006;
* 多项非法时仅保留校验过程中最后一个故障码。
* @return 1=全部通过;0=存在门禁故障(不落 BKP)
* @details 校验失败时仍完成拷贝,故障码写入 0x2006;
* 多项非法时仅保留校验过程中最后一个故障码。
* @return 1=全部通过;0=存在门禁故障(不落BKP)
*/
uint8_t PlsrParamBlockApplyFromHold(void)
{
@@ -318,65 +284,12 @@ uint8_t PlsrParamBlockApplyFromHold(void)
}

/**
* @brief 运行映像 → 全部相关保持寄存器(含未使用段槽位)
*
* @details 用途(与落 BKP 无关)
* 1. Apply 钳位后摊回 hold,使「读 PLC」与运行结构体一致;
* 2. ModbusDataInit() 清 hold 后,把已 Apply 的运行参数填回,
* 否则上位机读公共/段参数全 0,START 也会用空 hold 再次 Apply 冲掉结构体。
* @brief 统计接受帧数,收满释放信号量
*
* @note 0x100F 保留字写 0;段表写满 PLSR_SEG_MAX 槽,避免读回脏数据
* @note 落 BKP 请用 PlsrPersistSaveParamsFromHold(读 hold 原值),不依赖本函数
*/
void PlsrParamBlockExportToHold(void)
{
uint16_t i;
uint16_t base;

WriteHoldReg(PLSR_REG_PULSE_Y, g_plsr_config.pulse_y);
WriteHoldReg(PLSR_REG_DIR_Y, g_plsr_config.dir_y);
WriteHoldReg(PLSR_REG_WAIT_X, g_plsr_config.wait_x_sel);
WriteHoldReg(PLSR_REG_EXT_X, g_plsr_config.ext_x_sel);
WriteHoldReg(PLSR_REG_SEND_MODE, (uint16_t)g_plsr_config.send_mode);
WriteHoldReg(PLSR_REG_DIR_DELAY, g_plsr_config.dir_delay_ms);
WriteHoldReg(PLSR_REG_DIR_LOGIC, (uint16_t)g_plsr_config.dir_logic);
WriteHoldReg(PLSR_REG_ACCEL_MODE, (uint16_t)g_plsr_config.accel_mode);
WriteHoldReg(PLSR_REG_RUN_MODE, (uint16_t)g_plsr_config.run_mode);
WriteHoldReg(PLSR_REG_SEG_COUNT, g_plsr_config.seg_count);
WriteHoldReg(PLSR_REG_START_SEG, g_plsr_config.start_seg);
PlsrParamWriteDWord(PLSR_REG_DEFAULT_SPD_L, g_plsr_config.default_speed);
PlsrParamWriteDWord(PLSR_REG_START_SPD_L, g_plsr_config.start_speed);
WriteHoldReg(0x100FU, 0U);
PlsrParamWriteDWord(PLSR_REG_END_SPD_L, g_plsr_config.end_speed);
WriteHoldReg(PLSR_REG_ACCEL_MS, g_plsr_config.accel_ms);
WriteHoldReg(PLSR_REG_DECEL_MS, g_plsr_config.decel_ms);

for (i = 0U; i < PLSR_SEG_MAX; i++)
{
base = (uint16_t)(PLSR_REG_SEG1_BASE + i * PLSR_SEG_STRIDE);
PlsrParamWriteDWord((uint16_t)(base + PLSR_SEG_OFF_FREQ_L),
(uint32_t)g_plsr_segments[i].freq_hz);
PlsrParamWriteDWord((uint16_t)(base + PLSR_SEG_OFF_PULSE_L),
(uint32_t)g_plsr_segments[i].pulse_cnt);
WriteHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT),
(uint16_t)g_plsr_segments[i].wait_type);
WriteHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT_MS),
g_plsr_segments[i].wait_ms);
WriteHoldReg((uint16_t)(base + PLSR_SEG_OFF_ACT_MS),
g_plsr_segments[i].act_ms);
WriteHoldReg((uint16_t)(base + PLSR_SEG_OFF_JUMP),
g_plsr_segments[i].jump_seg);
}
}

/**
* @brief FC10 写后分帧状态机(见 plsr_param.h)
*
* 状态转移:
* 公共帧1@0x1000~0x100A → BUSY,expect=5+N,recv=1
* 公共帧1@0x1000~0x100A,expect=5+N,recv=1
* 传输中公共帧2~5 / 段帧 → recv++
* recv>=expect → 清 active,Post 信号量(或同步 Apply)
* 其它写地址忽略(例如运行中只写频率双字不走本路径的分帧逻辑)
* recv>=expect → 清 active,Post 信号量
* 运行中只写频率双字不走本路径
*/
void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity)
{
@@ -385,11 +298,6 @@ void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity)
return;
}

/*
* 公共帧1:0x1000~0x100A(含段数)→ 开启传输,期望帧=5+段数。
* 公共帧2~5 / 段帧:传输中且地址匹配 → 帧计数+1。
* 收齐后 post 信号量,由 ParamBlockTask 执行 Apply。
*/
if ((start_addr == PLSR_REG_COMMON_F1_BASE) &&
(quantity >= PLSR_PARAM_COMMON_FRAME1_WORDS))
{
@@ -401,14 +309,12 @@ void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity)
s_expect_frames = (uint16_t)(PLSR_PARAM_COMMON_FRAMES + seg_n);
s_recv_frames = 1U;
s_xfer_active = 1U;
PlsrParamSetXferStatus(PLSR_PARAM_XFER_BUSY, 0U);
}
else if ((s_xfer_active != 0U) &&
((PlsrParamIsCommonTailFrameWrite(start_addr, quantity) != 0U) ||
(PlsrParamIsSegFrameWrite(start_addr, quantity) != 0U)))
{
s_recv_frames++;
WriteHoldReg(PLSR_PARAM_XFER_RECV_REG, s_recv_frames);
}
else
{
@@ -422,33 +328,23 @@ void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity)
{
(void)OSSemPost(s_param_sem);
}
else if (PlsrParamBlockApplyFromHold() != 0U)
{
/* 信号量尚未创建时的兜底:同步 Apply */
PlsrParamSetXferStatus(PLSR_PARAM_XFER_OK, 0U);
}
else
{
PlsrParamSetXferStatus(PLSR_PARAM_XFER_FAIL, s_recv_frames);
}
}
}

/** @brief 创建信号量并置传输空闲(见 plsr_param.h) */
/** @brief 创建信号量并置清空接收计数 */
void PlsrParamBlockInit(void)
{
s_param_sem = OSSemCreate(0U);
s_expect_frames = 0U;
s_recv_frames = 0U;
s_xfer_active = 0U;
PlsrParamSetXferStatus(PLSR_PARAM_XFER_IDLE, 0U);
}

/**
* @brief 参数块任务(见 plsr_param.h)
* @brief 参数块任务
*
* for(;;):OSSemPend → ApplyFromHold(校验+写 0x2006)→ 通过则 SaveParamsFromHold。
* 校验失败:不 BKP,hold 保留上位机原值,由故障码提示修正。
* OSSemPend → ApplyFromHold(校验+写 0x2006)→ 通过则 SaveParamsFromHold。
* 校验失败:不 BKP,hold 保留上位机原值,由故障码提示修正。
*/
void PlsrParamBlockTask(void *pArg)
{
@@ -466,12 +362,7 @@ void PlsrParamBlockTask(void *pArg)

if (PlsrParamBlockApplyFromHold() != 0U)
{
PlsrParamSetXferStatus(PLSR_PARAM_XFER_OK, 0U);
PlsrPersistSaveParamsFromHold(); /* 仅全部校验通过才落 BKP */
}
else
{
PlsrParamSetXferStatus(PLSR_PARAM_XFER_FAIL, s_recv_frames);
PlsrPersistSaveParamsFromHold(); /* 仅全部校验通过才存 BKP */
}
}
}

+ 10
- 37
plsr/param/plsr_param.h Целия файл

@@ -4,7 +4,7 @@
*
* @details 模块职责
* 1. 定义公共参数区 0x1000~0x1013、段表区 0x1100+i*0x10 的地址与字段语义;
* 2. 维护 g_plsr_config / g_plsr_segments[](运动规划只读,不直接读寄存器)
* 2. 维护 g_plsr_config / g_plsr_segments[];
* 3. 支持上位机「5 公共帧 + N 段帧」分帧 FC10 写入:收齐后 ApplyFromHold;
* 4. 上电由 PersistLoad 填 hold;ExportToHold 仅保留作调试接口。
*
@@ -12,8 +12,8 @@
* - modbus_rtu / modbus_data :ReadHoldReg / WriteHoldReg
* - plsr_command :启动前 ApplyFromHold;运行中修改当前段 freq_hz
* - plsr_run_control :GetCfg / GetSeg / GetSegCount / GetStartSeg
* - plsr_persist :Apply 成功后 SaveParamsFromHold;动态改频 SaveSegFreqToBkp
* - PlsrParamBlockTask :独立 uC/OS 任务,等信号量后 Apply + 整包 BKP
* - plsr_persist :拷贝成功后存入BKP;动态改频存频率进BKP
* - PlsrParamBlockTask :独立 uC/OS 任务,等信号量后 Apply + 整包 BKP
*
* 关键数据流
* 上位机写公共帧1@0x1000 → OnHoldWrite 开传输 expect=5+N,recv=1
@@ -23,7 +23,7 @@
*
* 协议概要
* - 公共 5 帧:
* 1: 0x1000~0x100A(11 字,含段数 N@0x1009
* 1: 0x1000~0x100A(11 字)
* 2: 0x100B~0x100C(默认速度)
* 3: 0x100D~0x100E(起速)
* 4: 0x1010~0x1011(止速;跳过 0x100F)
@@ -59,7 +59,7 @@
/* 0x100F 保留,写帧填 0 */
#define PLSR_REG_END_SPD_L 0x1010U /* 止速 Hz */
#define PLSR_REG_END_SPD_H 0x1011U
#define PLSR_REG_ACCEL_MS 0x1012U /* 默认速度加速时间 ms(定斜率) */
#define PLSR_REG_ACCEL_MS 0x1012U /* 默认速度加速时间 ms */
#define PLSR_REG_DECEL_MS 0x1013U /* 默认速度减速时间 ms */

/* ---------- 公共参数分帧(5 帧 + N 段帧) ---------- */
@@ -87,16 +87,6 @@
#define PLSR_SEG_OFF_ACT_MS 6U /* ACT 时间 ms */
#define PLSR_SEG_OFF_JUMP 7U /* 0=顺序/末段停;1~N=跳转目标段号 */

/* ---------- 分帧传输状态(上位机可选读) ---------- */
#define PLSR_PARAM_XFER_RECV_REG 0x0FFCU /* 已接收帧计数 */
#define PLSR_PARAM_XFER_FAIL_FRAME_REG 0x0FFDU /* 失败时的帧序号 */
#define PLSR_PARAM_XFER_STATUS_REG 0x0FFEU /* IDLE/BUSY/OK/FAIL */

#define PLSR_PARAM_XFER_IDLE 0U
#define PLSR_PARAM_XFER_BUSY 1U
#define PLSR_PARAM_XFER_OK 2U
#define PLSR_PARAM_XFER_FAIL 3U

/** 方向逻辑:正转时方向脚电平 */
typedef enum {
PLSR_DIR_LOGIC_POS = 0, /* 正转→方向高,反转→低 */
@@ -113,7 +103,7 @@ typedef enum {
PLSR_SEND_FOLLOW = 1
} PlsrSendMode_e;

/** 加减速曲线形状(脉冲域规划) */
/** 加减速曲线形状 */
typedef enum {
PLSR_ACCEL_LINEAR = 0, /* f^2 = f0^2 ± 2an */
PLSR_ACCEL_S = 1, /* 时间域七段 S:加速度梯形 1:2:1 */
@@ -131,7 +121,7 @@ typedef enum {
} PlsrPosMode_e;

/**
* 段末/段内等待类型(由 run_control + signal_io 执行)
* 段末/段内等待类型
* TIME/SIGNAL/ACT/EXT:完成/后续均规划到止速;并阻止 FOLLOW 不停表衔接
* EXT_OR_DONE:与下一段同向时后续可接目标/完成匀速跑完并可 FOLLOW 衔接;
* 与下一段反向时规划同其它等待(减速到止速,下一段从起速再爬)
@@ -145,8 +135,7 @@ typedef enum {
} PlsrWaitType_e;

/**
* 公共运行参数映像(运动侧只读)
* 斜率:a ≈ default_speed * 1000 / accel_ms(Hz/s)
* 公共运行参数映像
*/
typedef struct {
uint16_t pulse_y; /* 0=Y0/TIM10 1=Y1/TIM13 2=Y2/TIM11 */
@@ -178,15 +167,6 @@ typedef struct {
} PlsrSeg_t;

/* ---------- 运行参数 ---------- */

/*
* 所有 PLSR 模块都直接读取这两份数据。
* g_plsr_config :公共参数,只有一份。
* g_plsr_segments[i] :第 i+1 段参数,i 的范围是 0~9。
*
* 参数任务负责从保持寄存器更新它们;运动过程中其它模块只读取,
* 只有“运行中改频”会修改当前段的 freq_hz。
*/
extern PlsrCfg_t g_plsr_config;
extern PlsrSeg_t g_plsr_segments[PLSR_SEG_MAX];

@@ -210,7 +190,6 @@ void PlsrParamBlockInit(void);
/**
* @brief 参数块任务:阻塞等信号量 → ApplyFromHold(校验)→ 通过则 SaveParamsFromHold
* @param pArg 未使用
* @note for(;;) 死循环为 RTOS 任务常态;空循环体是错觉(花括号内有 Pend/Apply)
*/
void PlsrParamBlockTask(void *pArg);

@@ -218,20 +197,14 @@ void PlsrParamBlockTask(void *pArg);
* @brief FC10 写保持寄存器后由 Modbus 回调
* @param start_addr 起始地址
* @param quantity 字数
* @note 公共帧开传输;段帧累加;收齐 post 信号量(或无信号量时同步 Apply)
* @note 公共帧开传输;段帧累加;收齐 post 信号量
*/
void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity);

/**
* @brief 保持寄存器 → g_plsr_config / g_plsr_segments,边拷贝边校验
* @return 1=全部通过(写 0x2006=0);0=存在门禁故障(写对应码,不落 BKP)
* @return 1=全部通过;0=存在门禁故障
*/
uint8_t PlsrParamBlockApplyFromHold(void);

/**
* @brief g_plsr_config / g_plsr_segments → 保持寄存器(调试/特殊用途)
* @note 上电参数由 BKP→hold(PersistLoad);非法参数保留 hold 原值供上位机读回修正
*/
void PlsrParamBlockExportToHold(void);

#endif

+ 4
- 9
plsr/plsr.c Целия файл

@@ -2,12 +2,7 @@
* @file plsr.c
* @brief PLSR 顶层初始化和周期任务
*
* @details 模块职责
* 本文件只做两件事:按顺序初始化各模块,以及运行 PlsrTask 周期任务。
* 启停和中断函数直接实现在 run_control.c,这里不再做重复转发。
*
* 与其它模块关系
* 本文件仅依赖 plsr.h 及各子模块头文件,不被其它 plsr 模块反向引用。
* @details 按顺序初始化各模块,以及运行 PlsrTask 周期任务。
*
* 关键数据流
* PlsrInit 顺序:PersistLoad(BKP→hold) → ApplyFromHold(hold→结构体) → …
@@ -24,15 +19,15 @@
#include "ucos_ii.h"

/**
* @brief 子系统初始化(见 plsr.h)
* @brief 子系统初始化
*
* 顺序要点
* PersistLoad → Apply:BKP → hold → 结构体(BKP 内参数已合法);
* PersistLoad → Apply:BKP → hold → 结构体(BKP 内参数已合法);
* 非上电不再把结构体 Export 回 hold;Modbus 清零后由 BKP 再填 hold。
*/
void PlsrInit(void)
{
PlsrPersistInit(); /* 使能 BKPSRAM 写访问,否则落盘无效 */
PlsrPersistInit(); /* 使能 BKPSRAM 写访问,否则存BKP无效 */
PlsrPersistLoad(); /* BKPSRAM → g_hold_reg */
(void)PlsrParamBlockApplyFromHold(); /* hold → 运行参数 + 校验 */
PlsrPulseDriverInit();


+ 2
- 15
plsr/plsr.h Целия файл

@@ -30,27 +30,14 @@ extern volatile uint16_t g_plsr_current_segment_index;
extern volatile int32_t g_plsr_accumulated_pulses;
#include "plsr_param.h"

/*
* PLSR_LOOP_TEST_EN:调试宏。
* 1 = 第 1 段跑完后空闲约 1s 自动再启(仅联调);正式产品保持 0。
*/
#ifndef PLSR_LOOP_TEST_EN
#define PLSR_LOOP_TEST_EN 0
#endif

/**
* @brief 子系统一次性初始化
* @note 调用时机:OS 启动后、Modbus 从站就绪前,由 main 或启动任务调用一次
* @note 副作用:加载 Flash 公共参数、初始化 TIM/GPIO、导出默认映像到保持寄存器
* @brief plsr任务初始化
*/
void PlsrInit(void);

/**
* @brief uC/OS-II 周期任务入口
* @param pArg 任务参数(未使用,传 NULL)
* @note 调用时机:创建后永久循环;WAIT/ACT 到期由信号量立刻唤醒,否则最多 1 个 OS tick
* @note 副作用:轮询 Modbus 控制位、刷新监控寄存器、推进运行控制状态机、
* 空闲时触发 Flash 持久化;首次进入延迟 ~300ms 再导出参数(避免 Modbus 清零冲掉)
* @param pArg 任务参数
*/
void PlsrTask(void *pArg);



Зареждане…
Отказ
Запис