STM32 UART串口printf函数应用及浮点打印代码空间节省 (HAL)
在应用STM32的UART接口打印输出串口字符信息时,可以通过printf函数的重载和应用实现。但要打印输出浮点数据时,采用常规方式,对于Flash空间小的MCU,常常出现代码空间不够的报错,这里设计了替代的函数实现浮点转字符,从而解决空间不够报错的问题。
STM32 printf()函数重载
要使用printf函数通过串口输出字符打印,在工程里引入两个文件即可:
usart.h:
#ifndef _USART_H
#define _USART_H
#include "stm32g0xx_hal.h"
#include "stdio.h"
int fputc(int ch, FILE *f) ;
#endif
注意这一行,根据实际所用的芯片进行调整:
#include "stm32g0xx_hal.h"
usart.c:
#include "usart.h"
extern UART_HandleTypeDef huart2; //声明串口
/* USER CODE BEGIN 1 */
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END 1 */
注意这两行,根据实际所用的串口号进行调整(这里用的是huart2):
extern UART_HandleTypeDef huart2; //声明串口
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);
然后再主文件main.c里引入:
#include "usart.h"
就可以在需要的地方通过printf()函数进行打印输出,如:
printf("Do you have problem with float print?\r\n");
有一个顺序需要注意,必须在STM32CUBE配置UART后,进行一次编译后,再引入usart.h和usart.c文件,再编译运行,则printf输出功能正常。如果在STM32CUBE配置UART后,没有进行初次编译就直接引入usart.h和usart.c,然后编译,printf功能运行会出现异常不会输出。
STM32 printf浮点打印常规方式
要想进行浮点打印输出,如:
printf("Float Data: %f \r\n", 100.001);
编译则会告警,是因为没有把支持选项打开:
在STM32CUBEIDE工具里,在此处选择printf支持浮点转换打印:
采用这种方式(snprintf()库函数也必须开启这种方式才能使用),引入的代码比较大,编译占用空间比较多,对于STM32F0, STM32L0, STM32G0等MCU, 容易超过FLASH空间导致不能用。
通过单独编写浮点转字符串的函数,则可以解决问题,占用的FLASH空间小很多。
STM32 printf浮点转字符串函数设计
设计的printf浮点转字符串函数如下:
/*
*Convert float to string type
*Written by Pegasus Yu in 2022
*stra: string address as mychar from char mychar[];
*float: float input like 12.345
*flen: fraction length as 3 for 12.345
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
void py_f2s4printf(char * stra, float x, uint8_t flen)
{
uint32_t base;
int64_t dn;
char mc[32];
base = pow(10,flen);
dn = x*base;
sprintf(stra, "%d.", (int)(dn/base));
dn = abs(dn);
if(dn%base==0)
{
for(uint8_t j=1;j<=flen;j++)
{
stra = strcat(stra, "0");
}
return;
}
else
{
if(flen==1){
sprintf(mc, "%d", (int)(dn%base));
stra = strcat(stra, mc);
return;
}
for(uint8_t j=1;j<flen;j++)
{
if((dn%base)<pow(10,j))
{
for(uint8_t k=1;k<=(flen-j);k++)
{
stra = strcat(stra, "0");
}
sprintf(mc, "%d", (int)(dn%base));
stra = strcat(stra, mc);
return;
}
}
sprintf(mc, "%d", (int)(dn%base));
stra = strcat(stra, mc);
return;
}
}
STM32 printf浮点转字符串函数应用及效果
采用如下的代码进行测试:
char mychar[100];
py_f2s4printf(mychar, 0.000, 3);
printf("\r\n x: %s\r\n", mychar);
py_f2s4printf(mychar, 1.000, 3);
printf("\r\n x: %s\r\n", mychar);
py_f2s4printf(mychar, -1.000, 3);
printf("\r\n x: %s\r\n", mychar);
py_f2s4printf(mychar, -1.023, 3);
printf("\r\n x: %s\r\n", mychar);
py_f2s4printf(mychar, 1.023, 3);
printf("\r\n x: %s\r\n", mychar);
py_f2s4printf(mychar, -1.123, 3);
printf("\r\n x: %s\r\n", mychar);
串口打印输出效果:
注意事项
如果采用单独的py_f2s4printf()函数后,编译空间仍然超过了Flash的空间,则需要摒弃printf()函数的使用,直接使用HAL函数调用方式替代printf()方式,如将
py_f2s4printf(mychar, -1.123, 3);
printf("\r\n x: %s\r\n", mychar);
改为:
py_f2s4printf(mychar, -1.123, 3);
HAL_UART_Transmit(&huart2, " \r\n x: ", strlen(" \r\n x: "), 0xFFFF);
HAL_UART_Transmit(&huart2, mychar, strlen(mychar), 0xFFFF);
HAL_UART_Transmit(&huart2, "\r\n", strlen("\r\n"), 0xFFFF);
虽然处理繁杂一点(也可以用 strcat()函数先连接整个字符串,串口则只发送一次),但却可以进一步缩减编译后所占空间的大小。
–End–