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
验证方法
按以下步骤执行并观察结果:
- 启动Renode:
renode -P 1234,然后在monitor中执行include @echo.resc。 - 在monitor中向虚拟串口写入字符:
uart "COM1" "A"。 - 从同一串口读取回显:
uart "COM1"。
判定标准:第3步读取到的输出字符与第2步写入的字符完全一致(例如写入A,读取到A)。连续测试多个不同字符(如Z、5、@)均能正确回显,即判定通过。
预期结果说明
根据上述代码逻辑,当monitor向虚拟串口写入单个字符时,固件阻塞等待接收,收到后立即发送同一字符,因此monitor从串口读取到的内容必然与写入内容相同。此结论由代码逻辑直接推出,可作为预期输出参考。实际执行时,在Renode monitor中依次执行写入和读取命令,观察读取结果即可完成验证。