STM32 UART串口printf函数应用及浮点打印代码空间节省 (HAL)

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–

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,以下是在STM32中使用USART3和HAL库实现printf函数的基本步骤: 1. 配置USART3模块 在CubeMX中,您需要配置USART3模块,包括波特率、数据位数、停止位数、奇偶校验等参数。然后,在代码中使用HAL库初始化USART3,例如: ``` UART_HandleTypeDef huart; huart.Instance = USART3; huart.Init.BaudRate = 9600; huart.Init.WordLength = UART_WORDLENGTH_8B; huart.Init.StopBits = UART_STOPBITS_1; huart.Init.Parity = UART_PARITY_NONE; huart.Init.Mode = UART_MODE_TX_RX; huart.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart) != HAL_OK) { Error_Handler(); } ``` 注意,上述代码中的USART3和初始化参数应根据您的具体硬件和软件环境进行相应的更改。 2. 重定向printf函数 为了使printf函数能够输出到USART3,我们需要重新定义printf函数。在main函数中,您可以使用以下代码重新定义printf函数: ``` int __io_putchar(int ch) { HAL_UART_Transmit(&huart, (uint8_t*)&ch, 1, 0xFFFF); return ch; } int _write(int file, char *ptr, int len) { int DataIdx; for (DataIdx = 0; DataIdx < len; DataIdx++) { __io_putchar(*ptr++); } return len; } ``` 在上述代码中,我们定义了__io_putchar函数,用于将单个字符发送到USART3。然后,我们使用_write函数将输出缓冲区中的数据发送到USART3。 3. 使用printf函数输出数据 现在,您可以在代码中使用printf函数输出数据到USART3,例如: ``` printf("Hello, world!\r\n"); ``` 在上述代码中,我们使用printf函数输出“Hello, world!”字符串,并在最后添加回车换行符,以便在串口终端中正确显示。 希望这些步骤能够帮助您在STM32中成功使用USART3和HAL库实现printf函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PegasusYu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值