STM32标准库_03 | 串口printf打印

本篇文章主要介绍STM32的调试利器,串口printf打印输出,希望能给人以收获。

1.开发环境

软件环境

使用MDK5.25版本,芯片包为STM32F4系列。

硬件环境

开发板:STM32F407VGT6开发板,是一款大容量芯片,最高能跑168MHz。

烧录器:STlink或者Jlink。

2.工程搭建

直接复制上一篇代码,在工程栏加入/LIB/src文件夹下的串口库函数文件stm32f4xx_usart.c,在/APP文件夹下加入usart.c和usart.h文件并添加到MDK工程栏。

开始编写串口初始化函数和重定义printf打印函数。

在usart.c文件中添加串口初始化函数,F407和F103有些区别,1是串口挂载的时钟总线,2是F103对于串口TX和RX是分别初始化为复用推挽输出和上拉输入的。

/*
*********************************************************************************************************
*	函 数 名: uart1_Init
*	功能说明: 串口1初始化函数
*	形    参: 1.bound(串口波特率)
*	返 回 值: 无
*********************************************************************************************************
*/ 
void uart1_Init(u32 bound)
{
        //GPIO端口设置
        GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
 
	//串口1对应引脚复用映射
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1
	
	//USART1端口配置
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//速度50MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
	GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10

        //USART1 初始化设置
	USART_InitStructure.USART_BaudRate = bound;//波特率设置
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode =  USART_Mode_Tx;	//收发模式
        USART_Init(USART1, &USART_InitStructure); //初始化串口1
	
        USART_Cmd(USART1, ENABLE);  //使能串口1 
	//USART_ClearFlag(USART1, USART_FLAG_TC);   //解决第一个字节丢失问题,如果第一个字节丢失可以加上这行
}

对于重定义printf函数有两种方法,一种是使用微库,一种是不是用微库(正点原子)使用的方法。

1.使用微库重定义printf函数

注意:printf函数依赖于"stdio.h",在使用的时候记得添加上"stdio.h"。

如果是C++文件则修改成

2.不使用微库重定义printf函数

在原来的fputc函数的基础上再加入避免使用半主机模式的一些代码(参考正点原子)。

可以参考这篇对于半主机模式的理解

小结:所谓重定义就是修改fputc函数的底层代码,修改成运行一次串口发送一个字节的数据。

3.测试

3.打印方案

编写打印代码

于我而言,我个人把打印分成两种,一种是错误打印(一般用于else的后面,或者校验失败的地方),另一种就是常规打印,这些打印还可能遇到一些场景,例如我的单片机资源比较少,我就写程序的时候用一下,或者我想控制我的打印输出等等。

直接上代码开讲

USER_DEBUG是程序控制的开关,用于单片机资源比较少的时候,我们调试的时候用一下。

Print_Switch是一个接口控制的开关,可用于远程网络或者本地串口修改,来开启或者关闭打印。

当然,我们还可以分很多级别的打印,希望各位举一反三。

测试

4.总结

这个宏定义最好放在.h头文件中,方便其他.c文件,后续我会加在Dbg.c和Dbg.h中,对于逻辑复杂的状态机,用打印的方法是一个很好的调试手段,当然如果遇到死机,那得用仿真器Debug了。

代码已全部上传到gitee,希望各位小伙伴们在下载的同时不忘点击Star,地址:https://gitee.com/Notmi/stm32-standard-peripheral-libraries

原文地址:https://www.cnblogs.com/zhanxiaohong0303/p/xh_2020_7_1.html