hal库中对printf进行重定向

该代码实现了将C标准库中的printf和scanf函数重定向到DEBUG_USARTx(通常为UART1)的功能。通过HAL_UART_Transmit发送字符,使用HAL_UART_Receive接收字符,实现串口通信与标准输入输出的关联。

#include “stdio.h”//对printf进行重定向
/**

  • 函数功能: 重定向c库函数printf到DEBUG_USARTx
  • 输入参数: 无
  • 返 回 值: 无
  • 说 明:无
    */
    int fputc(int ch, FILE *f)
    {
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
    return ch;
    }

/**

  • 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  • 输入参数: 无
  • 返 回 值: 无
  • 说 明:无
    */
    int fgetc(FILE *f)
    {
    uint8_t ch = 0;
    HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
    return ch;
    }
STM32 HAL 开发中,使用 DMA 实现非阻塞式串口 `printf` 重定向需要结合底层 I/O 函数替换与异步传输机制。标准的 `printf` 输出依赖于 `stdout` 的写入操作,通常通过 `fputc` 或 `__io_putchar` 函数实现重定向。为了支持非阻塞特性,应将实际的串口发送逻辑替换为基于 DMA 的异步方式。 ### 使用 HAL_UART_Transmit_DMA 实现异步输出 HAL 提供了 `HAL_UART_Transmit_DMA()` 接口用于启动 DMA 模式的串口数据发送。该接口不会阻塞当前线程,而是通过硬件自动搬运数据[^1]。为了实现 `printf` 的非阻塞重定向,需定义一个自定义的字符输出函数(如 `__io_putchar`),并在其中调用 `HAL_UART_Transmit_DMA()`。 由于 `HAL_UART_Transmit_DMA()` 是异步操作,必须确保缓冲区在整个 DMA 传输期间保持有效。因此,建议在全局或静态变量中缓存待发送的数据,并在 DMA 传输完成中断中释放资源或准备下一次传输。 以下是一个示例实现: ```c #include "stdio.h" #include "stm32f4xx_hal.h" UART_HandleTypeDef huart1; #define TX_BUFFER_SIZE 128 static uint8_t tx_buffer[TX_BUFFER_SIZE]; int __io_putchar(int ch) { if (ch == '\n') { // 处理换行符 __io_putchar('\r'); } static uint8_t tx_byte; tx_byte = (uint8_t)ch; HAL_UART_Transmit_DMA(&huart1, &tx_byte, 1); return ch; } void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART1_UART_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); printf("Non-blocking printf via UART with DMA\r\n"); while (1) { // 主循环任务 } } static void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&huart1); } ``` ### 注意事项与优化策略 - **DMA 缓冲区管理**:为避免缓冲区覆盖问题,应在每次调用 `HAL_UART_Transmit_DMA()` 前确保上一次传输已完成。可以通过查询标志位、使用互斥锁或等待 DMA 完成中断来实现。 - **中断处理**:在 `HAL_UART_TxCpltCallback()` 中可以触发下一次 DMA 传输或释放临时缓冲区。 - **性能优化**:对于连续字符串输出,可将多个字符拼接至固定大小的缓冲区后一次性发送,以减少频繁调用 `HAL_UART_Transmit_DMA()` 所带来的开销。 ### 异常处理与调试建议 - 若 `HAL_UART_Transmit_DMA()` 返回错误状态,应检查 UART 和 DMA 配置是否正确。 - 使用调试器观察 `huart1.gState` 可判断当前 UART 状态。 - 在 DMA 初始化时启用中断并注册回调函数,有助于及时响应传输完成事件。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值