[经验分享] 如何在keil5中实现printf函数

[复制链接]
400|0
八层楼 发表于 2025-8-12 17:05 | 显示全部楼层 |阅读模式
在Keil MDK(Keil5)中实现printf函数,需通过​​重定向字符输出到硬件接口(如串口)​​,并配置工程选项。以下是完整步骤及注意事项:


​​一、实现步骤​​
1. ​​添加头文件与重定向函数​​
​​包含标准I/O库​​:
#include <stdio.h>  // 提供printf函数声明


​​重写fputc函数​​(以STM32串口为例):
// 方法1:使用标准库函数(如HAL库)
int fputc(int ch, FILE *f) {
    HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 100);  // 通过UART1发送字符
    return ch;
}


// 方法2:直接操作寄存器(高效)[2](@ref)
int fputc(int ch, FILE *f) {
    while (!(USART1->ISR & USART_ISR_TXE));  // 等待发送缓冲区空
    USART1->TDR = (uint8_t)ch;                // 写入数据寄存器
    return ch;
}

关键​​:fputc是printf的底层输出函数,重定向后所有printf输出将发送至指定串口。


2. ​​初始化硬件接口​​
确保串口已初始化(波特率需与PC端一致,如115200):
void UART_Init(void) {
    // 以STM32标准库为例[1](@ref)
    USART_InitTypeDef USART_InitStruct = {0};
    USART_InitStruct.USART_BaudRate = 115200;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_Mode = USART_Mode_Tx;  // 仅发送模式
    USART_Init(USART1, &USART_InitStruct);
    USART_Cmd(USART1, ENABLE);
}



3. ​​工程配置​​
​​启用MicroLib​​(精简C库,减少资源占用):
点击魔术棒图标 → Options for Target → Target标签页;
勾选 ​​Use MicroLIB​​;
点击OK保存。
​​检查链接设置​​:
若未启用MicroLib,需手动实现_write等系统调用。
4. ​​调用printf测试​​
printf("System Clock: %d MHz\r\n", SystemCoreClock / 1000000);  // 输出系统时钟

​​二、常见问题及解决​​

1. ​​无输出或乱码​​
​​波特率不匹配​​:确保串口初始化波特率与PC端调试工具(如串口助手)一致;
​​硬件未初始化​​:确认串口时钟和引脚已配置;
​​发送未完成​​:在fputc中添加等待发送完成的循环(参考方法2)。
2. ​​中文乱码​​
​​Keil编码设置​​:
菜单栏 Edit → Configuration → Editor → 设置编码为 ​​UTF-8​​;
在Misc Controls中添加 --no-multibyte-chars(防止多字节字符解析错误);
​​串口助手编码​​:选择与Keil一致的编码(如UTF-8或GBK)。
3. ​​代码体积过大​​
启用MicroLib可显著减小代码尺寸;
避免使用浮点数(如%f),改用整数运算(如%d放大100倍显示)。

​​三、替代方案​​
1. ​​使用sprintf格式化到缓冲区​​
char buffer[50];
sprintf(buffer, "ADC Value: %d\r\n", adc_value);
HAL_UART_Transmit(&huart1, (uint8_t*)buffer, strlen(buffer), 100);  // 手动发送


​​优点​​:不依赖重定向,可多串口并行输出。

2. ​​自定义简化版printf​​
#include <stdarg.h>
void UART_Printf(char *format, ...) {
    char buf[100];
    va_list args;
    va_start(args, format);
    vsnprintf(buf, sizeof(buf), format, args);  // 格式化到缓冲区
    va_end(args);
    HAL_UART_Transmit(&huart1, (uint8_t*)buf, strlen(buf), 100);  // 发送
}


​​适用场景​​:需控制栈空间或避免库冲突时。


​​四、不同重定向方法对比​​





​五、调试技巧​​
​​单步调试验证​​:在fputc函数内设断点,确认printf是否触发该函数;
​​检查串口引脚​​:用示波器测量TX引脚波形,确认数据是否发出;
​​简化输出内容​​:先发送固定字符串(如"TEST"),排除格式化参数的影响。
通过以上步骤,可稳定实现Keil5中的printf输出功能。若需更深入的优化(如降低延迟),可结合SWO或RTT等高级调试方式。

注意:最后要记得勾选Use MicroLIB微库的功能不然运行printf时会出现卡死现象.
————————————————
版权声明:本文为CSDN博主「风停了123」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/2301_79036162/article/details/148892974

您需要登录后才可以回帖 登录 | 注册

本版积分规则

131

主题

4396

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部