Keil µVision 调试指南---UART#1 模拟/调试窗口 完全使用教程

💡UART#1 窗口 是 Keil 调试模式下的"虚拟串口终端",可实时查看 MCU 串口输出、模拟输入数据。无论是否拥有硬件,都能高效调试串口通信代码。

🔧 1. 核心概念

🧪 软件仿真模式

无需真实开发板,Keil 模拟 MCU 外设。UART#1 窗口直接显示 printf 或串口发送的数据,并可模拟串口输入。适合算法验证、初期调试。

无硬件 · 快速迭代

🔌 硬件调试模式

连接 J-Link/ST-Link 等调试器,真实运行目标板。通过 ASSIGN 命令将物理串口映射到 UART#1 窗口,实现输出捕获。

真实外设 · 映射显示

💻 2. 软件仿真模式 ------ 让 UART#1 显示 printf

📌 步骤 1:开启软件仿真

  • 点击菜单 Project → Options for Target (或工具栏"魔术棒"图标)。
  • 切换到 Debug 标签页 → 选中 Use Simulator → 确定。
  • Ctrl+F5 进入调试模式。
  • 通过菜单 View → Serial Windows → UART #1 打开串口窗口。

📌 步骤 2:重定向 printf → 串口1 (关键代码)

在工程中添加以下代码,将标准输出映射到 USART1,否则 printf 无法显示在 UART#1 窗口。

复制代码
/* 禁用半主机模式 (必须) */
#pragma import(__use_no_semihosting_swi)

struct __FILE { int handle; };
FILE __stdout;

void _sys_exit(int x) { 
    x = x; 
}

/* 重定向 fputc 函数 ------ 将 printf 内容发往 USART1 */
int fputc(int ch, FILE *f) {
    // 等待发送缓冲区为空 (根据芯片库函数调整)
    while (!(USART1->SR & (1<<7)));  // 示例: 检查 TXE 标志
    USART1->DR = (uint8_t)ch;
    return ch;
}

📢 提示: 如果使用标准外设库,常用写法为 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)==RESET);

HAL 库用户可使用 while(!(USART1->ISR & USART_ISR_TXE_TXFIFOE)); 或者直接调用 HAL_UART_Transmit 实现重定向。

📌 步骤 3:编写测试代码 & 运行

复制代码
// 初始化 USART1 (波特率 115200, 8N1 等)
void UART1_Init(void) {
    // 使能时钟,配置 GPIO, 波特率等 (略)
    // 以 STM32 为例: RCC_APB2PeriphClockCmd...
    USART_Init(USART1, &USART_InitStruct);
    USART_Cmd(USART1, ENABLE);
}

int main(void) {
    UART1_Init();
    printf("Hello from Keil UART#1!\r\n");
    printf("当前仿真时间: 正常输出\r\n");
    while(1);
}

全速运行 (F5) 后,UART#1 窗口 会显示打印的字符串,效果与真实串口助手完全一致。

🌍 3. 硬件调试模式 ------ 映射物理串口到 UART#1 窗口

当连接真实开发板调试时,MCU 实际通过 TX/RX 引脚输出数据,Keil 默认不会自动抓取。使用 ASSIGN 命令建立映射关系。

⚙️ 操作流程

  • 进入硬件调试模式(Options for Target → Debug → 选择硬件调试器如 ST-Link, J-Link)。
  • 打开 View → Serial Windows → UART #1 窗口。
  • 同时打开 Command 窗口 (View → Command Window)。
  • Command 窗口输入映射命令后回车:

ASSIGN WIN1 < S0IN > S0OUT

命令解析:

  • WIN1 → 对应 UART #1 窗口。
  • S0IN / S0OUT → Keil 仿真器虚拟串口通道,S0 一般映射到 MCU 的 USART1。对于 USART2 则使用 S1IN / S1OUT
  • 执行后,真实硬件通过 USART1 发出的所有数据会实时显示在 UART#1 窗口。

注意事项: 某些较新的 Cortex-M 系列需要确保调试接口 SWO 或者串口引脚未被占用。若命令无效,检查芯片型号是否支持 ASSIGN 映射。另外也可以使用 ITM 方式,但 ASSIGN 是最直观的串口映射方法。

📡 示例:多串口映射

UART 外设 目标窗口 ASSIGN 命令
USART1 UART #1 ASSIGN WIN1 < S0IN > S0OUT
USART2 UART #2 ASSIGN WIN2 < S1IN > S1OUT
USART3 UART #3 ASSIGN WIN3 < S2IN > S2OUT

⌨️ 4. 进阶技巧:向 MCU 发送模拟数据(软件仿真)

在软件仿真下,你可以通过 Command 窗口模拟串口接收数据,用于测试协议解析、命令响应。

  • 确保处于软件仿真模式,并已打开 UART #1 窗口和 Command 窗口。
  • 在 Command 窗口输入模拟发送命令:

S0IN = 'A' // 发送字符 A

S0IN = 0x31 // 发送十六进制 0x31 (ASCII '1')

S0IN = "Hello" // 发送字符串

此时 MCU 的串口接收中断或查询方式会收到上述数据,程序可进行相应处理,便于调试 AT 指令等逻辑。

💡**提示:**硬件调试模式下也可以通过类似方式注入数据,但需要确保硬件上无电气冲突;推荐纯软件仿真时使用此功能。

5. 性能优化:加速串口输出(仿真模式)

软件仿真时串口数据传输会按位时间模拟,速度较慢。可以修改 S0TIME 参数强制让数据"瞬间"传输完毕。

S0TIME = 0

S0TIME 代表发送每一位数据需要的时间(单位:秒),默认值为 0.000104(约 9600 波特率每一位时长)。设为 0 后,输出不再延迟,极大提高调试效率。若恢复模拟真实波特率可重新赋正值。

🚀 小贴士:S0TIME = 0 对于大量 printf 调试信息尤其有用,避免长时间等待仿真输出。

6. 常见问题与排查

现象 可能原因 & 解决方案
UART#1 窗口无任何输出 1. 未重定向 fputc 或者重定向函数内未发送数据。 2. 软件仿真下未正确配置系统时钟,导致外设未使能。 3. 硬件调试下未执行 ASSIGN 映射命令。 4. 检查串口初始化代码是否真正使能了 USART。
printf 卡死/程序跑飞 多半是半主机模式问题,确保添加了 #pragma import(__use_no_semihosting_swi) 及空实现 _sys_exit
硬件映射后无输出但硬件真实串口有数据 确认调试器连接稳定,部分 MCU 需要正确配置 DBGMCU 寄存器以允许调试时串口继续工作;也可以使用逻辑分析仪对比。
Command窗口无法识别ASSIGN 请检查是否在硬件调试会话中且芯片支持。部分较老的ARM7/9支持,Cortex-M系列通常支持。也可以尝试将串口映射到 ITM 控制台。
输出乱码 波特率/时钟配置与实际仿真设置不符?仿真默认按目标时钟计算,若时钟初始化错误则乱码。检查 SystemInit 及波特率寄存器。

📁 7. 完整示例流程(软件仿真+硬件通用)

📌 快捷检查表:

  • ✔ 工程中包含 UART 初始化代码(波特率配置正确)。

  • ✔ 重定向代码已添加(对于 printf 方式)或直接使用 USART_SendData 发送,但显示到 UART#1 仍需重定向或映射。

  • ✔ 进入调试模式 → 打开 UART #1 窗口 → 如果是硬件模式则执行 ASSIGN 命令。

  • ✔ 运行程序,查看窗口实时打印。

  • ✔ 想模拟接收,软件仿真下使用 S0IN = "指令"

    // 典型初始化 + 重定向整体示例 (适用于STM32F103 标准库)
    #include "stm32f10x.h"
    #include <stdio.h>

    #pragma import(__use_no_semihosting_swi)
    struct __FILE { int handle; };
    FILE __stdout;
    void _sys_exit(int x) { x = x; }

    int fputc(int ch, FILE *f) {
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, (uint8_t)ch);
    return ch;
    }

    void USART1_Config(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);
    USART_Cmd(USART1, ENABLE);
    }

    int main(void) {
    USART1_Config();
    printf("✅ Keil UART#1 窗口调试成功!\r\n");
    while(1);
    }

🎯结论: 掌握 UART#1 窗口相当于拥有一个集成在调试器里的"虚拟串口终端"。无论是代码初期仿真还是后期硬件联调,都能大幅提升串口相关功能的调试效率。灵活使用printf重定向、ASSIGN映射和S0TIME加速,让调试更加丝滑。

Keil µVision 调试技巧 · UART#1 完整指南 | 适用于 MDK v5 / v6 及主流 Cortex-M 系列

相关推荐
iCxhust2 小时前
51单片机引脚 ALE EA PSEN的用途
单片机·嵌入式硬件·51单片机
碎像2 小时前
51单片机创建项目
单片机·嵌入式硬件·51单片机
木白CPP2 小时前
MCU 进程内存布局详解(.text, .rodata, .data, .bss, 堆, 栈)
单片机·嵌入式硬件
Lugas Luo2 小时前
车载录像存储性能模拟测试工具设计
linux·嵌入式硬件·测试工具
v132665623682 小时前
BK7258 wifi6音视频soc芯片应用分析
嵌入式硬件·物联网·音视频·iot·wifi6
風清掦3 小时前
【江科大STM32学习笔记-10】I2C通信协议 - 10.2 硬件 I2C 读写MPU6050
笔记·stm32·单片机·嵌入式硬件·学习
ALINX技术博客3 小时前
【黑金云课堂】FPGA技术教程Vitis开发:RTC中断讲解
单片机·嵌入式硬件·fpga开发
进击的小头3 小时前
第10篇:嵌入式芯片中断系统详解:NVIC与硬实时性优化设计
单片机·嵌入式硬件
菠萝地亚狂想曲3 小时前
Zephyr_02,SEM
单片机