2. HIL测试平台初始化

任务目标

搭建一个最小可用的HIL(硬件在环)测试平台,实现上位机(PC)与STM32目标板之间的双向数据交互。平台包含实时仿真机(以脚本模拟)、STM32目标板(以开发板固件实现)和上位机通信接口,三者通过串口连接,完成命令下发与状态回传的闭环。

平台架构与连接

本案例采用“上位机(PC) — 实时仿真机(PC脚本) — STM32目标板”的简化拓扑。实时仿真机与STM32之间通过UART1连接,上位机与实时仿真机之间通过UART2连接(实际部署时可用同一PC的两个串口或虚拟串口对)。实时仿真机负责转发上位机指令并模拟被控对象响应。

上位机 PC (Python) UART2 实时仿真机 PC脚本 (Python) 转发+模拟 STM32目标板 UART1 固件响应 命令 状态 命令 状态

环境依赖

  • STM32开发板(Nucleo-F401RE或类似),板载ST-Link虚拟串口
  • STM32CubeIDE(含CubeMX)用于生成和编译固件
  • Python 3.8+,安装 pyserial 库:pip install pyserial
  • 两个可用串口(Windows下可用虚拟串口软件如VSPD模拟一对互联串口)

STM32目标板固件(CubeMX配置 + 核心代码)

使用CubeMX生成基础工程,配置UART1(115200-8-N-1)和UART2(115200-8-N-1),开启UART1接收中断。在 main.c 中添加以下核心逻辑:

// 全局变量
uint8_t rx1_buf[64];
uint8_t rx1_len = 0;
uint8_t tx2_buf[64];

// UART1接收中断回调(接收来自实时仿真机的命令)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart == &huart1) {
        // 简单协议:收到单字节命令,回传状态
        uint8_t cmd = rx1_buf[0];
        uint8_t status[2];
        status[0] = cmd;           // 回显命令
        status[1] = cmd + 1;       // 模拟状态值(如ADC采样结果)

        // 通过UART2发送到实时仿真机
        HAL_UART_Transmit(&huart2, status, 2, 100);

        // 重新开启接收中断
        HAL_UART_Receive_IT(&huart1, rx1_buf, 1);
    }
}

// main() 中初始化后启动接收
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_USART2_UART_Init();

    // 启动UART1接收中断
    HAL_UART_Receive_IT(&huart1, rx1_buf, 1);

    while (1)
    {
        // 主循环可处理其他任务,此处留空
    }
}

实时仿真机脚本(simulator.py)

该脚本运行在PC上,连接STM32的UART1和上位机的UART2,负责双向转发并模拟被控对象延迟。

import serial
import time
import threading

# 串口配置(根据实际设备修改)
STM_PORT = 'COM5'   # 连接STM32的串口
HOST_PORT = 'COM6'  # 连接上位机的串口
BAUD = 115200

stm_ser = serial.Serial(STM_PORT, BAUD, timeout=0.1)
host_ser = serial.Serial(HOST_PORT, BAUD, timeout=0.1)

def stm_to_host():
    """STM32 → 上位机转发"""
    while True:
        if stm_ser.in_waiting:
            data = stm_ser.read(stm_ser.in_waiting)
            host_ser.write(data)
        time.sleep(0.001)

def host_to_stm():
    """上位机 → STM32转发(模拟实时仿真机处理延迟)"""
    while True:
        if host_ser.in_waiting:
            data = host_ser.read(host_ser.in_waiting)
            time.sleep(0.01)  # 模拟10ms处理延迟
            stm_ser.write(data)
        time.sleep(0.001)

# 启动双向转发线程
threading.Thread(target=stm_to_host, daemon=True).start()
threading.Thread(target=host_to_stm, daemon=True).start()

print("实时仿真机已启动,双向转发中...")
while True:
    time.sleep(1)

上位机测试脚本(host.py)

import serial
import time

HOST_PORT = 'COM6'  # 与simulator.py的HOST_PORT对应
BAUD = 115200

ser = serial.Serial(HOST_PORT, BAUD, timeout=1)

def send_command(cmd_byte):
    """发送单字节命令并接收2字节响应"""
    ser.write(bytes([cmd_byte]))
    resp = ser.read(2)
    return resp

# 发送测试命令序列
test_commands = [0x01, 0x02, 0x03, 0x10, 0x55]

print("=== HIL平台通信测试 ===")
for cmd in test_commands:
    resp = send_command(cmd)
    if len(resp) == 2:
        echo = resp[0]
        status = resp[1]
        print(f"发送: 0x{cmd:02X} → 回显: 0x{echo:02X}, 状态: 0x{status:02X}")
        if echo == cmd and status == cmd + 1:
            print("  ✓ 校验通过")
        else:
            print("  ✗ 数据不匹配")
    else:
        print(f"发送: 0x{cmd:02X} → 无响应(超时)")

ser.close()

运行与验证

  1. 烧录固件:编译STM32工程并烧录到目标板,打开串口调试助手确认UART1和UART2均正常初始化。
  2. 启动实时仿真机:运行 python simulator.py,看到“实时仿真机已启动”提示。
  3. 运行上位机测试:另开终端执行 python host.py。
  4. 通过标准:所有测试命令均显示“✓ 校验通过”,即证明上位机→实时仿真机→STM32→实时仿真机→上位机的完整数据链路已打通,HIL平台初始化成功。

常见问题

  • 串口打不开:确认设备管理器中端口号,关闭占用该串口的其他程序。
  • 无响应:检查STM32的UART1接收中断是否已启动(HAL_UART_Receive_IT必须在主循环前调用一次)。
  • 数据乱码:核对所有串口参数一致(115200, 8, N, 1),且共地连接。