STM32串口重定向:MDK與GCC環境下需重寫的函數差異
在嵌入式開發中,尤其是使用 STM32系列微控制器 的項目中,調試信息的輸出是不可或缺的一部分。為了方便調試,開發者通常會選擇將 printf
等標準輸出函數通過 UART 串口發送到 PC 端進行查看和分析。
然而,在不同的編譯器環境中(如 MDK(Keil) 和 GCC),實現標準輸出函數重定向的方式存在差異。本文將詳細介紹如何在這兩種環境下完成串口重定向,并指出它們之間需要重寫的函數區別。
? 一、重定向的基本原理
無論是在 MDK 還是 GCC 編譯環境下,串口重定向的核心思想都是通過重寫底層的字符輸出函數,使得標準庫中的 printf
系列函數能夠通過串口發送數據。
標準 C 庫中的 printf
函數最終會調用底層的字符輸出函數,而不同編譯器對這些底層函數的命名和接口定義略有不同。因此,開發者需要根據所使用的編譯器環境,選擇并實現對應的函數。
🛠? 二、在不同編譯器下的實現方法
1. Keil MDK 環境(ARMCC / AC6)
在 Keil MDK 中,標準輸入輸出函數依賴于 ARM 自帶的 C 標準庫。要重定向 printf
,需要重寫 _sys_write()
或者更常用的 fputc()
函數。
// Keil MDK 下的標準重定向函數
int __io_putchar(int ch)
{HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);return ch;
}
或者使用傳統的:
int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);return ch;
}
?? 注意:如果使用的是 ARM Compiler 6(即基于 LLVM 的編譯器),建議優先使用
__io_putchar()
。
2. GCC 編譯器環境(適用于 STM32CubeIDE、Makefile + arm-none-eabi-gcc)
在 GCC 環境下,標準輸出函數依賴于新lib庫(newlib-nano)。此時需要實現 _write()
函數來捕捉 write()
調用,從而完成串口輸出。
// GCC 下的重定向函數
int _write(int fd, char *ptr, int len)
{HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, HAL_MAX_DELAY);return len;
}
該函數接收文件描述符 fd
(通常我們忽略它)、指向字符串的指針 ptr
,以及長度 len
,然后將整個緩沖區通過串口發送出去。
🔁 三、統一方式:使用宏定義簡化適配
為了兼容不同編譯器,可以使用預處理器宏定義統一代碼風格,避免重復編寫兩個版本。
// 通用重定向頭文件或代碼段
#ifdef __GNUC__#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endifPUTCHAR_PROTOTYPE
{HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, HAL_MAX_DELAY);return ch;
}// GCC 特定部分
#ifdef __GNUC__
int _write(int fd, char *ptr, int len)
{HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, HAL_MAX_DELAY);return len;
}
#endif
這樣處理后,只需切換編譯器即可自動適配對應函數,提高代碼復用性和可維護性。
💡 四、注意事項
- 串口句柄:確保
&huart1
已被正確初始化并在全局作用域中可用。 - 阻塞問題:
HAL_UART_Transmit()
是阻塞函數,若用于中斷上下文或實時性強的場景,請改用非阻塞方式(如DMA或中斷發送)。 - 性能優化:頻繁調用
printf()
可能影響性能,建議僅用于調試階段。 - 重定向范圍:除了輸出,還可以重定向輸入(如
scanf
),但需重寫對應的_read()
或fgetc()
。
📌 五、總結
編譯器 | 需重寫的函數 | 函數原型 |
---|---|---|
MDK(Keil) | fputc / __io_putchar | int fputc(int ch, FILE *f) / int __io_putchar(int ch) |
GCC | _write | int _write(int fd, char *ptr, int len) |
通過以上方式,我們可以靈活地在 STM32 開發中實現串口重定向,為調試提供極大的便利。
📚 參考資料
- CSDN 博客 - 原文鏈接
- ST官方 HAL 庫文檔
- GCC 新版標準庫(newlib-nano)說明文檔
📢 如您發現任何錯誤或有改進建議,歡迎留言交流!
版權聲明:本文為原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請注明出處并保留原文鏈接。