diff --git a/Core/Src/main.c b/Core/Src/main.c index 1f8c2e9..dd9b591 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -26,6 +26,7 @@ #include "modbus_rtu_slave.h" #include "plc_device.h" #include "plsr_core.h" +#include "plsr_self_test.h" #include "stdio.h" /* USER CODE END Includes */ @@ -199,6 +200,9 @@ int main(void) Error_Handler(); } + /* 上电自测:Q0 发一段测试脉冲(验证后删除)。 */ + (void)PlsrSelfTestQueue(); + OSStart(); /* USER CODE END 2 */ diff --git a/EWARM/Modbus.ewp b/EWARM/Modbus.ewp index 84d63a6..870b464 100644 --- a/EWARM/Modbus.ewp +++ b/EWARM/Modbus.ewp @@ -1293,6 +1293,9 @@ $PROJ_DIR$\..\PLSR\Inc\plsr_hal_f407.h + + $PROJ_DIR$\..\PLSR\Inc\plsr_self_test.h + $PROJ_DIR$\..\PLSR\Src\plsr_persistence.c @@ -1314,6 +1317,9 @@ $PROJ_DIR$\..\PLSR\Src\plsr_hal_f407.c + + $PROJ_DIR$\..\PLSR\Src\plsr_self_test.c + $PROJ_DIR$\..\PLSR\Src\plsr_core.c diff --git a/PLSR/Inc/plsr_self_test.h b/PLSR/Inc/plsr_self_test.h new file mode 100644 index 0000000..f9815a0 --- /dev/null +++ b/PLSR/Inc/plsr_self_test.h @@ -0,0 +1,18 @@ +#ifndef PLSR_SELF_TEST_H +#define PLSR_SELF_TEST_H + +#include "plsr_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 上电自测:入队一段测试任务(Q0 发 2000Hz/1000 脉冲,K1 默认参数)。 + * 用于首次上板验证脉冲波形,验证完成后可删除。 */ +PLSR_RESULT PlsrSelfTestQueue(void); + +#ifdef __cplusplus +} +#endif + +#endif /* PLSR_SELF_TEST_H */ diff --git a/PLSR/Src/plsr_hal_f407.c b/PLSR/Src/plsr_hal_f407.c index 8f89e9d..6341d05 100644 --- a/PLSR/Src/plsr_hal_f407.c +++ b/PLSR/Src/plsr_hal_f407.c @@ -291,6 +291,64 @@ PLSR_RESULT PlsrHwInit(void) PlsrHwTimerSetCen(axis, 0UL); #endif } + +#ifndef PLSR_HOST_TEST + { + GPIO_InitTypeDef gpio; + uint8_t point; + + /* 1. 输出点 GPIO 时钟。 */ + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + + /* 2. 全部输出点上电安全电平(推挽输出、低)。 */ + gpio.Mode = GPIO_MODE_OUTPUT_PP; + gpio.Pull = GPIO_NOPULL; + gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + for (point = 0U; point < PLSR_HW_OUTPUT_POINT_COUNT; point++) + { + if (PlsrHwOutputPins[point].port != NULL) + { + gpio.Pin = PlsrHwOutputPins[point].pin; + HAL_GPIO_WritePin(PlsrHwOutputPins[point].port, + PlsrHwOutputPins[point].pin, + GPIO_PIN_RESET); + HAL_GPIO_Init(PlsrHwOutputPins[point].port, + &gpio); + } + } + + /* 3. 定时器时钟。 */ + __HAL_RCC_TIM10_CLK_ENABLE(); + __HAL_RCC_TIM11_CLK_ENABLE(); + __HAL_RCC_TIM13_CLK_ENABLE(); + __HAL_RCC_TIM14_CLK_ENABLE(); + + /* 4. 脉冲点切定时器复用(PF6/7=AF3、PF8/9=AF9)。 + * 定时器通道尚未使能(CC1E=0),输出为无效电平(低),无毛刺。 */ + gpio.Mode = GPIO_MODE_AF_PP; + gpio.Pin = GPIO_PIN_6 | GPIO_PIN_7; + gpio.Alternate = 3U; + HAL_GPIO_Init(GPIOF, &gpio); + gpio.Pin = GPIO_PIN_8 | GPIO_PIN_9; + gpio.Alternate = 9U; + HAL_GPIO_Init(GPIOF, &gpio); + + /* 5. 更新中断 NVIC:高速计数/尾脉冲层(P3b 统一规划优先级表)。 */ + HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 1U, 0U); + HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn); + HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 1U, 0U); + HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn); + HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 1U, 0U); + HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn); + HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 1U, 0U); + HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn); + } +#endif return PLSR_RESULT_OK; } diff --git a/PLSR/Src/plsr_self_test.c b/PLSR/Src/plsr_self_test.c new file mode 100644 index 0000000..ec2135a --- /dev/null +++ b/PLSR/Src/plsr_self_test.c @@ -0,0 +1,102 @@ +#include "plsr_self_test.h" +#include "plc_device.h" +#include "plsr_core.h" +#include "plsr_job.h" +#include + +/* 上电自测(验证后可删除): + * - 方向端子设为 Y4(SFD906=4),其余用出厂默认参数(K1) + * - 任务:Q0 发 1 段 2000Hz / 1000 脉冲,H00 完成,梯形曲线 + * 数据源为静态数组,仅自测使用(正式 D 设备适配器见 Modbus 阶段)。 */ + +#define SELF_TEST_WORD_CAPACITY (64U) +#define SELF_TEST_S0_BASE (10U) +#define SELF_TEST_S1_BASE (30U) +#define SELF_TEST_DIR_POINT (4U) + +static uint16_t SelfTestWords[3][SELF_TEST_WORD_CAPACITY]; + +static uint8_t SelfTestValidateWords(void *context, + PLSR_DEVICE_TYPE device, + uint32_t firstAddress, + uint32_t wordCount) +{ + (void)context; + if ((device > PLSR_DEVICE_FD) || (wordCount == 0UL)) + { + return 0U; + } + return (((uint64_t)firstAddress + wordCount) + <= SELF_TEST_WORD_CAPACITY) + ? 1U + : 0U; +} + +static uint8_t SelfTestReadWord(void *context, + PLSR_DEVICE_TYPE device, + uint32_t address, + uint16_t *value) +{ + (void)context; + if ((device > PLSR_DEVICE_FD) || (value == NULL) + || (address >= SELF_TEST_WORD_CAPACITY)) + { + return 0U; + } + *value = SelfTestWords[device][address]; + return 1U; +} + +static uint8_t SelfTestReadBit(void *context, + PLSR_DEVICE_TYPE device, + uint32_t address, + uint8_t *value) +{ + (void)context; + (void)device; + (void)address; + *value = 0U; + return 1U; +} + +static void SelfTestWriteDword(PLSR_DEVICE_TYPE device, + uint32_t address, + uint32_t value) +{ + SelfTestWords[device][address] = (uint16_t)(value & 0xFFFFUL); + SelfTestWords[device][address + 1UL] = (uint16_t)(value >> 16U); +} + +PLSR_RESULT PlsrSelfTestQueue(void) +{ + PLSR_CALL call; + + (void)memset(SelfTestWords, 0, sizeof(SelfTestWords)); + + /* 方向端子 Y4(PULSE/DIR 模式必需,接线参数)。 */ + (void)PlcDeviceWriteSfd(906U, SELF_TEST_DIR_POINT); + + /* S0:1 段,2000Hz / 1000 脉冲,H00 完成,顺序跳转。 */ + SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE, 1U); + SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 10U, 2000UL); + SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 12U, 1000UL); + + /* S1:相对模式,起始段 0(=段1)。 */ + SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S1_BASE, 0U); + + (void)memset(&call, 0, sizeof(call)); + call.sequence = 0xA5A5UL; + call.source.context = NULL; + call.source.validateWords = SelfTestValidateWords; + call.source.readWord = SelfTestReadWord; + call.source.readBit = SelfTestReadBit; + call.s0.device = PLSR_DEVICE_D; + call.s0.address = SELF_TEST_S0_BASE; + call.s1.device = PLSR_DEVICE_D; + call.s1.address = SELF_TEST_S1_BASE; + call.s2.type = PLSR_OPERAND_CONSTANT; + call.s2.constant = 1; + call.dAxis = 0U; + call.outputModeOverride = PLSR_OUTPUT_MODE_FROM_SFD; + return PlsrPostCall(&call); +}