STM32开发中重定向printf输出到串口的方法及实际应用技巧(基于HAL库和CubeMX配置,包含巧用goto语句)

在stdio.h中的printf 原本输出到控制台, 在单片机应用中一般将其改到串口, 并利用串口输出信息来调试程序,非常方便。(本文以USART1为例)

此外CubeMX及CubeIDE 由于自动生成基础代码,因此每当更改硬件配置的时候, 都会被重置生成的基础代码。 这里使用goto语句来避免部分修改过的基础代码被替换掉。

方法如下:

  1. 配置CubeMX ,选择芯片: 选择芯片后勾选右上角蓝色图标:"StartProject"

  1. 在系统内核中,配置系统时钟。在mode中, 选择使用外部晶振。

  1. 进入 Clock Configuration 进行时钟树的配置(根据外接晶振的实际情况配置)

  1. 进入Connectivity选项卡配置 串口, 这里使用USART1, Mode选择为A,,, 即异步通讯。

5.在该页的Configuration中,依次配置ParameterSettings, NVIC及GPIO

根据串口的情况, 配置波特率,数据长度,停止位,及校验位,如下图绿框

接着配置NVIC, 勾选打开 global Interrupt

最后配置GPIO选项, 引脚以及由系统自动生成了, 这里需要将引脚改为上拉模式,如下图

  1. 在projectManager中,选择编译环境,准备自动生成代码

  1. 最后一步, 生成代码

在生成的代码中,我们可以看到,基本外设的初始化等基础函数及框架都已经由CubeMX自己生成完毕,并能够直接使用了。

其中关于USART外设部分 主要由结构体UART_HandleTypeDef, 和相关外设初始化函数:

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_USART1_UART_Init(void);组成

这里为了方便维护,将printf重新定向做了一个.c文件和.h头文件。 并命名为uart_printf.c和uart_printf.h. 保存在UserSrc的文件夹中。打开选项卡, 对刚做的头文件路径进行添加。(否则即使在代码中添加了#include“uart_printf.h”也会找不到, 头文件必须添加搜索路径。)

同时在选项卡中勾选使用微库。 (否则, 无法使用微库, 也就是说, 你添加了stdio或者string这样的C语言标准库,也无法使用。)

接着在生成的代码中 添加头文件。 注意, 用户代码必须严格的写在USER CODE BEGIN和END之间, 否则容易被重置掉。

代码自动生成的相关外设,不用管。 如果printf使用的是USART1, 就将huart1的结构体删除, 因为我们把这个结构体的声明放在了uart_printf.h中

在main函数中使用goto语句跳过初始化, (其实也不是跳过初始化, 而是跳过系统自动生成的部分,使用用户代码部分中的初始化, 来避免更改配置后被重置的一些问题。 )

在下面USART初始化函数的位置添加 空闲中断函数

接着创建两个文件, uart_printf.h和uart_printf.c

/*************uart_printf.h*********************/

#ifndef _UART_PRINT_H
#define _UART_PRINT_H

#include "main.h"
#include "stdio.h"


#ifndef _UART_PRINT_C
//放置需要被外部调用的uart.c文件中的全局变量\函数

#endif
extern UART_HandleTypeDef huart1;

void Usart_SendString(uint8_t *str);
int fputc(int ch, FILE *f);
int fgetc(FILE *f);


#endif

uart_printf.c文件如下:

/*************Printf重定向UART**************/
/*用途:
*使用printf将打印内容通过串口发送。 
*原理:
*将C语言库函数中的fputc 和fgetc函数重新定向到UART串口
*使用方法及注意事项:
*使用前,需要在main.c中添加头文件 "stdio.h""uart_printf.h" 如果是keil编译器,同时需要在选项卡中勾选“使用微库”
*
*默认使用USART1串口, 当需要使用其他串口的时候, 修改huart1 为目标串口, 
*建议使用CubeMX生成的代码,这样直接修改huart1后面的标号即可直接使用
******************************************/
#define _UART_PRINTF_C


#include "uart_printf.h"



/*****************  发送字符串(重新定向) **********************/
void Usart_SendString(uint8_t *str)
{
    unsigned int k=0;
  do 
  {
      HAL_UART_Transmit(&huart1,(uint8_t *)(str + k) ,1,1000);
      k++;
  } while(*(str + k)!='\0');
  
}
///重定向c库函数printf到串口DEBUG_USART,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
    /* 发送一个字节数据到串口DEBUG_USART */
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);    
    
    return (ch);
}

///重定向c库函数scanf到串口DEBUG_USART,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
        
    int ch;
    HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, 1000);    
    return (ch);
}

编译一下,就可以使用printf函数输出串口了

例如在需要的地方 加上printf输出:

当程序运行到这里的时候, 就会利用串口1输出调试打印信息

物联沃分享整理
物联沃-IOTWORD物联网 » STM32开发中重定向printf输出到串口的方法及实际应用技巧(基于HAL库和CubeMX配置,包含巧用goto语句)

发表评论