在不同编译环境下进行串口重定向,需要重写的函数不同。
serial.h
为方便移植,新建一个 User 文件夹,在文件夹中新建 serial.h 文件。
包含必要的头文件并声明要重定义的函数。
#ifndef __SERIAL_H
#define __SERIAL_H
#include "usart.h"
#include "stdio.h"
#pragma import(__use_no_semihosting)
int _write(int fd, char *ptr, int len);
void _sys_exit(int x);
#endif
serial.c
在 User 文件夹中新建 serial.c 文件。
重定义函数。
#include "serial.h"
int _write(int fd, char *ptr, int len)
{
HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, 0xFFFF);
return len;
}
/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x)
{
x = x;
}
c_cpp_properties.json
在 .vscode 文件夹中找到 c_cpp_properties.json 文件。
在 “includePath” 中添加 “${workspaceFolder}/User”。
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/Core/Inc",
"${workspaceFolder}/Drivers/STM32G4xx_HAL_Driver/Inc",
"${workspaceFolder}/Drivers/STM32G4xx_HAL_Driver/Inc/Legacy",
"${workspaceFolder}/Drivers/CMSIS/Device/ST/STM32G4xx/Include",
"${workspaceFolder}/Drivers/CMSIS/Include",
"${workspaceFolder}/Middlewares/Third_Party/FreeRTOS/Source/include",
"${workspaceFolder}/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F",
"${workspaceFolder}/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2",
"${workspaceFolder}/User"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE",
"USE_HAL_DRIVER",
"STM32G431xx"
],
"compilerPath": "D:/app/gcc-arm-none-eabi/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gcc.exe",
"cStandard": "c23",
"intelliSenseMode": "gcc-arm",
"cppStandard": "c++23"
}
],
"version": 4
}
Makefile
新建 .c 文件和 .h 文件后需要在 Makefile 文件中修改 C_SOURCE 和 C_INCLUDES。
若想打印浮点数,需要修改 LDFLAGS。
-
C_SOURCE
添加 “User/serial.c”。
###################################### # source ###################################### # C sources C_SOURCES = \ Core/Src/main.c \ Core/Src/gpio.c \ Core/Src/adc.c \ Core/Src/dma.c \ Core/Src/fdcan.c \ Core/Src/stm32g4xx_it.c \ Core/Src/stm32g4xx_hal_msp.c \ Core/Src/stm32g4xx_hal_timebase_tim.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_adc.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_adc_ex.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_ll_adc.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_rcc.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_rcc_ex.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_flash.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_flash_ex.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_flash_ramfunc.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_gpio.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_exti.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_dma.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_dma_ex.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_pwr.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_pwr_ex.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_cortex.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_fdcan.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_tim.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_tim_ex.c \ Core/Src/system_stm32g4xx.c \ Core/Src/app_freertos.c \ Middlewares/Third_Party/FreeRTOS/Source/croutine.c \ Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \ Middlewares/Third_Party/FreeRTOS/Source/list.c \ Middlewares/Third_Party/FreeRTOS/Source/queue.c \ Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \ Middlewares/Third_Party/FreeRTOS/Source/tasks.c \ Middlewares/Third_Party/FreeRTOS/Source/timers.c \ Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \ Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c \ Core/Src/usart.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_uart.c \ Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_hal_uart_ex.c \ Core/Src/tim.c \ Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \ User/serial.c
-
C_INCLUDES
添加 “-IUser”。
# C includes C_INCLUDES = \ -ICore/Inc \ -IDrivers/STM32G4xx_HAL_Driver/Inc \ -IDrivers/STM32G4xx_HAL_Driver/Inc/Legacy \ -IDrivers/CMSIS/Device/ST/STM32G4xx/Include \ -IDrivers/CMSIS/Include \ -IMiddlewares/Third_Party/FreeRTOS/Source/include \ -IMiddlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F \ -IMiddlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \ -IUser
-
LDFLAGS
添加 “LDFLAGS += -lc -lrdimon -u _printf_float”。
####################################### # LDFLAGS ####################################### # link script LDSCRIPT = STM32G431KBUx_FLASH.ld # libraries LIBS = -lc -lm -lnosys LIBDIR = LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections # printf float LDFLAGS += -lc -lrdimon -u _printf_float
printf
完成以上配置后就可以通过 printf 函数将数据打印到串口上了。
这里放一个我用于打印任务堆栈最小剩余空间的测试程序。
-
led.h
使用 printf 函数需包含 “stdio.h” 头文件,这里我 “main.h” 中已经包含了。
#ifndef __LED_H #define __LED_H #include "FreeRTOS.h" #include "task.h" #include "main.h" #include "cmsis_os.h" #endif
-
led.c
#include "led.h" extern osThreadId_t LedHandle; void LedTask(void *argument) { while (pdTRUE) { // HAL_GPIO_TogglePin(GPIOA, LED_GREEN_Pin); HAL_GPIO_TogglePin(GPIOA, LED_RED_Pin); printf(" the min free stack size of LedTask is %ld \r\n", (uint32_t)uxTaskGetStackHighWaterMark(LedHandle)); vTaskDelay(pdMS_TO_TICKS(250)); } }
-
serial monitor
---- 已打开串行端口 COM4 ----
the min free stack size of LedTask is 26
the min free stack size of LedTask is 26
the min free stack size of LedTask is 26
the min free stack size of LedTask is 26
the min free stack size of LedTask is 26
the min free stack size of LedTask is 26
the min free stack size of LedTask is 26
the min free stack size of LedTask is 26
the min free stack size of LedTask is 26
the min free stack size of LedTask is 26
---- 关闭串行端口 COM4 ----printf 函数占用堆栈较大,若给任务分配的堆栈不足,运行时会进硬件错误中断。
/** * @brief This function handles Hard fault interrupt. */ void HardFault_Handler(void) { /* USER CODE BEGIN HardFault_IRQn 0 */ /* USER CODE END HardFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_HardFault_IRQn 0 */ /* USER CODE END W1_HardFault_IRQn 0 */ } }