Parcourir la source

PLSR P3a 上板准备:GPIO/定时器初始化 + 上电自测(Q0 测试脉冲)

- 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
ywh il y a 1 mois
Parent
révision
539fe6b4a5
5 fichiers modifiés avec 188 ajouts et 0 suppressions
  1. +4
    -0
      Core/Src/main.c
  2. +6
    -0
      EWARM/Modbus.ewp
  3. +18
    -0
      PLSR/Inc/plsr_self_test.h
  4. +58
    -0
      PLSR/Src/plsr_hal_f407.c
  5. +102
    -0
      PLSR/Src/plsr_self_test.c

+ 4
- 0
Core/Src/main.c Voir le fichier

@@ -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 */



+ 6
- 0
EWARM/Modbus.ewp Voir le fichier

@@ -1293,6 +1293,9 @@
<file>
<name>$PROJ_DIR$\..\PLSR\Inc\plsr_hal_f407.h</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Inc\plsr_self_test.h</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Src\plsr_persistence.c</name>
</file>
@@ -1314,6 +1317,9 @@
<file>
<name>$PROJ_DIR$\..\PLSR\Src\plsr_hal_f407.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Src\plsr_self_test.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\PLSR\Src\plsr_core.c</name>
</file>


+ 18
- 0
PLSR/Inc/plsr_self_test.h Voir le fichier

@@ -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 */

+ 58
- 0
PLSR/Src/plsr_hal_f407.c Voir le fichier

@@ -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;
}



+ 102
- 0
PLSR/Src/plsr_self_test.c Voir le fichier

@@ -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);
}

Chargement…
Annuler
Enregistrer