如何在STM32上实现printf函数输出到串口
背景
printf是学习C语言时常用的函数,可以将想要显示的数字、字符串等显示在屏幕上
但单片机没有屏幕,于是便希望将结果输出到串口
本文提供两种实现方案(传统的printf函数重定向和DMA实现printf)
printf函数重定向
printf的底层操作实际上就是使用fputc函数一个一个输出字符到屏幕上,所以我们只需要将fputc函数进行修改,使其功能变为通过串口输出一个字符即可实现printf的重定向
具体代码如下
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
随后在main函数里面调用printf函数即可,方法与C语言完全一致
DMA实现
DMA能够大大提升串口的传输速度,既然能够实现printf的重定向,能否和DMA结合,在调用方便的基础上,提高传输速度呢?
仿造printf重定向
如果简单地对上面的代码进行替换,改成下面这种形式
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit_DMA(&huart1,(uint8_t*)&ch,1);
return ch;
}
这个时候如果你想使用这个新的printf输出“Hello world!”
那么你会发现串口只会一直输出H,串口助手接到的就会是HHHHH…
这是因为DMA传输的速度取决于串口发送的速度,在串口发送H的时候,后面的ello world!都会调用fputc函数,而这时DMA仍然在进行H的发送,所以导致最后只发送了一个H
如果在fputc函数里面加上一句延时,例如HAL_Delay(1),就又可以正常地进行工作
但是这和我们之前使用DMA的目的背道而驰,所以需要采用新的解决方案
构建新函数
构造如下函数,调用即可实现使用DMA输出到串口
void USART1_DMA_printf(const char *format,...)
{
uint16_t len;
va_list args;
va_start(args,format);
len = vsnprintf((char*)UartTxBuf,sizeof(UartTxBuf)+1,(char*)format,args);
va_end(args);
HAL_UART_Transmit_DMA(&huart1, UartTxBuf, len);
}
作者:zeandon