- PlsrHwInit 补生产初始化:全部输出点上电安全电平(先输出拉低再切 AF)、 PF6/7=AF3、PF8/9=AF9 定时器复用、TIM10/11/13/14 时钟与更新中断 NVIC(优先级1) - 新增 plsr_self_test.c/.h:上电自动执行 Q0 发 2000Hz/1000 脉冲(K1 默认参数、 方向端子 Y4、静态数据源),main.c 一行接入,验证后可删 - 六套 host 测试 1151 项全绿,IAR 0 错误 0 警告deepseek
| @@ -26,6 +26,7 @@ | |||||
| #include "modbus_rtu_slave.h" | #include "modbus_rtu_slave.h" | ||||
| #include "plc_device.h" | #include "plc_device.h" | ||||
| #include "plsr_core.h" | #include "plsr_core.h" | ||||
| #include "plsr_self_test.h" | |||||
| #include "stdio.h" | #include "stdio.h" | ||||
| /* USER CODE END Includes */ | /* USER CODE END Includes */ | ||||
| @@ -199,6 +200,9 @@ int main(void) | |||||
| Error_Handler(); | Error_Handler(); | ||||
| } | } | ||||
| /* 上电自测:Q0 发一段测试脉冲(验证后删除)。 */ | |||||
| (void)PlsrSelfTestQueue(); | |||||
| OSStart(); | OSStart(); | ||||
| /* USER CODE END 2 */ | /* USER CODE END 2 */ | ||||
| @@ -1293,6 +1293,9 @@ | |||||
| <file> | <file> | ||||
| <name>$PROJ_DIR$\..\PLSR\Inc\plsr_hal_f407.h</name> | <name>$PROJ_DIR$\..\PLSR\Inc\plsr_hal_f407.h</name> | ||||
| </file> | </file> | ||||
| <file> | |||||
| <name>$PROJ_DIR$\..\PLSR\Inc\plsr_self_test.h</name> | |||||
| </file> | |||||
| <file> | <file> | ||||
| <name>$PROJ_DIR$\..\PLSR\Src\plsr_persistence.c</name> | <name>$PROJ_DIR$\..\PLSR\Src\plsr_persistence.c</name> | ||||
| </file> | </file> | ||||
| @@ -1314,6 +1317,9 @@ | |||||
| <file> | <file> | ||||
| <name>$PROJ_DIR$\..\PLSR\Src\plsr_hal_f407.c</name> | <name>$PROJ_DIR$\..\PLSR\Src\plsr_hal_f407.c</name> | ||||
| </file> | </file> | ||||
| <file> | |||||
| <name>$PROJ_DIR$\..\PLSR\Src\plsr_self_test.c</name> | |||||
| </file> | |||||
| <file> | <file> | ||||
| <name>$PROJ_DIR$\..\PLSR\Src\plsr_core.c</name> | <name>$PROJ_DIR$\..\PLSR\Src\plsr_core.c</name> | ||||
| </file> | </file> | ||||
| @@ -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 */ | |||||
| @@ -291,6 +291,64 @@ PLSR_RESULT PlsrHwInit(void) | |||||
| PlsrHwTimerSetCen(axis, 0UL); | PlsrHwTimerSetCen(axis, 0UL); | ||||
| #endif | #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; | return PLSR_RESULT_OK; | ||||
| } | } | ||||
| @@ -0,0 +1,102 @@ | |||||
| #include "plsr_self_test.h" | |||||
| #include "plc_device.h" | |||||
| #include "plsr_core.h" | |||||
| #include "plsr_job.h" | |||||
| #include <string.h> | |||||
| /* 上电自测(验证后可删除): | |||||
| * - 方向端子设为 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); | |||||
| } | |||||