瀏覽代碼

终版

Signed-off-by: hanyongwei <2043702190@qq.com>
dev3
hanyongwei 2 週之前
父節點
當前提交
13e2511195
共有 14 個文件被更改,包括 2102 次插入2263 次删除
  1. +1
    -1
      app/main.c
  2. +170
    -169
      iar/plsr.dep
  3. +735
    -798
      plsr/accel_curve/plsr_accel_curve.c
  4. +27
    -28
      plsr/accel_curve/plsr_accel_curve.h
  5. +29
    -30
      plsr/command/plsr_command.c
  6. +21
    -21
      plsr/command/plsr_command.h
  7. +46
    -46
      plsr/param/plsr_param.c
  8. +52
    -52
      plsr/param/plsr_param.h
  9. +13
    -13
      plsr/plsr.c
  10. +3
    -4
      plsr/plsr.h
  11. +261
    -282
      plsr/pulse_driver/plsr_pulse_driver.c
  12. +4
    -5
      plsr/pulse_driver/plsr_pulse_driver.h
  13. +715
    -789
      plsr/run_control/plsr_run_control.c
  14. +25
    -25
      plsr/signal_io/plsr_signal_io.c

+ 1
- 1
app/main.c 查看文件

@@ -138,7 +138,7 @@ void SystemClock_Config(void)
RCC_OscInitStruct.PLL.PLLM = 12; /* HSE=12MHz → VCO in = 1MHz */ RCC_OscInitStruct.PLL.PLLM = 12; /* HSE=12MHz → VCO in = 1MHz */
RCC_OscInitStruct.PLL.PLLN = 336; RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;/*不准改成7*/
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{ {
Error_Handler(); Error_Handler();


+ 170
- 169
iar/plsr.dep
文件差異過大導致無法顯示
查看文件


+ 735
- 798
plsr/accel_curve/plsr_accel_curve.c
文件差異過大導致無法顯示
查看文件


+ 27
- 28
plsr/accel_curve/plsr_accel_curve.h 查看文件

@@ -16,15 +16,15 @@
* run_control 进入减速时使用局部规划副本,不会改写这里的整段规划预算。 * run_control 进入减速时使用局部规划副本,不会改写这里的整段规划预算。
*/ */
typedef struct { typedef struct {
uint32_t accel_pulses; /* 入口到目标频率需要的脉冲数 */
uint32_t const_pulses; /* 保持目标频率的脉冲数 */
uint32_t decel_pulses; /* 目标到出口频率需要的脉冲数 */
uint32_t start_freq_hz; /* 本段实际入口频率 */
uint32_t target_freq_hz; /* 实际目标频率,短段可能被降低 */
uint32_t end_freq_hz; /* 本段出口频率 */
uint32_t accel_rate_hz_per_s; /* 升高频率时使用的变化率 */
uint32_t decel_rate_hz_per_s; /* 降低频率时使用的变化率 */
PlsrAccelMode_e curve_mode; /* 直线 / S / 正弦 */
uint32_t accel_pulses;
uint32_t const_pulses;
uint32_t decel_pulses;
uint32_t start_freq_hz;
uint32_t target_freq_hz;
uint32_t end_freq_hz;
uint32_t accel_rate_hz_per_s;
uint32_t decel_rate_hz_per_s;
PlsrAccelMode_e curve_mode;
} PlsrAccelPlan_t; } PlsrAccelPlan_t;


/** 配置起速 → 规划入口:起速>目标用起速;否则目标与起跳比较取其一 */ /** 配置起速 → 规划入口:起速>目标用起速;否则目标与起跳比较取其一 */
@@ -65,27 +65,26 @@ uint32_t PlsrAccelCurveFreqAtPulse(const PlsrAccelPlan_t *plan,
* S/正弦:查预计算频率表(开相 BeginAcc/BeginDec 时填好) * S/正弦:查预计算频率表(开相 BeginAcc/BeginDec 时填好)
*/ */
typedef struct { typedef struct {
uint32_t cur_freq_hz; /* 当前输出频率 */
uint32_t start_freq_hz; /* 当前相起点频率 */
uint32_t end_freq_hz; /* 当前相终点频率 */
uint32_t accel_hz_per_s; /* 当前相使用的变化率 */
uint32_t completed_pulses; /* 当前相已经步进的脉冲数 */
uint32_t total_pulses; /* 当前相计划步进的脉冲数 */
uint32_t elapsed_time_us; /* 时间曲线已经经过的时间 */
uint32_t jerk_time_us; /* S 曲线单个 jerk 阶段时间 */
uint32_t const_accel_time_us; /* S 曲线恒加速阶段时间 */
uint32_t ramp_time_us; /* 整个斜坡时间 */
uint32_t table_stride; /* 每几个脉冲读取一个表项 */
uint32_t table_length; /* 表中有效项数 */
uint8_t freq_rising; /* 1=频率升高,0=降低 */
uint8_t is_active; /* 1=当前相仍在运行 */
uint8_t freq_table_id; /* 0=不用表,1=加速表,2=减速表 */
PlsrAccelMode_e curve_mode; /* 直线 / S / 正弦 */
uint32_t cur_freq_hz;
uint32_t start_freq_hz;
uint32_t end_freq_hz;
uint32_t accel_hz_per_s;
uint32_t completed_pulses;
uint32_t total_pulses;
uint32_t elapsed_time_us;
uint32_t jerk_time_us;
uint32_t const_accel_time_us;
uint32_t ramp_time_us;
uint32_t table_stride;
uint32_t table_length;
uint8_t freq_rising;
uint8_t is_active;
uint8_t freq_table_id;
PlsrAccelMode_e curve_mode;
} PlsrAccelRuntime_t; } PlsrAccelRuntime_t;


/* 当前段唯一的曲线规划和逐拍状态,run_control 直接使用,不再另存副本。 */
extern PlsrAccelPlan_t g_plsr_accel_plan; /* 本段三相规划结果 */
extern PlsrAccelRuntime_t g_plsr_accel_runtime; /* 当前相 ISR 逐拍状态 */
extern PlsrAccelPlan_t g_plsr_accel_plan;
extern PlsrAccelRuntime_t g_plsr_accel_runtime;


/** PlanSeg 后调用:预建 S/正弦加减速频率表(勿在 ISR) */ /** PlanSeg 后调用:预建 S/正弦加减速频率表(勿在 ISR) */
void PlsrAccelPrebuildFreqTables(const PlsrAccelPlan_t *plan); void PlsrAccelPrebuildFreqTables(const PlsrAccelPlan_t *plan);


+ 29
- 30
plsr/command/plsr_command.c 查看文件

@@ -30,9 +30,9 @@
* s_live_freq_req — 运行中写频请求标志,Poll 消费后清 0 * s_live_freq_req — 运行中写频请求标志,Poll 消费后清 0
* s_live_freq_hz — 待应用的 new_tgt_hz * s_live_freq_hz — 待应用的 new_tgt_hz
*/ */
static uint16_t s_fault = PLSR_ERR_NONE; /* 故障码镜像,与 0x2006 同步 */
static volatile uint8_t s_live_freq_req; /* 1=运行中改频待 Poll 消费 */
static volatile uint32_t s_live_freq_hz; /* 待应用的新目标频率 Hz */
static uint16_t s_fault = PLSR_ERR_NONE;
static volatile uint8_t s_live_freq_req;
static volatile uint32_t s_live_freq_hz;


/** /**
* @brief 写 32 位值到相邻两个modbus保持寄存器 * @brief 写 32 位值到相邻两个modbus保持寄存器
@@ -57,13 +57,13 @@ static void PlsrCommandPublishMonitor(void)


if (g_plsr_busy != 0U) if (g_plsr_busy != 0U)
{ {
PlsrCommandWriteDWord(PLSR_MON_FREQ_L, g_plsr_output_freq_hz); /* 0x2002/03 当前频 */
WriteHoldReg(PLSR_MON_RUN_STATUS, 1U); /* 0x2004 运行中 */
WriteHoldReg(PLSR_MON_CUR_SEG, (uint16_t)(g_plsr_cur_seg_idx + 1U)); /* 0x2005 1-based */
PlsrCommandWriteDWord(PLSR_MON_FREQ_L, g_plsr_output_freq_hz);
WriteHoldReg(PLSR_MON_RUN_STATUS, 1U);
WriteHoldReg(PLSR_MON_CUR_SEG, (uint16_t)(g_plsr_cur_seg_idx + 1U));
} }
else else
{ {
/* 空闲/停止:运行、段、频率一律清零;累计与故障码单独维护 */
PlsrCommandWriteDWord(PLSR_MON_FREQ_L, 0U); PlsrCommandWriteDWord(PLSR_MON_FREQ_L, 0U);
WriteHoldReg(PLSR_MON_RUN_STATUS, 0U); WriteHoldReg(PLSR_MON_RUN_STATUS, 0U);
WriteHoldReg(PLSR_MON_CUR_SEG, 0U); WriteHoldReg(PLSR_MON_CUR_SEG, 0U);
@@ -107,7 +107,7 @@ void PlsrCommandInit(void)
WriteHoldReg(PLSR_CTRL_REG, 0U); WriteHoldReg(PLSR_CTRL_REG, 0U);
s_live_freq_req = 0U; s_live_freq_req = 0U;
s_live_freq_hz = 0U; s_live_freq_hz = 0U;
/* 不清故障:上电由 PersistRestoreMonitor 恢复;无镜像时 s_fault 默认为 0 */
PlsrCommandPublishMonitor(); PlsrCommandPublishMonitor();
} }


@@ -118,18 +118,18 @@ void PlsrCommandInit(void)
*/ */
void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity) void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity)
{ {
uint16_t cur_seg; /* 当前运行段(1-based) */
uint16_t seg; /* 本次写入对应的段下标(0-based) */
uint16_t cur_seg;
uint16_t seg;
uint16_t offset; uint16_t offset;
uint32_t freqency; uint32_t freqency;


if (quantity != 2U) if (quantity != 2U)
{ {
return; /* 须为频率双字 */
return;
} }
if (g_plsr_busy == 0U) if (g_plsr_busy == 0U)
{ {
return; /* 空闲改频走参数块,不走本路径 */
return;
} }
if (start_addr < PLSR_REG_SEG1_BASE) if (start_addr < PLSR_REG_SEG1_BASE)
{ {
@@ -139,7 +139,7 @@ void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity)
offset = (uint16_t)(start_addr - PLSR_REG_SEG1_BASE); offset = (uint16_t)(start_addr - PLSR_REG_SEG1_BASE);
if ((offset % PLSR_SEG_STRIDE) != PLSR_SEG_OFF_FREQ_L) if ((offset % PLSR_SEG_STRIDE) != PLSR_SEG_OFF_FREQ_L)
{ {
return; /* 地址须对齐该段 FREQ_L */
return;
} }
seg = (uint16_t)(offset / PLSR_SEG_STRIDE); seg = (uint16_t)(offset / PLSR_SEG_STRIDE);
if (seg >= PLSR_SEG_MAX) if (seg >= PLSR_SEG_MAX)
@@ -150,22 +150,22 @@ void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity)
cur_seg = (uint16_t)(g_plsr_cur_seg_idx + 1U); cur_seg = (uint16_t)(g_plsr_cur_seg_idx + 1U);
if ((cur_seg < 1U) || ((uint16_t)(cur_seg - 1U) != seg)) if ((cur_seg < 1U) || ((uint16_t)(cur_seg - 1U) != seg))
{ {
return; /* 仅允许改当前运行段 */
return;
} }


freqency = (uint32_t)ReadHoldReg(start_addr) | freqency = (uint32_t)ReadHoldReg(start_addr) |
((uint32_t)ReadHoldReg((uint16_t)(start_addr + 1U)) << 16); ((uint32_t)ReadHoldReg((uint16_t)(start_addr + 1U)) << 16);
if ((freqency < 1U) || (freqency > 100000U)) if ((freqency < 1U) || (freqency > 100000U))
{ {
PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL); /* 非法:不改段表、不请求 */
PlsrCommandSetFault(PLSR_ERR_FREQ_ILLEGAL);
return; return;
} }


g_plsr_segs[seg].freq_hz = (int32_t)freqency; /* 更新运行段表 */
PlsrPersistSaveSegFreqToBkp(seg, freqency); /* 仅该段频率落 BKP */
g_plsr_segs[seg].freq_hz = (int32_t)freqency;
PlsrPersistSaveSegFreqToBkp(seg, freqency);


s_live_freq_hz = freqency; s_live_freq_hz = freqency;
s_live_freq_req = 1U; /* 交 Poll → ChangeFreq */
s_live_freq_req = 1U;
} }


/** /**
@@ -181,42 +181,41 @@ void PlsrCommandOnSegFreqHoldWrite(uint16_t start_addr, uint16_t quantity)
void PlsrCommandPoll(void) void PlsrCommandPoll(void)
{ {
uint16_t ctrl = ReadHoldReg(PLSR_CTRL_REG); uint16_t ctrl = ReadHoldReg(PLSR_CTRL_REG);
uint8_t skip_monitor = 0U; /* 精确等待时跳过本拍监控刷新 */
uint8_t skip_monitor = 0U;


if (ctrl != 0U) if (ctrl != 0U)
{ {
WriteHoldReg(PLSR_CTRL_REG, 0U); /* 立即清,避免重复触发 */
WriteHoldReg(PLSR_CTRL_REG, 0U);


if ((ctrl & PLSR_CTRL_BIT_STOP) != 0U) if ((ctrl & PLSR_CTRL_BIT_STOP) != 0U)
{ {
PlsrStop(); /* 急停 */
PlsrStop();
} }


if ((ctrl & PLSR_CTRL_BIT_CLR) != 0U) if ((ctrl & PLSR_CTRL_BIT_CLR) != 0U)
{ {
PlsrClearAccPulse(); /* 清累计 + 绝对原点 */
PlsrCommandClearFault(); /* 同步清故障码 */
PlsrClearAccPulse();
PlsrCommandClearFault();
} }


/* START:同拍有 STOP 则不启 */
if (((ctrl & PLSR_CTRL_BIT_START) != 0U) && if (((ctrl & PLSR_CTRL_BIT_START) != 0U) &&
((ctrl & PLSR_CTRL_BIT_STOP) == 0U)) ((ctrl & PLSR_CTRL_BIT_STOP) == 0U))
{ {
if (g_plsr_busy != 0U) if (g_plsr_busy != 0U)
{ {
PlsrCommandSetFault(PLSR_ERR_DUP_START); /* 0x0C 重复启动 */
PlsrCommandSetFault(PLSR_ERR_DUP_START);
} }
else if (PlsrCommandIsStartBlocked() != 0U) else if (PlsrCommandIsStartBlocked() != 0U)
{ {
PlsrStop(); /* 0x04~0x0B:拒启,仅停 */
PlsrStop();
} }
else else
{ {
PlsrStop(); /* 先清残留再启 */
PlsrStop();
(void)PlsrStart(PlsrParamGetStartSeg()); (void)PlsrStart(PlsrParamGetStartSeg());
if (PlsrRunControlIsPreciseWait() != 0U) if (PlsrRunControlIsPreciseWait() != 0U)
{ {
skip_monitor = 1U; /* 换向/WAIT 精确等 TIM5 */
skip_monitor = 1U;
} }
} }
} }
@@ -226,11 +225,11 @@ void PlsrCommandPoll(void)
{ {
uint32_t freq = s_live_freq_hz; uint32_t freq = s_live_freq_hz;
s_live_freq_req = 0U; s_live_freq_req = 0U;
(void)PlsrChangeFreq(freq); /* 重规划剩余脉冲 */
(void)PlsrChangeFreq(freq);
} }


if (skip_monitor == 0U) if (skip_monitor == 0U)
{ {
PlsrCommandPublishMonitor(); /* 回写 0x2000~0x2006 */
PlsrCommandPublishMonitor();
} }
} }

+ 21
- 21
plsr/command/plsr_command.h 查看文件

@@ -28,36 +28,36 @@
#include <stdint.h> #include <stdint.h>


/* ---------- 监控保持寄存器(双字低地址存低 16 位,高地址存高 16 位) ---------- */ /* ---------- 监控保持寄存器(双字低地址存低 16 位,高地址存高 16 位) ---------- */
#define PLSR_MON_ACC_PULSE_L 0x2000U /* 脉冲累计 SDW,有符号补码 */
#define PLSR_MON_ACC_PULSE_L 0x2000U
#define PLSR_MON_ACC_PULSE_H 0x2001U #define PLSR_MON_ACC_PULSE_H 0x2001U
#define PLSR_MON_FREQ_L 0x2002U /* 当前发送频率 Hz,UDW */
#define PLSR_MON_FREQ_L 0x2002U
#define PLSR_MON_FREQ_H 0x2003U #define PLSR_MON_FREQ_H 0x2003U
#define PLSR_MON_RUN_STATUS 0x2004U /* 0=空闲,1=运行中 */
#define PLSR_MON_CUR_SEG 0x2005U /* 当前执行段号,1-based;空闲为 0 */
#define PLSR_MON_ERR 0x2006U /* 故障码,见 PLSR_ERR_* */
#define PLSR_MON_RUN_STATUS 0x2004U
#define PLSR_MON_CUR_SEG 0x2005U
#define PLSR_MON_ERR 0x2006U


/* ---------- 控制寄存器(读/写;从站处理后写回 0) ---------- */ /* ---------- 控制寄存器(读/写;从站处理后写回 0) ---------- */
#define PLSR_CTRL_REG 0x3000U #define PLSR_CTRL_REG 0x3000U
#define PLSR_CTRL_BIT_START (1U << 0) /* 置 1:Apply 参数后启动 */
#define PLSR_CTRL_BIT_STOP (1U << 1) /* 置 1:急停 */
#define PLSR_CTRL_BIT_CLR (1U << 2) /* 置 1:清零累计脉冲与故障码 */
#define PLSR_CTRL_BIT_START (1U << 0)
#define PLSR_CTRL_BIT_STOP (1U << 1)
#define PLSR_CTRL_BIT_CLR (1U << 2)


/* /*
* 故障码定义(写入 0x2006,须经 PlsrCommandSetFault,勿直接只写寄存器) * 故障码定义(写入 0x2006,须经 PlsrCommandSetFault,勿直接只写寄存器)
*/ */
#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_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_PARAM_BLOCK_MIN PLSR_ERR_FREQ_ILLEGAL #define PLSR_ERR_PARAM_BLOCK_MIN PLSR_ERR_FREQ_ILLEGAL


+ 46
- 46
plsr/param/plsr_param.c 查看文件

@@ -17,24 +17,24 @@
#include "modbus_rtu.h" #include "modbus_rtu.h"
#include "ucos_ii.h" #include "ucos_ii.h"


PlsrCfg_t g_plsr_config; /* 公共参数运行映像 */
PlsrSeg_t g_plsr_segs[PLSR_SEG_MAX]; /* 段表运行映像(最多 PLSR_SEG_MAX) */
PlsrCfg_t g_plsr_config;
PlsrSeg_t g_plsr_segs[PLSR_SEG_MAX];


static OS_EVENT *s_param_sem; /* 分帧收齐后唤醒 ParamBlockTask */
static volatile uint16_t s_expect_frames; /* 本批期望总帧数 = 5 + 段数 */
static volatile uint16_t s_recv_frames; /* 已收帧计数 */
static volatile uint8_t s_xfer_active; /* 1=正在接收一批分帧 */
static OS_EVENT *s_param_sem;
static volatile uint16_t s_expect_frames;
static volatile uint16_t s_recv_frames;
static volatile uint8_t s_xfer_active;


/** @return 有效段数,软钳到 [0, PLSR_SEG_MAX] */ /** @return 有效段数,软钳到 [0, PLSR_SEG_MAX] */
uint16_t PlsrParamGetSegCount(void) uint16_t PlsrParamGetSegCount(void)
{ {
if (g_plsr_config.seg_count < 1U) if (g_plsr_config.seg_count < 1U)
{ {
return 0U; /* 无有效段 */
return 0U;
} }
if (g_plsr_config.seg_count > PLSR_SEG_MAX) if (g_plsr_config.seg_count > PLSR_SEG_MAX)
{ {
return (uint16_t)PLSR_SEG_MAX; /* 超上限钳住 */
return (uint16_t)PLSR_SEG_MAX;
} }
return g_plsr_config.seg_count; return g_plsr_config.seg_count;
} }
@@ -48,7 +48,7 @@ uint16_t PlsrParamGetStartSeg(void)


if (n < 1U) if (n < 1U)
{ {
return 1U; /* 无段时仍返回 1 */
return 1U;
} }
if (g_plsr_config.start_seg < 1U) if (g_plsr_config.start_seg < 1U)
{ {
@@ -56,7 +56,7 @@ uint16_t PlsrParamGetStartSeg(void)
} }
if (g_plsr_config.start_seg > n) if (g_plsr_config.start_seg > n)
{ {
return n; /* 超出则钳到末段 */
return n;
} }
return g_plsr_config.start_seg; return g_plsr_config.start_seg;
} }
@@ -114,7 +114,7 @@ static uint8_t PlsrParamIsSegFrameWrite(uint16_t start_addr, uint16_t quantity)
} }


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


#define PLSR_PARAM_SPD_MIN_HZ 1U #define PLSR_PARAM_SPD_MIN_HZ 1U
@@ -156,7 +156,7 @@ static uint8_t PlsrParamIsSegFreqValid(int32_t freq_hz)
/** 脉冲个数 SDW:须在 int32 可安全取绝对值的范围内(排除 INT_MIN) */ /** 脉冲个数 SDW:须在 int32 可安全取绝对值的范围内(排除 INT_MIN) */
static uint8_t PlsrParamIsPulseCntValid(int32_t pulse_cnt) static uint8_t PlsrParamIsPulseCntValid(int32_t pulse_cnt)
{ {
/* INT_MIN 无法安全取反成正的目标脉冲数,报 0x05 */
if (pulse_cnt == (int32_t)(-2147483647L - 1L)) if (pulse_cnt == (int32_t)(-2147483647L - 1L))
{ {
return 0U; return 0U;
@@ -165,7 +165,7 @@ static uint8_t PlsrParamIsPulseCntValid(int32_t pulse_cnt)
} }


/*============================================================================*/ /*============================================================================*/
/* 分帧导入 / 导出 */
/*============================================================================*/ /*============================================================================*/


/** /**
@@ -182,41 +182,41 @@ uint8_t PlsrParamBlockApplyFromHold(void)
uint16_t base; uint16_t base;
uint16_t fault = PLSR_ERR_NONE; uint16_t fault = PLSR_ERR_NONE;


g_plsr_config.pulse_y = ReadHoldReg(PLSR_REG_PULSE_Y); /* 脉冲端子 Y0~Y2 */
g_plsr_config.pulse_y = ReadHoldReg(PLSR_REG_PULSE_Y);
if (g_plsr_config.pulse_y > 2U) if (g_plsr_config.pulse_y > 2U)
{ {
fault = PLSR_ERR_PULSE_Y; /* 0x07:端子非法 */
fault = PLSR_ERR_PULSE_Y;
} }


g_plsr_config.dir_y = ReadHoldReg(PLSR_REG_DIR_Y); /* 方向端子须为 Y3 */
g_plsr_config.dir_y = ReadHoldReg(PLSR_REG_DIR_Y);
if (g_plsr_config.dir_y != 3U) if (g_plsr_config.dir_y != 3U)
{ {
fault = PLSR_ERR_DIR_Y; /* 0x08 */
fault = PLSR_ERR_DIR_Y;
} }


g_plsr_config.wait_x_sel = ReadHoldReg(PLSR_REG_WAIT_X) ? 1U : 0U; /* 0=X4,1=X5 */
g_plsr_config.ext_x_sel = ReadHoldReg(PLSR_REG_EXT_X) ? 1U : 0U; /* 0=X4,1=X5 */
g_plsr_config.wait_x_sel = ReadHoldReg(PLSR_REG_WAIT_X) ? 1U : 0U;
g_plsr_config.ext_x_sel = ReadHoldReg(PLSR_REG_EXT_X) ? 1U : 0U;
g_plsr_config.send_mode = (PlsrSendMode_e)(ReadHoldReg(PLSR_REG_SEND_MODE) ? 1U : 0U); g_plsr_config.send_mode = (PlsrSendMode_e)(ReadHoldReg(PLSR_REG_SEND_MODE) ? 1U : 0U);
g_plsr_config.dir_delay_ms = ReadHoldReg(PLSR_REG_DIR_DELAY); /* 换向延时 ms */
g_plsr_config.dir_delay_ms = ReadHoldReg(PLSR_REG_DIR_DELAY);
g_plsr_config.dir_logic = (ReadHoldReg(PLSR_REG_DIR_LOGIC) != 0U) ? g_plsr_config.dir_logic = (ReadHoldReg(PLSR_REG_DIR_LOGIC) != 0U) ?
PLSR_DIR_LOGIC_NEG : PLSR_DIR_LOGIC_POS; /* 方向电平逻辑 */
PLSR_DIR_LOGIC_NEG : PLSR_DIR_LOGIC_POS;
g_plsr_config.accel_mode = (PlsrAccelMode_e)ReadHoldReg(PLSR_REG_ACCEL_MODE); g_plsr_config.accel_mode = (PlsrAccelMode_e)ReadHoldReg(PLSR_REG_ACCEL_MODE);
g_plsr_config.run_mode = (ReadHoldReg(PLSR_REG_RUN_MODE) != 0U) ? g_plsr_config.run_mode = (ReadHoldReg(PLSR_REG_RUN_MODE) != 0U) ?
PLSR_POS_ABSOLUTE : PLSR_POS_RELATIVE; /* 绝对/相对 */
PLSR_POS_ABSOLUTE : PLSR_POS_RELATIVE;


n = ReadHoldReg(PLSR_REG_SEG_COUNT); n = ReadHoldReg(PLSR_REG_SEG_COUNT);
g_plsr_config.seg_count = n; g_plsr_config.seg_count = n;
if ((n < 1U) || (n > PLSR_SEG_MAX)) if ((n < 1U) || (n > PLSR_SEG_MAX))
{ {
fault = PLSR_ERR_SEG_COUNT; /* 0x09:段数越界 */
fault = PLSR_ERR_SEG_COUNT;
} }


g_plsr_config.start_seg = ReadHoldReg(PLSR_REG_START_SEG); /* 1-based 启动段 */
g_plsr_config.start_seg = ReadHoldReg(PLSR_REG_START_SEG);
if ((n >= 1U) && (n <= PLSR_SEG_MAX)) if ((n >= 1U) && (n <= PLSR_SEG_MAX))
{ {
if ((g_plsr_config.start_seg < 1U) || (g_plsr_config.start_seg > n)) if ((g_plsr_config.start_seg < 1U) || (g_plsr_config.start_seg > n))
{ {
fault = PLSR_ERR_START_SEG; /* 0x0A:启动段越界 */
fault = PLSR_ERR_START_SEG;
} }
} }
else if (g_plsr_config.start_seg < 1U) else if (g_plsr_config.start_seg < 1U)
@@ -227,23 +227,23 @@ uint8_t PlsrParamBlockApplyFromHold(void)
g_plsr_config.default_speed = PlsrParamReadDWord(PLSR_REG_DEFAULT_SPD_L); g_plsr_config.default_speed = PlsrParamReadDWord(PLSR_REG_DEFAULT_SPD_L);
if (PlsrParamIsSpeedHzValid(g_plsr_config.default_speed) == 0U) if (PlsrParamIsSpeedHzValid(g_plsr_config.default_speed) == 0U)
{ {
fault = PLSR_ERR_DEFAULT_SPD; /* 0x0B:默认速度非法 */
fault = PLSR_ERR_DEFAULT_SPD;
} }


g_plsr_config.start_speed = PlsrParamReadDWord(PLSR_REG_START_SPD_L); /* 起跳频,0 合法 */
g_plsr_config.start_speed = PlsrParamReadDWord(PLSR_REG_START_SPD_L);
if (PlsrParamIsStartEndSpeedValid(g_plsr_config.start_speed) == 0U) if (PlsrParamIsStartEndSpeedValid(g_plsr_config.start_speed) == 0U)
{ {
fault = PLSR_ERR_START_END_SPD; fault = PLSR_ERR_START_END_SPD;
} }


g_plsr_config.end_speed = PlsrParamReadDWord(PLSR_REG_END_SPD_L); /* 止速,0 合法 */
g_plsr_config.end_speed = PlsrParamReadDWord(PLSR_REG_END_SPD_L);
if (PlsrParamIsStartEndSpeedValid(g_plsr_config.end_speed) == 0U) if (PlsrParamIsStartEndSpeedValid(g_plsr_config.end_speed) == 0U)
{ {
fault = PLSR_ERR_START_END_SPD; fault = PLSR_ERR_START_END_SPD;
} }


g_plsr_config.accel_ms = ReadHoldReg(PLSR_REG_ACCEL_MS); /* 加速参考时间 */
g_plsr_config.decel_ms = ReadHoldReg(PLSR_REG_DECEL_MS); /* 减速参考时间 */
g_plsr_config.accel_ms = ReadHoldReg(PLSR_REG_ACCEL_MS);
g_plsr_config.decel_ms = ReadHoldReg(PLSR_REG_DECEL_MS);


if ((n >= 1U) && (n <= PLSR_SEG_MAX)) if ((n >= 1U) && (n <= PLSR_SEG_MAX))
{ {
@@ -254,32 +254,32 @@ uint8_t PlsrParamBlockApplyFromHold(void)
(int32_t)PlsrParamReadDWord((uint16_t)(base + PLSR_SEG_OFF_FREQ_L)); (int32_t)PlsrParamReadDWord((uint16_t)(base + PLSR_SEG_OFF_FREQ_L));
if (PlsrParamIsSegFreqValid(g_plsr_segs[i].freq_hz) == 0U) if (PlsrParamIsSegFreqValid(g_plsr_segs[i].freq_hz) == 0U)
{ {
fault = PLSR_ERR_FREQ_ILLEGAL; /* 0x04:段频率非法 */
fault = PLSR_ERR_FREQ_ILLEGAL;
} }


g_plsr_segs[i].pulse_cnt = g_plsr_segs[i].pulse_cnt =
(int32_t)PlsrParamReadDWord((uint16_t)(base + PLSR_SEG_OFF_PULSE_L)); (int32_t)PlsrParamReadDWord((uint16_t)(base + PLSR_SEG_OFF_PULSE_L));
if (PlsrParamIsPulseCntValid(g_plsr_segs[i].pulse_cnt) == 0U) if (PlsrParamIsPulseCntValid(g_plsr_segs[i].pulse_cnt) == 0U)
{ {
fault = PLSR_ERR_PULSE_RANGE; /* 0x05:脉冲数 INT_MIN */
fault = PLSR_ERR_PULSE_RANGE;
} }


g_plsr_segs[i].wait_type = g_plsr_segs[i].wait_type =
(PlsrWaitType_e)ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT)); (PlsrWaitType_e)ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT));
g_plsr_segs[i].wait_ms = g_plsr_segs[i].wait_ms =
ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT_MS)); /* 段后等待 ms */
ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_WAIT_MS));
g_plsr_segs[i].act_ms = g_plsr_segs[i].act_ms =
ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_ACT_MS)); /* ACT 定时 ms */
ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_ACT_MS));
g_plsr_segs[i].jump_seg = g_plsr_segs[i].jump_seg =
ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_JUMP)); /* 跳转目标段 */
ReadHoldReg((uint16_t)(base + PLSR_SEG_OFF_JUMP));
} }
} }


PlsrCommandSetFault(fault); /* 写 0x2006 镜像 */
PlsrCommandSetFault(fault);


if (fault == PLSR_ERR_NONE) if (fault == PLSR_ERR_NONE)
{ {
return 1U; /* 可落存 BKP */
return 1U;
} }
return 0U; return 0U;
} }
@@ -302,33 +302,33 @@ void PlsrParamBlockOnHoldWrite(uint16_t start_addr, uint16_t quantity)
if ((start_addr == PLSR_REG_COMMON_F1_BASE) && if ((start_addr == PLSR_REG_COMMON_F1_BASE) &&
(quantity >= PLSR_PARAM_COMMON_FRAME1_WORDS)) (quantity >= PLSR_PARAM_COMMON_FRAME1_WORDS))
{ {
/* 公共帧 1:开新一批,期望 5+段数 */
uint16_t seg_n = ReadHoldReg(PLSR_REG_SEG_COUNT); uint16_t seg_n = ReadHoldReg(PLSR_REG_SEG_COUNT);
if (seg_n > PLSR_SEG_MAX) if (seg_n > PLSR_SEG_MAX)
{ {
seg_n = (uint16_t)PLSR_SEG_MAX; /* 计数软钳,避免 expect 溢出 */
seg_n = (uint16_t)PLSR_SEG_MAX;
} }
s_expect_frames = (uint16_t)(PLSR_PARAM_COMMON_FRAMES + seg_n); s_expect_frames = (uint16_t)(PLSR_PARAM_COMMON_FRAMES + seg_n);
s_recv_frames = 1U; /* 帧 1 已计入 */
s_xfer_active = 1U; /* 开始收批 */
s_recv_frames = 1U;
s_xfer_active = 1U;
} }
else if ((s_xfer_active != 0U) && else if ((s_xfer_active != 0U) &&
((PlsrParamIsCommonTailFrameWrite(start_addr, quantity) != 0U) || ((PlsrParamIsCommonTailFrameWrite(start_addr, quantity) != 0U) ||
(PlsrParamIsSegFrameWrite(start_addr, quantity) != 0U))) (PlsrParamIsSegFrameWrite(start_addr, quantity) != 0U)))
{ {
s_recv_frames++; /* 公共帧 2~5 或段帧 +1 */
s_recv_frames++;
} }
else else
{ {
return; /* 非本批帧 / 未开批 → 忽略 */
return;
} }


if ((s_xfer_active != 0U) && (s_recv_frames >= s_expect_frames)) if ((s_xfer_active != 0U) && (s_recv_frames >= s_expect_frames))
{ {
s_xfer_active = 0U; /* 收齐 */
s_xfer_active = 0U;
if (s_param_sem != (OS_EVENT *)0) if (s_param_sem != (OS_EVENT *)0)
{ {
(void)OSSemPost(s_param_sem); /* 唤醒 ParamBlockTask */
(void)OSSemPost(s_param_sem);
} }
} }
} }
@@ -364,7 +364,7 @@ void PlsrParamBlockTask(void *pArg)


if (PlsrParamBlockApplyFromHold() != 0U) if (PlsrParamBlockApplyFromHold() != 0U)
{ {
PlsrPersistSaveParamsFromHold(); /* 仅全部校验通过才存 BKP */
PlsrPersistSaveParamsFromHold();
} }
} }
} }

+ 52
- 52
plsr/param/plsr_param.h 查看文件

@@ -41,56 +41,56 @@
#define PLSR_SEG_MAX 10U #define PLSR_SEG_MAX 10U


/* ---------- 公共参数保持寄存器(0x1000 起,共 20 字到 0x1013) ---------- */ /* ---------- 公共参数保持寄存器(0x1000 起,共 20 字到 0x1013) ---------- */
#define PLSR_REG_PULSE_Y 0x1000U /* 脉冲端子:0=Y0 1=Y1 2=Y2 */
#define PLSR_REG_DIR_Y 0x1001U /* 方向端子:固件强制 3=Y3 */
#define PLSR_REG_WAIT_X 0x1002U /* WAIT 输入选择:0=X4 1=X5 */
#define PLSR_REG_EXT_X 0x1003U /* EXT 输入选择:0=X4 1=X5 */
#define PLSR_REG_SEND_MODE 0x1004U /* 发送方式:0完成 1后续 */
#define PLSR_REG_DIR_DELAY 0x1005U /* 方向建立延时 ms */
#define PLSR_REG_DIR_LOGIC 0x1006U /* 方向逻辑:0正 1负 */
#define PLSR_REG_ACCEL_MODE 0x1007U /* 曲线:0直线 1=S 2正弦 */
#define PLSR_REG_RUN_MODE 0x1008U /* 定位:0相对 1绝对 */
#define PLSR_REG_SEG_COUNT 0x1009U /* 脉冲总段数 N(决定 expect=5+N) */
#define PLSR_REG_START_SEG 0x100AU /* 启动段号 1-based */
#define PLSR_REG_DEFAULT_SPD_L 0x100BU /* 默认速度 Hz,双字低 */
#define PLSR_REG_PULSE_Y 0x1000U
#define PLSR_REG_DIR_Y 0x1001U
#define PLSR_REG_WAIT_X 0x1002U
#define PLSR_REG_EXT_X 0x1003U
#define PLSR_REG_SEND_MODE 0x1004U
#define PLSR_REG_DIR_DELAY 0x1005U
#define PLSR_REG_DIR_LOGIC 0x1006U
#define PLSR_REG_ACCEL_MODE 0x1007U
#define PLSR_REG_RUN_MODE 0x1008U
#define PLSR_REG_SEG_COUNT 0x1009U
#define PLSR_REG_START_SEG 0x100AU
#define PLSR_REG_DEFAULT_SPD_L 0x100BU
#define PLSR_REG_DEFAULT_SPD_H 0x100CU #define PLSR_REG_DEFAULT_SPD_H 0x100CU
#define PLSR_REG_START_SPD_L 0x100DU /* 起速 Hz */
#define PLSR_REG_START_SPD_L 0x100DU
#define PLSR_REG_START_SPD_H 0x100EU #define PLSR_REG_START_SPD_H 0x100EU
/* 0x100F 保留,写帧填 0 */
#define PLSR_REG_END_SPD_L 0x1010U /* 止速 Hz */
#define PLSR_REG_END_SPD_L 0x1010U
#define PLSR_REG_END_SPD_H 0x1011U #define PLSR_REG_END_SPD_H 0x1011U
#define PLSR_REG_ACCEL_MS 0x1012U /* 默认速度加速时间 ms */
#define PLSR_REG_DECEL_MS 0x1013U /* 默认速度减速时间 ms */
#define PLSR_REG_ACCEL_MS 0x1012U
#define PLSR_REG_DECEL_MS 0x1013U


/* ---------- 公共参数分帧(5 帧 + N 段帧) ---------- */ /* ---------- 公共参数分帧(5 帧 + N 段帧) ---------- */
#define PLSR_PARAM_COMMON_FRAMES 5U #define PLSR_PARAM_COMMON_FRAMES 5U
#define PLSR_PARAM_COMMON_FRAME1_WORDS 11U /* 0x1000~0x100A */
#define PLSR_PARAM_COMMON_DWORD_WORDS 2U /* 双字帧字数 */
#define PLSR_PARAM_COMMON_FRAME1_WORDS 11U
#define PLSR_PARAM_COMMON_DWORD_WORDS 2U


#define PLSR_REG_COMMON_F1_BASE PLSR_REG_PULSE_Y /* 0x1000 */
#define PLSR_REG_COMMON_F1_END PLSR_REG_START_SEG /* 0x100A */
#define PLSR_REG_COMMON_F2_BASE PLSR_REG_DEFAULT_SPD_L /* 0x100B */
#define PLSR_REG_COMMON_F3_BASE PLSR_REG_START_SPD_L /* 0x100D */
#define PLSR_REG_COMMON_F4_BASE PLSR_REG_END_SPD_L /* 0x1010 */
#define PLSR_REG_COMMON_F5_BASE PLSR_REG_ACCEL_MS /* 0x1012 */
#define PLSR_REG_COMMON_F1_BASE PLSR_REG_PULSE_Y
#define PLSR_REG_COMMON_F1_END PLSR_REG_START_SEG
#define PLSR_REG_COMMON_F2_BASE PLSR_REG_DEFAULT_SPD_L
#define PLSR_REG_COMMON_F3_BASE PLSR_REG_START_SPD_L
#define PLSR_REG_COMMON_F4_BASE PLSR_REG_END_SPD_L
#define PLSR_REG_COMMON_F5_BASE PLSR_REG_ACCEL_MS


/* ---------- 段参数:第 i 段基址 = 0x1100 + i*0x10,每段 8 字 ---------- */ /* ---------- 段参数:第 i 段基址 = 0x1100 + i*0x10,每段 8 字 ---------- */
#define PLSR_REG_SEG1_BASE 0x1100U #define PLSR_REG_SEG1_BASE 0x1100U
#define PLSR_SEG_STRIDE 0x0010U #define PLSR_SEG_STRIDE 0x0010U


#define PLSR_SEG_OFF_FREQ_L 0U /* 目标频率 SDW;0=用 default_speed */
#define PLSR_SEG_OFF_FREQ_L 0U
#define PLSR_SEG_OFF_FREQ_H 1U #define PLSR_SEG_OFF_FREQ_H 1U
#define PLSR_SEG_OFF_PULSE_L 2U /* 脉冲数/绝对坐标 SDW,负=反转 */
#define PLSR_SEG_OFF_PULSE_L 2U
#define PLSR_SEG_OFF_PULSE_H 3U #define PLSR_SEG_OFF_PULSE_H 3U
#define PLSR_SEG_OFF_WAIT 4U /* PlsrWaitType_e */
#define PLSR_SEG_OFF_WAIT_MS 5U /* WAIT 时间 ms */
#define PLSR_SEG_OFF_ACT_MS 6U /* ACT 时间 ms */
#define PLSR_SEG_OFF_JUMP 7U /* 0=顺序/末段停;1~N=跳转目标段号 */
#define PLSR_SEG_OFF_WAIT 4U
#define PLSR_SEG_OFF_WAIT_MS 5U
#define PLSR_SEG_OFF_ACT_MS 6U
#define PLSR_SEG_OFF_JUMP 7U


/** 方向逻辑:正转时方向脚电平 */ /** 方向逻辑:正转时方向脚电平 */
typedef enum { typedef enum {
PLSR_DIR_LOGIC_POS = 0, /* 正转→方向高,反转→低 */
PLSR_DIR_LOGIC_NEG = 1 /* 相反 */
PLSR_DIR_LOGIC_POS = 0,
PLSR_DIR_LOGIC_NEG = 1
} PlsrDirLogic_e; } PlsrDirLogic_e;


/** /**
@@ -105,9 +105,9 @@ typedef enum {


/** 加减速曲线形状 */ /** 加减速曲线形状 */
typedef enum { typedef enum {
PLSR_ACCEL_LINEAR = 0, /* f^2 = f0^2 ± 2an */
PLSR_ACCEL_S = 1, /* 时间域七段 S:加速度梯形 1:2:1 */
PLSR_ACCEL_SINE = 2 /* 时间域 raised-cosine */
PLSR_ACCEL_LINEAR = 0,
PLSR_ACCEL_S = 1,
PLSR_ACCEL_SINE = 2
} PlsrAccelMode_e; } PlsrAccelMode_e;


/** /**
@@ -127,43 +127,43 @@ typedef enum {
* 与下一段反向时规划同其它等待(减速到止速,下一段从起速再爬) * 与下一段反向时规划同其它等待(减速到止速,下一段从起速再爬)
*/ */
typedef enum { typedef enum {
PLSR_WAIT_TIME = 0, /* 发完后等 wait_ms(0 按 1ms),再跳转 */
PLSR_WAIT_SIGNAL = 1, /* 发完后等 WAIT 口下降沿 */
PLSR_WAIT_ACT = 2, /* 开跑后满 act_ms 从当前频切下一段;脉冲先完则等到点 */
PLSR_WAIT_EXT = 3, /* 运行中 EXT 沿中途切段;发完后仍等 EXT */
PLSR_WAIT_EXT_OR_DONE = 4 /* EXT 沿或脉冲发完,先到先切 */
PLSR_WAIT_TIME = 0,
PLSR_WAIT_SIGNAL = 1,
PLSR_WAIT_ACT = 2,
PLSR_WAIT_EXT = 3,
PLSR_WAIT_EXT_OR_DONE = 4
} PlsrWaitType_e; } PlsrWaitType_e;


/** /**
* 公共运行参数映像 * 公共运行参数映像
*/ */
typedef struct { typedef struct {
uint16_t pulse_y; /* 0=Y0/TIM10 1=Y1/TIM13 2=Y2/TIM11 */
uint16_t dir_y; /* 固定 3=Y3 */
uint16_t wait_x_sel; /* 0=X4 1=X5 */
uint16_t pulse_y;
uint16_t dir_y;
uint16_t wait_x_sel;
uint16_t ext_x_sel; uint16_t ext_x_sel;
PlsrSendMode_e send_mode; PlsrSendMode_e send_mode;
uint16_t dir_delay_ms; uint16_t dir_delay_ms;
PlsrDirLogic_e dir_logic; PlsrDirLogic_e dir_logic;
PlsrAccelMode_e accel_mode; PlsrAccelMode_e accel_mode;
PlsrPosMode_e run_mode; PlsrPosMode_e run_mode;
uint16_t seg_count; /* 有效段数 0~PLSR_SEG_MAX */
uint16_t start_seg; /* 1-based */
uint32_t default_speed; /* Hz;段频为 0 时作段目标;并定斜率 */
uint32_t start_speed; /* 起速;0=运行层 ResolveStartHz 起跳 */
uint32_t end_speed; /* 止速;0=ResolveEndHz 落地后停表 */
uint16_t seg_count;
uint16_t start_seg;
uint32_t default_speed;
uint32_t start_speed;
uint32_t end_speed;
uint16_t accel_ms; uint16_t accel_ms;
uint16_t decel_ms; uint16_t decel_ms;
} PlsrCfg_t; } PlsrCfg_t;


/** 单段运行参数 */ /** 单段运行参数 */
typedef struct { typedef struct {
int32_t freq_hz; /* 0=用默认速度;解析后须在 1~100k,否则 0x04 */
int32_t pulse_cnt; /* 可负=反向;0=本段不发 */
int32_t freq_hz;
int32_t pulse_cnt;
PlsrWaitType_e wait_type; PlsrWaitType_e wait_type;
uint16_t wait_ms; uint16_t wait_ms;
uint16_t act_ms; uint16_t act_ms;
uint16_t jump_seg; /* 0=顺序/末段结束;1~N=跳转 */
uint16_t jump_seg;
} PlsrSeg_t; } PlsrSeg_t;


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


+ 13
- 13
plsr/plsr.c 查看文件

@@ -27,16 +27,16 @@
*/ */
void PlsrInit(void) void PlsrInit(void)
{ {
PlsrPersistInit(); /* 使能 BKPSRAM 写访问,否则存BKP无效 */
PlsrPersistLoad(); /* BKPSRAM → g_hold_reg */
(void)PlsrParamBlockApplyFromHold(); /* hold → 运行参数 + 校验 */
PlsrPersistInit();
PlsrPersistLoad();
(void)PlsrParamBlockApplyFromHold();
PlsrPulseDriverInit(); PlsrPulseDriverInit();
PlsrSignalIoInit(); PlsrSignalIoInit();
PlsrRunControlInit(); PlsrRunControlInit();
PlsrPersistRestoreRuntime(); /* hold 0x2000 累计 → run_control */
PlsrPersistRestoreRuntime();
PlsrCommandInit(); PlsrCommandInit();
PlsrPersistRestoreMonitor(); /* 恢复故障码;0x3000/运行态强制空闲 */
PlsrPersistTickMonitor(); /* 监控区 hold+BKP 与运行态对齐 */
PlsrPersistRestoreMonitor();
PlsrPersistTickMonitor();
} }


/** /**
@@ -50,11 +50,11 @@ void PlsrInit(void)
*/ */
void PlsrTask(void *pArg) void PlsrTask(void *pArg)
{ {
static uint8_t s_booted = 0U; /* 1=已完成首次延迟对齐(等 Modbus 填 hold) */
static uint8_t s_booted = 0U;


(void)pArg; (void)pArg;


PlsrRunControlWakeInit(); /* OS 已启动,创建 WAIT/ACT 到期唤醒信号量 */
PlsrRunControlWakeInit();


while(1) while(1)
{ {
@@ -64,17 +64,17 @@ void PlsrTask(void *pArg)
*/ */
if (s_booted == 0U) if (s_booted == 0U)
{ {
OSTimeDly(3U); /* ~30ms @ 100Hz tick;让出 CPU 给 Modbus 完成初始化 */
OSTimeDly(3U);
PlsrCommandInit(); PlsrCommandInit();
PlsrPersistRestoreMonitor(); PlsrPersistRestoreMonitor();
PlsrPersistTickMonitor(); PlsrPersistTickMonitor();
s_booted = 1U; s_booted = 1U;
} }


PlsrRunControlTickMs(); /* 处理延时/外部信号输入,优先:WAIT/换向到期立刻开表 */
PlsrSignalIoDebouncePoll(); /* OS 节拍消抖确认 */
PlsrCommandPoll(); /* 收 START/STOP/CLR,回写 0x2000~0x2006 监控 ,决定是否开pwm输出*/
PlsrPersistTickMonitor(); /* 监控区:运行态→hold→BKP(每 OS 节拍) */
PlsrRunControlTickMs();
PlsrSignalIoDebouncePoll();
PlsrCommandPoll();
PlsrPersistTickMonitor();


/* /*
* 换向 / WAIT 时间:WakePend(0) 只等 TIM5 Post(墙钟≈设定 ms)。 * 换向 / WAIT 时间:WakePend(0) 只等 TIM5 Post(墙钟≈设定 ms)。


+ 3
- 4
plsr/plsr.h 查看文件

@@ -24,10 +24,9 @@


#include <stdint.h> #include <stdint.h>


/* run_control 拥有的共享运行状态;段下标从 0 开始。 */
extern volatile uint8_t g_plsr_busy; /* 运行忙标志(上位机监控) */
extern volatile uint16_t g_plsr_cur_seg_idx; /* 当前段下标(0-based) */
extern volatile int32_t g_plsr_accumulated_pulses; /* 全局累计脉冲(有符号) */
extern volatile uint8_t g_plsr_busy;
extern volatile uint16_t g_plsr_cur_seg_idx;
extern volatile int32_t g_plsr_accumulated_pulses;
#include "plsr_param.h" #include "plsr_param.h"


/** /**


+ 261
- 282
plsr/pulse_driver/plsr_pulse_driver.c
文件差異過大導致無法顯示
查看文件


+ 4
- 5
plsr/pulse_driver/plsr_pulse_driver.h 查看文件

@@ -34,11 +34,10 @@ extern TIM_HandleTypeDef htim10;
extern TIM_HandleTypeDef htim11; extern TIM_HandleTypeDef htim11;
extern TIM_HandleTypeDef htim13; extern TIM_HandleTypeDef htim13;


/* 驱动拥有的真实输出状态,run_control 直接读取,不再保存第二份。 */
extern volatile uint32_t g_plsr_output_freq_hz; /* 当前输出频率 Hz */
extern volatile uint8_t g_plsr_pwm_running; /* 1=PWM 正在跑 */
extern uint8_t g_plsr_direction_forward; /* 1=正转方向语义 */
extern uint8_t g_plsr_direction_valid; /* 1=方向脚已有效写出 */
extern volatile uint32_t g_plsr_output_freq_hz;
extern volatile uint8_t g_plsr_pwm_running;
extern uint8_t g_plsr_direction_forward;
extern uint8_t g_plsr_direction_valid;


/** /**
* @brief 初始化三路脉冲 TIM + 方向 GPIO * @brief 初始化三路脉冲 TIM + 方向 GPIO


+ 715
- 789
plsr/run_control/plsr_run_control.c
文件差異過大導致無法顯示
查看文件


+ 25
- 25
plsr/signal_io/plsr_signal_io.c 查看文件

@@ -34,16 +34,16 @@


/* ---------- 硬件引脚 ---------- */ /* ---------- 硬件引脚 ---------- */
#define PLSR_X4_PORT GPIOB #define PLSR_X4_PORT GPIOB
#define PLSR_X4_PIN GPIO_PIN_5 /* X4:WAIT/EXT 可选 */
#define PLSR_X4_PIN GPIO_PIN_5
#define PLSR_X5_PORT GPIOG #define PLSR_X5_PORT GPIOG
#define PLSR_X5_PIN GPIO_PIN_12 /* X5:WAIT/EXT 可选 */
#define PLSR_X5_PIN GPIO_PIN_12


/* /*
* TIM5 时基:84MHz / (8399+1) = 10kHz → 100µs/格。 * TIM5 时基:84MHz / (8399+1) = 10kHz → 100µs/格。
* PSC=8399 落在 16 位内 * PSC=8399 落在 16 位内
*/ */
#define PLSR_TIM5_PSC_100US 8399U #define PLSR_TIM5_PSC_100US 8399U
#define PLSR_TIM5_TICKS_PER_MS 10U /* 10×100µs = 1ms */
#define PLSR_TIM5_TICKS_PER_MS 10U
#define PLSR_DELAY_MS_MAX 65535U #define PLSR_DELAY_MS_MAX 65535U


/** OS 节拍消抖窗口(ms),与 PlsrTask tick 配合 */ /** OS 节拍消抖窗口(ms),与 PlsrTask tick 配合 */
@@ -51,17 +51,17 @@


/** 单路 X 口消抖状态(pending / fell 由 ISR 与任务共享,volatile) */ /** 单路 X 口消抖状态(pending / fell 由 ISR 与任务共享,volatile) */
typedef struct { typedef struct {
volatile uint8_t pending; /* 1=EXTI 已见下降沿,待 Confirm */
volatile uint8_t stamp_ok; /* 1=已记 arm_tick,正在计时 */
volatile INT32U arm_tick; /* 消抖起点 OS tick */
volatile uint8_t fell; /* 1=消抖确认的有效下降沿,Take* 消费 */
volatile uint8_t pending;
volatile uint8_t stamp_ok;
volatile INT32U arm_tick;
volatile uint8_t fell;
GPIO_TypeDef *port; GPIO_TypeDef *port;
uint16_t pin; uint16_t pin;
} PlsrEdge_t; } PlsrEdge_t;


static PlsrEdge_t s_debounce_x4; /* X4 消抖状态 */
static PlsrEdge_t s_debounce_x5; /* X5 消抖状态 */
static volatile uint8_t s_delay_armed; /* 1=TIM5 单次延时正在计时 */
static PlsrEdge_t s_debounce_x4;
static PlsrEdge_t s_debounce_x5;
static volatile uint8_t s_delay_armed;


/** 毫秒 → OS tick 数(向上取整,至少 1 tick) */ /** 毫秒 → OS tick 数(向上取整,至少 1 tick) */
static INT32U PlsrSignalIoMsToTicks(uint32_t ms) static INT32U PlsrSignalIoMsToTicks(uint32_t ms)
@@ -164,14 +164,14 @@ static void PlsrSignalIoTim5Init(void)
{ {
__HAL_RCC_TIM5_CLK_ENABLE(); __HAL_RCC_TIM5_CLK_ENABLE();


TIM5->CR1 = 0U; /* 停表:向上计、关 OPM */
TIM5->DIER = 0U; /* 关 UPDATE 中断 */
TIM5->SR = 0U; /* 清状态标志 */
TIM5->PSC = PLSR_TIM5_PSC_100US; /* PSC=8399 → 10kHz(100µs/格),非 1MHz */
TIM5->ARR = 0xFFFFFFFFUL; /* 预装最大 ARR,真正延时在 Schedule 重写 */
TIM5->CR1 = 0U;
TIM5->DIER = 0U;
TIM5->SR = 0U;
TIM5->PSC = PLSR_TIM5_PSC_100US;
TIM5->ARR = 0xFFFFFFFFUL;
TIM5->CNT = 0U; TIM5->CNT = 0U;
TIM5->EGR = TIM_EGR_UG; /* UG:PSC 立刻生效(会置 UIF) */
TIM5->SR = 0U; /* 清 UG 带来的 UIF */
TIM5->EGR = TIM_EGR_UG;
TIM5->SR = 0U;


HAL_NVIC_SetPriority(TIM5_IRQn, 7, 0); HAL_NVIC_SetPriority(TIM5_IRQn, 7, 0);
HAL_NVIC_EnableIRQ(TIM5_IRQn); HAL_NVIC_EnableIRQ(TIM5_IRQn);
@@ -198,7 +198,7 @@ void PlsrSignalIoInit(void)


PlsrSignalIoGpioExtiInit(); PlsrSignalIoGpioExtiInit();
PlsrSignalIoTim5Init(); PlsrSignalIoTim5Init();
/* 配完 NVIC 后再清一次,避免配置期误沿 */
__HAL_GPIO_EXTI_CLEAR_IT(PLSR_X4_PIN); __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X4_PIN);
__HAL_GPIO_EXTI_CLEAR_IT(PLSR_X5_PIN); __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X5_PIN);
s_debounce_x4.fell = 0U; s_debounce_x4.fell = 0U;
@@ -229,13 +229,13 @@ void PlsrSignalIoScheduleDelayMs(uint32_t delay_ms)
TIM5->SR = 0U; TIM5->SR = 0U;
TIM5->PSC = PLSR_TIM5_PSC_100US; TIM5->PSC = PLSR_TIM5_PSC_100US;
TIM5->ARR = ticks - 1U; TIM5->ARR = ticks - 1U;
TIM5->CR1 = TIM_CR1_URS; /* 仅溢出产生 UPDATE */
TIM5->EGR = TIM_EGR_UG; /* PSC/ARR 立刻生效 */
TIM5->SR = 0U; /* 清 UG 带来的 UIF */
TIM5->CR1 = TIM_CR1_URS;
TIM5->EGR = TIM_EGR_UG;
TIM5->SR = 0U;
TIM5->CNT = 0U; TIM5->CNT = 0U;
TIM5->DIER = TIM_DIER_UIE; TIM5->DIER = TIM_DIER_UIE;
s_delay_armed = 1U; s_delay_armed = 1U;
TIM5->CR1 = (uint32_t)(TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS); /* 开表单次 */
TIM5->CR1 = (uint32_t)(TIM_CR1_CEN | TIM_CR1_OPM | TIM_CR1_URS);
} }


/** @brief 取消 TIM5 延时并清武装 */ /** @brief 取消 TIM5 延时并清武装 */
@@ -305,7 +305,7 @@ void PlsrSignalIoClearPending(void)
/** @brief 取 WAIT 口有效下降沿(读后清) */ /** @brief 取 WAIT 口有效下降沿(读后清) */
uint8_t PlsrSignalIoTakeWaitFalling(void) uint8_t PlsrSignalIoTakeWaitFalling(void)
{ {
/* wait_x_sel:0=X4,1=X5 */
if (g_plsr_config.wait_x_sel == 0U) if (g_plsr_config.wait_x_sel == 0U)
{ {
if (s_debounce_x4.fell != 0U) if (s_debounce_x4.fell != 0U)
@@ -325,7 +325,7 @@ uint8_t PlsrSignalIoTakeWaitFalling(void)
/** @brief 取 EXT 口有效下降沿(读后清) */ /** @brief 取 EXT 口有效下降沿(读后清) */
uint8_t PlsrSignalIoTakeExtFalling(void) uint8_t PlsrSignalIoTakeExtFalling(void)
{ {
/* ext_x_sel:0=X4,1=X5 */
if (g_plsr_config.ext_x_sel == 0U) if (g_plsr_config.ext_x_sel == 0U)
{ {
if (s_debounce_x4.fell != 0U) if (s_debounce_x4.fell != 0U)
@@ -353,7 +353,7 @@ void PlsrSignalIoOnTim5Irq(void)
if (s_delay_armed != 0U) if (s_delay_armed != 0U)
{ {
s_delay_armed = 0U; s_delay_armed = 0U;
PlsrRunControlOnDelayTimer(); /* 方向/WAIT/ACT 到期 */
PlsrRunControlOnDelayTimer();
} }
} }
} }


Loading…
取消
儲存