在 STM32 上輕鬆使用 printf 函數

除了利用閃爍著 LED 外,向序列控制台發送列印資訊可能是除錯嵌入式專案時最簡單、最直接且最常用的技術。 雖然大多數平台都擁有可以在 UART 匯流排上傳輸資料的 API,但它們在功能和普及度上都遜於 printf() 函數。但在嵌入式 C 應用中僅利用此函數包含 stdio 函式庫是遠遠不夠的。在 STM32 專案中,我們還需要額外加上幾行程式碼。

對於那些希望透過 UART 總線發送和接收格式化資料的人,請參考另一貼文「在 STM32 上輕鬆使用 scanf 函數」!

步驟

此程序涵蓋了配置和啟用適當的 UART 周邊裝置的預備步驟、將該 UART 實例對應到 printf() 函數的主要步驟,以及用於列印浮點的可選輔助步驟。 本文適用於使用 STM32CubeIDE(版本 1.11.2)開發的項目,但也可以擴展到其他環境。

0. 建立 UART 實例

為了在接下來的步驟中正確地使用 stdio 庫中的 printf() 函數,我們必須配置一個 UART(或 USART)周邊裝置以傳輸格式化字串。通常情況下,在 ST 開發板上操作時,應選擇可以連接到 ST-LINK 編程器/除錯器 RX 和 TX 引腳的 UART 周邊裝置。 因為這樣可以透過 ST-LINK 的 USB 虛擬 COM 埠橋接將字串傳送到序列控制台。 幸運地,在 STM32CubeIDESTM32CubeMX 中啟動新專案時,此 UART 實例已預設配置完成!作為程式設計師,你只需要留意已經配置的特定 UART,然後繼續下一步。

對於那些已有專案但未配置 UART 的用戶,只需開啟專案的 .ioc 檔案,並按照圖1 所示進行修改即可。 具體來說,

  • 選擇適當的周邊裝置實例
  • 設定模式和配置參數(通常使用的設定如圖1 所示)
  • 確保將適當的 GPIO 引腳配置為 UART RX 和 TX。

完成後,儲存 .ioc 檔案以產生專案的程式碼。

圖 1: 啟用和設定所需的U(S)ART周邊裝置的範例。

1. 重新定向 printf() 至 UART 實例

UART 準備就緒後,只需新加幾行程式碼即可新增 printf()

a. 將 #include <stdio.h> 加入 main.c 檔案頂部的「包含」部分中(圖2)。

include

圖 2: 包括 stdio

b. 在 main.c 檔案中,將以下程式碼複製並貼上到 main()函數前、UART 控制代碼聲明。你可以選擇「私有函數原型」部分,如下圖3 所示。 請注意,UART 控制代碼必須從 &huart? 更改為所需UART 周邊裝置的控制代碼(例如 &huart2


#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart?, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}

putchar_prototype

圖 3: 將重定向程式碼新增至 main.c 檔案中。

除了浮點格式說明符之外,printf() 函數現在應該按預期運行。若要啟用這些功能,請繼續執行下一步。

2. 啟用浮點支援(可選)

為了說明浮點格式化的問題,我們可以使用 printf()參考頁面提供的範例程式碼。

printf("Characters: %c %c\n", 'a', 65);
printf("Decimals: %d %ld\n", 1977, 650000L);
printf("Preceding with blanks: %10d\n", 1977);
printf("Preceding with zeros: %010d\n", 1977);
printf("Some different radices: %d %x %o %#x %#o\n", 100, 100, 100, 100, 100);
printf("floats: %4.2f %+.0e %E\n", 3.1416, 3.1416, 3.1416);
printf("Width trick: %*d\n", 5, 10);
printf("%s\n", "A string");

將此程式碼新增至我們的專案後,會出現一條警告,解釋「未啟用浮動格式支援」。如果我們繼續建置並運行該項目,序列控制台中的輸出將確認不會列印浮點數(圖 4)。

ex_output_noFloat

圖 4: 未啟用浮點格式支援的範例輸出。

如果您的應用程式中未使用浮點數,這可能不是問題。但是如果它們存在並且需要被啟用,只需右鍵單擊專案資源管理器中的專案名稱並選擇 屬性(Properties )。 在「C/C++ Build」類別中選擇 設定(Settings),然後在工具設定(Tool Settings)標籤下選擇 MCU 設定。 勾選「將 float 與 newlib-nano 中的 printf 一起使用」旁邊的方塊,如下圖 5 所示。 按一下 套用並關閉(Apply and Close )

請注意,啟用 printf() 的浮點格式化支援將消耗相當多的額外記憶體。 具體來說,在沒有浮點支援的情況下,printf() 函數將消耗大約 0.35 KB 的 RAM 和 10.30 KB 的快閃記憶體。 對於低階設備來說這可能是一個問題。

圖 5: 啟用浮動格式支援。

現在,在重新建置專案並執行程式碼後,浮點數數值已正確格式化,並如圖6所示。

ex_output_float

圖 6: 啟用浮點格式支援的範例輸出。