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。