3. 配置虚拟串口并实现回显

配置虚拟串口并实现回显 学习卡片

任务说明

本案例要求在Renode仿真环境中为嵌入式目标创建虚拟串口,并编写固件程序实现串口回显功能。完成目标是:通过Renode的monitor将字符写入虚拟串口后,固件能够接收并在同一串口上原样返回该字符,验证时在monitor中观察到回显数据。

硬件平台与依赖

选用Renode内置支持的STM32F4Discovery开发板仿真模型(STM32F405芯片),该模型已包含USART2外设。需要安装Renode(≥1.13),无需额外硬件。本案例使用Renode的UARTPtyDriver或UARTBackend作为虚拟串口后端,通过monitor的uart命令进行读写。

固件实现

以下C代码完成USART2的初始化(PA2=TX,PA3=RX,波特率115200,8N1),并在主循环中阻塞接收单个字节后立即发送回显。代码直接操作寄存器,不依赖HAL库,便于在仿真环境中精确控制。


// echo_uart.c
// STM32F405 USART2 回显程序(Renode仿真用)
// 时钟:内部HSI 16MHz,APB1=16MHz,USART2挂载于APB1

#define RCC_BASE        0x40021000
#define RCC_AHB1ENR     (*(volatile unsigned int*)(RCC_BASE + 0x30))
#define RCC_APB1ENR     (*(volatile unsigned int*)(RCC_BASE + 0x40))

#define GPIOA_BASE      0x40020000
#define GPIOA_MODER     (*(volatile unsigned int*)(GPIOA_BASE + 0x00))
#define GPIOA_AFRL      (*(volatile unsigned int*)(GPIOA_BASE + 0x20))

#define USART2_BASE     0x40004400
#define USART2_SR       (*(volatile unsigned int*)(USART2_BASE + 0x00))
#define USART2_DR       (*(volatile unsigned int*)(USART2_BASE + 0x04))
#define USART2_BRR      (*(volatile unsigned int*)(USART2_BASE + 0x08))
#define USART2_CR1      (*(volatile unsigned int*)(USART2_BASE + 0x0C))

// 状态位
#define SR_TXE          (1 << 7)
#define SR_RXNE         (1 << 5)

void uart_init(void) {
    // 1. 使能GPIOA和USART2时钟
    RCC_AHB1ENR |= (1 << 0);   // GPIOA
    RCC_APB1ENR |= (1 << 17);  // USART2

    // 2. PA2=AF7(TX), PA3=AF7(RX) 设置为复用功能
    GPIOA_MODER &= ~(0xF << (2*2));  // 清PA2,PA3模式位
    GPIOA_MODER |=  (0xA << (2*2));  // PA2=10(复用), PA3=10(复用)
    GPIOA_AFRL &= ~(0xFF << (2*4)); // 清AFRL bit8~15
    GPIOA_AFRL |=  (0x77 << (2*4)); // PA2=AF7, PA3=AF7

    // 3. 配置波特率 115200 @ 16MHz: BRR = 16000000/115200 = 138.89 ≈ 139
    USART2_BRR = 139;

    // 4. 使能USART2, 发送, 接收
    USART2_CR1 = (1 << 13) | (1 << 3) | (1 << 2); // UE=1, TE=1, RE=1
}

void uart_putc(char c) {
    while (!(USART2_SR & SR_TXE));  // 等待发送数据寄存器空
    USART2_DR = c;
}

char uart_getc(void) {
    while (!(USART2_SR & SR_RXNE)); // 等待接收数据寄存器非空
    return (char)(USART2_DR & 0xFF);
}

int main(void) {
    uart_init();
    while (1) {
        char ch = uart_getc();
        uart_putc(ch);
    }
    return 0;
}

编译与仿真配置

使用arm-none-eabi-gcc编译(需安装ARM交叉编译器),生成ELF文件。然后创建Renode仿真脚本,加载STM32F4Discovery平台并连接虚拟串口。


# echo.resc  (Renode 脚本)
:name: EchoTest
:description: Virtual UART echo test

using "platforms/boards/stm32f4_discovery.repl"

machine create
machine LoadPlatformDescription @platforms/boards/stm32f4_discovery.repl

# 加载编译好的固件
machine LoadELF @/path/to/echo_uart.elf

# 创建虚拟串口后端并连接到USART2
machine UartCreate "COM1" "/tmp/virtual_uart"
machine ConnectUart "COM1" "sysbus.usart2"

start

编译命令:


arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -nostdlib -Ttext=0x08000000 \
  -Wl,-e,main echo_uart.c -o echo_uart.elf

验证方法

按以下步骤执行并观察结果:

  1. 启动Renode:renode -P 1234,然后在monitor中执行include @echo.resc。
  2. 在monitor中向虚拟串口写入字符:uart "COM1" "A"。
  3. 从同一串口读取回显:uart "COM1"。

判定标准:第3步读取到的输出字符与第2步写入的字符完全一致(例如写入A,读取到A)。连续测试多个不同字符(如Z、5、@)均能正确回显,即判定通过。

虚拟串口回显验证拓扑 Renode Monitor uart "COM1" "A" uart "COM1" → A 虚拟串口 (COM1) UARTBackend /tmp/virtual_uart USART2 外设 PA2=TX, PA3=RX BRR=139 (115200) 固件回显循环 uart_getc() → uart_putc() 写"A" RX 回显"A" 读回"A" → 写入路径 → 回显路径 验证: 写入字符与读回字符一致

预期结果说明

根据上述代码逻辑,当monitor向虚拟串口写入单个字符时,固件阻塞等待接收,收到后立即发送同一字符,因此monitor从串口读取到的内容必然与写入内容相同。此结论由代码逻辑直接推出,可作为预期输出参考。实际执行时,在Renode monitor中依次执行写入和读取命令,观察读取结果即可完成验证。