| @@ -56,6 +56,9 @@ void DebugMon_Handler(void); | |||
| void PendSV_Handler(void); | |||
| void SysTick_Handler(void); | |||
| void TIM2_IRQHandler(void); | |||
| void TIM3_IRQHandler(void); | |||
| void EXTI9_5_IRQHandler(void); | |||
| void EXTI15_10_IRQHandler(void); | |||
| void TIM1_UP_TIM10_IRQHandler(void); | |||
| void TIM1_TRG_COM_TIM11_IRQHandler(void); | |||
| void TIM8_UP_TIM13_IRQHandler(void); | |||
| @@ -24,6 +24,7 @@ | |||
| /* USER CODE BEGIN Includes */ | |||
| #include "ucos_ii.h" | |||
| #include "os_cpu.h" | |||
| #include "plsr_signal_io.h" | |||
| /* USER CODE END Includes */ | |||
| /* Private typedef -----------------------------------------------------------*/ | |||
| @@ -223,6 +224,36 @@ void TIM2_IRQHandler(void) | |||
| OSIntExit(); | |||
| } | |||
| /** | |||
| * @brief TIM3:PLSR WAIT/ACT 1ms 时基 | |||
| */ | |||
| void TIM3_IRQHandler(void) | |||
| { | |||
| OSIntEnter(); | |||
| PlsrSignalIoOnTim3Irq(); | |||
| OSIntExit(); | |||
| } | |||
| /** | |||
| * @brief EXTI5~9:X4=PB5 下降沿 | |||
| */ | |||
| void EXTI9_5_IRQHandler(void) | |||
| { | |||
| OSIntEnter(); | |||
| PlsrSignalIoOnExti9_5(); | |||
| OSIntExit(); | |||
| } | |||
| /** | |||
| * @brief EXTI10~15:X5=PG12 下降沿 | |||
| */ | |||
| void EXTI15_10_IRQHandler(void) | |||
| { | |||
| OSIntEnter(); | |||
| PlsrSignalIoOnExti15_10(); | |||
| OSIntExit(); | |||
| } | |||
| /** | |||
| * @brief TIM1 Update / TIM10(PLSR Y0 脉冲计数) | |||
| */ | |||
| @@ -362,6 +362,7 @@ | |||
| <state>$PROJ_DIR$\..\plsr\accel_curve</state> | |||
| <state>$PROJ_DIR$\..\plsr\run_control</state> | |||
| <state>$PROJ_DIR$\..\plsr\command</state> | |||
| <state>$PROJ_DIR$\..\plsr\signal_io</state> | |||
| <state>$PROJ_DIR$\..\plsr\test</state> | |||
| <state>$PROJ_DIR$\..\ucos\uC-CPU</state> | |||
| <state>$PROJ_DIR$\..\ucos\uC-LIB\Ports</state> | |||
| @@ -2929,6 +2930,15 @@ | |||
| <name>$PROJ_DIR$\..\plsr\command\plsr_command.h</name> | |||
| </file> | |||
| </group> | |||
| <group> | |||
| <name>signal_io</name> | |||
| <file> | |||
| <name>$PROJ_DIR$\..\plsr\signal_io\plsr_signal_io.c</name> | |||
| </file> | |||
| <file> | |||
| <name>$PROJ_DIR$\..\plsr\signal_io\plsr_signal_io.h</name> | |||
| </file> | |||
| </group> | |||
| </group> | |||
| <group> | |||
| <name>ucos</name> | |||
| @@ -9,6 +9,7 @@ | |||
| * 已解决,原因是逻辑分析仪采样率不够,导致采样点减少,波形有毛刺。 | |||
| */ | |||
| #include "plsr_accel_curve.h" | |||
| #include <stdint.h> | |||
| /*频率大于100k时暂时固定到100k,后面增加报错*/ | |||
| uint32_t PlsrAccelCurveClampFreq(uint32_t freq_hz) | |||
| @@ -75,7 +76,7 @@ static uint32_t PlsrAccelCurveRampTimeMs(uint32_t f_from, | |||
| { | |||
| return 0U; | |||
| } | |||
| /* 默认速度未设时,用频差作分母:整段升降时间 = accel/decel_ms */ | |||
| /* 默认速度未设时,用频差作分母 */ | |||
| if (den == 0U) | |||
| { | |||
| den = df; | |||
| @@ -234,6 +235,73 @@ uint32_t PlsrAccelCurveFreqOnRampUs(uint32_t f0, | |||
| return PlsrAccelCurveLerp(f0, f1, r); | |||
| } | |||
| /** | |||
| * 1ms 时基取频(与 PlsrRunControlOn1ms 一致)。 | |||
| */ | |||
| uint32_t PlsrAccelCurveFreqOnRampMs(uint32_t f0, | |||
| uint32_t f1, | |||
| uint32_t t_ms, | |||
| uint32_t T_ms, | |||
| PlsrAccelMode_e mode) | |||
| { | |||
| uint32_t f; | |||
| if (T_ms < 1U) | |||
| { | |||
| return (f1 >= 1U) ? f1 : 1U; | |||
| } | |||
| if (mode == PLSR_ACCEL_LINEAR) | |||
| { | |||
| if ((f0 == 0U) && (f1 > 0U)) | |||
| { | |||
| uint32_t step = t_ms + 1U; | |||
| if (step >= T_ms) | |||
| { | |||
| return (f1 >= 1U) ? f1 : 1U; | |||
| } | |||
| f = (f1 * step) / T_ms; | |||
| if (f < 1U) | |||
| { | |||
| f = 1U; | |||
| } | |||
| return f; | |||
| } | |||
| if ((f1 == 0U) && (f0 > 0U)) | |||
| { | |||
| uint32_t step = t_ms + 1U; | |||
| uint32_t left; | |||
| if (step >= T_ms) | |||
| { | |||
| return 1U; | |||
| } | |||
| left = T_ms - step; | |||
| f = (f0 * left) / T_ms; | |||
| if (f < 1U) | |||
| { | |||
| f = 1U; | |||
| } | |||
| return f; | |||
| } | |||
| } | |||
| else if ((f0 == 0U) && (t_ms == 0U) && (f1 > 0U)) | |||
| { | |||
| f = f1 / T_ms; | |||
| if (f < 1U) | |||
| { | |||
| f = 1U; | |||
| } | |||
| return f; | |||
| } | |||
| f = PlsrAccelCurveFreqOnRampUs(f0, f1, t_ms * 1000UL, T_ms * 1000UL, mode); | |||
| if (f < 1U) | |||
| { | |||
| f = 1U; | |||
| } | |||
| return f; | |||
| } | |||
| /** | |||
| * 斜坡第一拍频率(规划/开跑共用)。 | |||
| * f0>=1:第一拍即 f0。 | |||
| @@ -286,8 +354,11 @@ uint32_t PlsrAccelCurveFirstPulseFreq(uint32_t f0, | |||
| } | |||
| /** | |||
| * 脉冲起点锁频递推脉冲数(与 ISR 一致);f(t) 按 mode 形状。 | |||
| * 脉冲起点锁频递推脉冲数(与每脉冲改频一致);f(t) 按 mode 形状。 | |||
| * 仅任务/规划上下文;禁止进脉冲 ISR。 | |||
| * | |||
| * 注意:不可再用「每 ms 贡献 f/1000」——低频时一个脉冲周期 >> 1ms, | |||
| * 那种估法会把 dec_n 估成 1,示波器上像没有减速。 | |||
| */ | |||
| static uint32_t PlsrAccelCurveEstimatePulses(uint32_t f_from, | |||
| uint32_t f_to, | |||
| @@ -321,7 +392,6 @@ static uint32_t PlsrAccelCurveEstimatePulses(uint32_t f_from, | |||
| } | |||
| else | |||
| { | |||
| /* 止速到 0:末段按 1Hz 计周期,与运行输出下限一致 */ | |||
| f = 1U; | |||
| } | |||
| } | |||
| @@ -2,10 +2,8 @@ | |||
| * @file plsr_accel_curve.h | |||
| * @brief 预估加/匀/减脉冲;相内按时间走直线/S/正弦 | |||
| * | |||
| * 相界按预估脉冲划分;预估与运行时一致:shape(t/T) + 脉冲起点锁频递推。 | |||
| * 完成方式非末段 f_end==f_tgt:不够则不减速,沿斜率加到脉冲用尽。 | |||
| * 后续方式非末段 f_end=下一段目标:段末过渡占用本段脉冲;不够则压峰/压缩过渡。 | |||
| * 末段(完成/后续)脉冲不够:降低峰值做三角到终止速度。 | |||
| * 相界按预估脉冲划分;预估与运行一致:shape(t/T) + 每脉冲改频、周期累加。 | |||
| * 斜率按公共参数:K≈(默认速度−起/止速)/加减速时间;小频差时 T 可能 <1ms,无可见斜坡属正常。 | |||
| */ | |||
| #ifndef PLSR_ACCEL_CURVE_H | |||
| #define PLSR_ACCEL_CURVE_H | |||
| @@ -43,6 +41,16 @@ uint32_t PlsrAccelCurveFreqOnRampUs(uint32_t f0, | |||
| uint32_t T_us, | |||
| PlsrAccelMode_e mode); | |||
| /** | |||
| * 与 TIM3 1ms 改频一致的斜坡取频(规划/运行共用)。 | |||
| * 直线起/止 0:离散台阶;其余走 shape。 | |||
| */ | |||
| uint32_t PlsrAccelCurveFreqOnRampMs(uint32_t f0, | |||
| uint32_t f1, | |||
| uint32_t t_ms, | |||
| uint32_t T_ms, | |||
| PlsrAccelMode_e mode); | |||
| /** | |||
| * 斜坡第一拍频率(起速为 0 时用自洽点,避免按 1Hz 整秒吃光加速相)。 | |||
| * ISR 可用:O(1)。 | |||
| @@ -81,11 +81,11 @@ typedef enum { | |||
| } PlsrPosMode_e; | |||
| typedef enum { | |||
| PLSR_WAIT_TIME = 0, /* WAIT 时间 */ | |||
| PLSR_WAIT_SIGNAL = 1, /* WAIT 信号(待实现) */ | |||
| PLSR_WAIT_ACT = 2, /* ACT 时间 */ | |||
| PLSR_WAIT_EXT = 3, /* EXT 信号(待实现) */ | |||
| PLSR_WAIT_EXT_OR_DONE = 4 /* EXT 或发完(当前等同立即继续) */ | |||
| PLSR_WAIT_TIME = 0, /* 发完后等 wait_ms,再跳转 */ | |||
| PLSR_WAIT_SIGNAL = 1, /* 发完后等 WAIT 口下降沿,再跳转 */ | |||
| PLSR_WAIT_ACT = 2, /* 出脉冲满 act_ms 后中途切段并立即跳转 */ | |||
| PLSR_WAIT_EXT = 3, /* 运行中 EXT 下降沿中途切段并立即跳转 */ | |||
| PLSR_WAIT_EXT_OR_DONE = 4 /* EXT 沿或脉冲发完,先到先跳转 */ | |||
| } PlsrWaitType_e; | |||
| /** 公共运行参数(运动侧只读此映像,不直接啃寄存器) */ | |||
| @@ -50,13 +50,12 @@ uint16_t PlsrPathPlanGetWaitMs(uint16_t seg_0based) | |||
| { | |||
| PlsrSeg_t *seg = PlsrParamGetSeg(seg_0based); | |||
| if ((seg->wait_type == PLSR_WAIT_TIME) || (seg->wait_type == PLSR_WAIT_ACT)) | |||
| /* 仅段后 WAIT 时间;0 按 1ms(手册);信号/ACT/EXT 由 run_control 处理 */ | |||
| if (seg->wait_type == PLSR_WAIT_TIME) | |||
| { | |||
| return (seg->wait_type == PLSR_WAIT_ACT) ? seg->act_ms : seg->wait_ms; | |||
| return (seg->wait_ms == 0U) ? 1U : seg->wait_ms; | |||
| } | |||
| /* WAIT_SIGNAL / EXT / EXT_OR_DONE:暂未接输入,按立即继续 */ | |||
| (void)seg; | |||
| (void)seg_0based; | |||
| return 0U; | |||
| } | |||
| @@ -3,7 +3,7 @@ | |||
| * @brief 多段路径规划:段序、跳转、段间等待、相对/绝对方向判定 | |||
| * | |||
| * 不直接驱动硬件;由运行控制查询后执行。 | |||
| * 5 类等待中目前仅 TIME/ACT 产生延时,其余返回 0(立即继续)。 | |||
| * 等待类型由 run_control + signal_io 执行(时间用 TIM3,信号用 EXTI)。 | |||
| */ | |||
| #ifndef PLSR_PATH_PLAN_H | |||
| #define PLSR_PATH_PLAN_H | |||
| @@ -26,8 +26,7 @@ int16_t PlsrPathPlanNextSeg(uint16_t cur_seg_0based); | |||
| uint8_t PlsrPathPlanIsForward(uint16_t seg_0based, int32_t acc_pulse); | |||
| /** | |||
| * @brief 段结束后需要等待的毫秒数 | |||
| * @return >0 进入等待;0 立即解析下一段 | |||
| * @brief 段结束后 WAIT 时间(ms);仅 WAIT_TIME 有效,0 按 1ms | |||
| */ | |||
| uint16_t PlsrPathPlanGetWaitMs(uint16_t seg_0based); | |||
| @@ -7,12 +7,14 @@ | |||
| #include "plsr_run_control.h" | |||
| #include "plsr_param.h" | |||
| #include "plsr_command.h" | |||
| #include "plsr_signal_io.h" | |||
| #include "ucos_ii.h" | |||
| void PlsrInit(void) | |||
| { | |||
| PlsrParamInitDefault(); | |||
| PlsrPulseDriverInit(); | |||
| PlsrSignalIoInit(); | |||
| PlsrRunControlInit(); | |||
| PlsrParamBlockExportToHold(); /* 上电把默认映像摊到保持寄存器 */ | |||
| PlsrCommandInit(); | |||
| @@ -293,14 +293,16 @@ void PlsrPulseDriverLockPscRange(uint32_t f_min_hz, uint32_t f_max_hz) | |||
| if (psc_div_lo > psc_div_hi) | |||
| { | |||
| /* 跨度过大:优先保证低频可表示 */ | |||
| div = psc_div_lo; | |||
| } | |||
| else | |||
| { | |||
| div = psc_div_lo; | |||
| /* | |||
| * 单一 PSC 无法同时覆盖 f_min~f_max(例如 1Hz~很高频)。 | |||
| * 不锁死,交由 SetFreq 按频率自适应 PSC,避免高频被算成平台方波。 | |||
| */ | |||
| s_psc_locked = 0U; | |||
| s_locked_psc = 0U; | |||
| return; | |||
| } | |||
| div = psc_div_lo; | |||
| s_locked_psc = div - 1UL; | |||
| s_psc_locked = 1U; | |||
| } | |||
| @@ -12,6 +12,7 @@ uint8_t PlsrRunControlStart(uint16_t start_seg_1based); | |||
| void PlsrRunControlStop(void); | |||
| uint8_t PlsrRunControlChangeFreq(uint32_t new_tgt_hz); | |||
| void PlsrRunControlTickMs(void); | |||
| void PlsrRunControlOn1ms(void); /* TIM3 节拍;升降速改在脉冲 ISR */ | |||
| void PlsrRunControlOnPulseIsr(void); | |||
| uint8_t PlsrRunControlIsBusy(void); | |||
| int32_t PlsrRunControlGetAccPulse(void); | |||
| @@ -0,0 +1,161 @@ | |||
| /** | |||
| * @file plsr_signal_io.c | |||
| * @brief X4/X5 EXTI 下降沿 + TIM3 1ms | |||
| */ | |||
| #include "plsr_signal_io.h" | |||
| #include "plsr_param.h" | |||
| #include "plsr_run_control.h" | |||
| #include "main.h" | |||
| /* X4=PB5 → EXTI5;X5=PG12 → EXTI12 */ | |||
| #define PLSR_X4_PORT GPIOB | |||
| #define PLSR_X4_PIN GPIO_PIN_5 | |||
| #define PLSR_X5_PORT GPIOG | |||
| #define PLSR_X5_PIN GPIO_PIN_12 | |||
| /* | |||
| * APB1=42MHz → TIM3CLK=84MHz;PSC=83 ARR=999 → 1kHz 更新 | |||
| */ | |||
| #define PLSR_TIM3_PSC 83U | |||
| #define PLSR_TIM3_ARR 999U | |||
| static volatile uint32_t s_ms; | |||
| static volatile uint8_t s_fall_x4; | |||
| static volatile uint8_t s_fall_x5; | |||
| static TIM_HandleTypeDef s_htim3; | |||
| static void PlsrSignalIoGpioExtiInit(void) | |||
| { | |||
| GPIO_InitTypeDef gpio = {0}; | |||
| __HAL_RCC_GPIOB_CLK_ENABLE(); | |||
| __HAL_RCC_GPIOG_CLK_ENABLE(); | |||
| __HAL_RCC_SYSCFG_CLK_ENABLE(); | |||
| gpio.Mode = GPIO_MODE_IT_FALLING; | |||
| gpio.Pull = GPIO_PULLUP; | |||
| gpio.Speed = GPIO_SPEED_FREQ_LOW; | |||
| gpio.Pin = PLSR_X4_PIN; | |||
| HAL_GPIO_Init(PLSR_X4_PORT, &gpio); | |||
| gpio.Pin = PLSR_X5_PIN; | |||
| HAL_GPIO_Init(PLSR_X5_PORT, &gpio); | |||
| HAL_NVIC_SetPriority(EXTI9_5_IRQn, 8, 0); | |||
| HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); | |||
| HAL_NVIC_SetPriority(EXTI15_10_IRQn, 8, 0); | |||
| HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); | |||
| } | |||
| static void PlsrSignalIoTim3Init(void) | |||
| { | |||
| __HAL_RCC_TIM3_CLK_ENABLE(); | |||
| s_htim3.Instance = TIM3; | |||
| s_htim3.Init.Prescaler = PLSR_TIM3_PSC; | |||
| s_htim3.Init.CounterMode = TIM_COUNTERMODE_UP; | |||
| s_htim3.Init.Period = PLSR_TIM3_ARR; | |||
| s_htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; | |||
| s_htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; | |||
| (void)HAL_TIM_Base_Init(&s_htim3); | |||
| HAL_NVIC_SetPriority(TIM3_IRQn, 9, 0); | |||
| HAL_NVIC_EnableIRQ(TIM3_IRQn); | |||
| (void)HAL_TIM_Base_Start_IT(&s_htim3); | |||
| } | |||
| void PlsrSignalIoInit(void) | |||
| { | |||
| s_ms = 0U; | |||
| s_fall_x4 = 0U; | |||
| s_fall_x5 = 0U; | |||
| PlsrSignalIoGpioExtiInit(); | |||
| PlsrSignalIoTim3Init(); | |||
| } | |||
| uint32_t PlsrSignalIoGetMs(void) | |||
| { | |||
| return s_ms; | |||
| } | |||
| uint32_t PlsrSignalIoDeadlineFromNow(uint32_t ms) | |||
| { | |||
| if (ms == 0U) | |||
| { | |||
| return s_ms; | |||
| } | |||
| return s_ms + ms; | |||
| } | |||
| uint8_t PlsrSignalIoMsReached(uint32_t deadline_ms) | |||
| { | |||
| return ((int32_t)(s_ms - deadline_ms) >= 0) ? 1U : 0U; | |||
| } | |||
| void PlsrSignalIoClearEdges(void) | |||
| { | |||
| s_fall_x4 = 0U; | |||
| s_fall_x5 = 0U; | |||
| } | |||
| static uint8_t PlsrSignalIoTakePinFalling(uint16_t sel_01) | |||
| { | |||
| if (sel_01 != 0U) | |||
| { | |||
| if (s_fall_x5 != 0U) | |||
| { | |||
| s_fall_x5 = 0U; | |||
| return 1U; | |||
| } | |||
| return 0U; | |||
| } | |||
| if (s_fall_x4 != 0U) | |||
| { | |||
| s_fall_x4 = 0U; | |||
| return 1U; | |||
| } | |||
| return 0U; | |||
| } | |||
| uint8_t PlsrSignalIoTakeWaitFalling(void) | |||
| { | |||
| PlsrCfg_t *cfg = PlsrParamGetCfg(); | |||
| return PlsrSignalIoTakePinFalling(cfg->wait_x_sel); | |||
| } | |||
| uint8_t PlsrSignalIoTakeExtFalling(void) | |||
| { | |||
| PlsrCfg_t *cfg = PlsrParamGetCfg(); | |||
| return PlsrSignalIoTakePinFalling(cfg->ext_x_sel); | |||
| } | |||
| void PlsrSignalIoOnTim3Irq(void) | |||
| { | |||
| if ((TIM3->SR & TIM_SR_UIF) != 0U) | |||
| { | |||
| TIM3->SR = (uint32_t)~TIM_SR_UIF; | |||
| s_ms++; | |||
| /* 升降速:1ms 更新一次输出频率 */ | |||
| PlsrRunControlOn1ms(); | |||
| } | |||
| } | |||
| void PlsrSignalIoOnExti9_5(void) | |||
| { | |||
| if (__HAL_GPIO_EXTI_GET_IT(PLSR_X4_PIN) != 0U) | |||
| { | |||
| __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X4_PIN); | |||
| s_fall_x4 = 1U; | |||
| } | |||
| } | |||
| void PlsrSignalIoOnExti15_10(void) | |||
| { | |||
| if (__HAL_GPIO_EXTI_GET_IT(PLSR_X5_PIN) != 0U) | |||
| { | |||
| __HAL_GPIO_EXTI_CLEAR_IT(PLSR_X5_PIN); | |||
| s_fall_x5 = 1U; | |||
| } | |||
| } | |||
| @@ -0,0 +1,45 @@ | |||
| /** | |||
| * @file plsr_signal_io.h | |||
| * @brief 等待/EXT 输入(X4=PB5、X5=PG12 EXTI)+ TIM3 1ms 时基(WAIT/ACT) | |||
| * | |||
| * 公共参数:wait_x_sel / ext_x_sel:0=X4,1=X5。 | |||
| * 引脚上拉默认高,外部拉低 → 下降沿触发。 | |||
| * TIM3 仅作毫秒计数,不占用 TIM10/11/13/14。 | |||
| */ | |||
| #ifndef PLSR_SIGNAL_IO_H | |||
| #define PLSR_SIGNAL_IO_H | |||
| #include <stdint.h> | |||
| void PlsrSignalIoInit(void); | |||
| /** TIM3 毫秒计数(自由运行,约 1ms/格) */ | |||
| uint32_t PlsrSignalIoGetMs(void); | |||
| /** deadline = GetMs()+ms;ms=0 则立即到期 */ | |||
| uint32_t PlsrSignalIoDeadlineFromNow(uint32_t ms); | |||
| /** 1=已到或过期(含无符号环绕) */ | |||
| uint8_t PlsrSignalIoMsReached(uint32_t deadline_ms); | |||
| /** 清 X4/X5 下降沿锁存 */ | |||
| void PlsrSignalIoClearEdges(void); | |||
| /** | |||
| * 取并清除 WAIT 所选口的下降沿(按 cfg->wait_x_sel) | |||
| * @return 1=本次取到沿 | |||
| */ | |||
| uint8_t PlsrSignalIoTakeWaitFalling(void); | |||
| /** | |||
| * 取并清除 EXT 所选口的下降沿(按 cfg->ext_x_sel) | |||
| * @return 1=本次取到沿 | |||
| */ | |||
| uint8_t PlsrSignalIoTakeExtFalling(void); | |||
| /* 由 stm32f4xx_it.c 转发 */ | |||
| void PlsrSignalIoOnTim3Irq(void); | |||
| void PlsrSignalIoOnExti9_5(void); | |||
| void PlsrSignalIoOnExti15_10(void); | |||
| #endif | |||