【GD32】---- 使用GD32调试串口并实现printf打印输出
1 复制工程模板
直接复制工程模板里的系统文件和固件库文件到新的工程文件01_USART_Printf
2 新建keil工程
参考上一篇博文:【GD32】---- 移植工程模板及点灯测试
3 编写代码
3.1 创建USART文件
创建一个USART.c
文件,放于05_UserDriver
文件夹中
USART.h
/**
* ************************************************************************
*
* @file USART.h
* @author zxr
* @brief
*
* ************************************************************************
* @copyright Copyright (c) 2024 zxr
* ************************************************************************
*/
#ifndef USART_H_
#define USART_H_
#include "gd32e23x_rcu.h"
#include "gd32e23x_gpio.h"
#include "gd32e23x_usart.h"
#define Printf_GPIO_RCU RCU_GPIOA //串口对应GPIO端口的时钟
#define Printf_USART_RCU RCU_USART0 //对应串口号的时钟
#define Printf_GPIO GPIOA //串口对应GPIO端口
#define Printf_GPIO_AF GPIO_AF_1 //串口是GPIO引脚的复用功能1(查询芯片数据手册)
#define Printf_TX_PIN GPIO_PIN_9 //串口对应的GPIO引脚
#define Printf_RX_PIN GPIO_PIN_10 //串口对应的GPIO引脚
#define Printf_USART USART0 //printf所使用的串口
/**
* ************************************************************************
* @brief 函数声明
* ************************************************************************
*/
void USART_Init(void);
void USART_send_char(uint8_t ch);
void USART_send_string(uint8_t *string);
#endif
USART.c
/**
* ************************************************************************
*
* @file USART.c
* @author zxr
* @brief
*
* ************************************************************************
* @copyright Copyright (c) 2024 zxr
* ************************************************************************
*/
#include "USART.h"
/**
* ************************************************************************
* @brief USART初始化配置
*
*
* ************************************************************************
*/
void USART_Init(void)
{
rcu_periph_clock_enable(Printf_GPIO_RCU); //使能串口对应的GPIO端口的时钟
rcu_periph_clock_enable(Printf_USART_RCU); //使能串口时钟
gpio_af_set(Printf_GPIO, Printf_GPIO_AF, Printf_TX_PIN); //将PA9复用为串口的TX引脚
gpio_af_set(Printf_GPIO, Printf_GPIO_AF, Printf_RX_PIN); //将PA10复用为串口的RX引脚
gpio_mode_set(Printf_GPIO, GPIO_MODE_AF, GPIO_PUPD_PULLUP, Printf_TX_PIN); //复用模式,上拉
gpio_mode_set(Printf_GPIO, GPIO_MODE_AF, GPIO_PUPD_PULLUP, Printf_RX_PIN); //复用模式,上拉
gpio_output_options_set(Printf_GPIO, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, Printf_TX_PIN);//推挽输出
gpio_output_options_set(Printf_GPIO, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, Printf_RX_PIN);//推挽输出
usart_deinit(Printf_USART); //复位串口
usart_baudrate_set(Printf_USART, 115200); //设置波特率115200
usart_parity_config(Printf_USART, USART_PM_NONE); //无校验位
usart_word_length_set(Printf_USART, USART_WL_8BIT); //8位数据长度
usart_stop_bit_set(Printf_USART, USART_STB_1BIT); //1位停止位
usart_enable(Printf_USART); //使能串口
usart_transmit_config(Printf_USART, USART_TRANSMIT_ENABLE); //使能串口发送功能
usart_receive_config(Printf_USART, USART_RECEIVE_ENABLE); //使能串口接收功能
}
/**
* ************************************************************************
* @brief USART发送单个字符
*
* @param[in] ch 要发送的字符
*
* ************************************************************************
*/
void USART_send_char(uint8_t ch)
{
usart_data_transmit(Printf_USART, (uint8_t)ch); //发送一个字符
while(usart_flag_get(Printf_USART, USART_FLAG_TBE) == RESET); //等待发送数据缓冲区标志置位
}
/**
* ************************************************************************
* @brief USART发送字符串
*
* @param[in] string 字符串
*
* ************************************************************************
*/
void USART_send_string(uint8_t *string)
{
while(string && *string) //地址为空或者值为空跳出
{
USART_send_char(*string++);
}
}
3.2 USART基本功能测试
/**
* ************************************************************************
*
* @file main.c
* @author GD32
* @brief
*
* ************************************************************************
* @copyright Copyright (c) 2024 GD32
* ************************************************************************
*/
#include "gd32e23x.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "USART.h"
/**
* ************************************************************************
* @brief 主函数main
*
*
* @return
* ************************************************************************
*/
int main(void)
{
USART_Init();
USART_send_string("hello\n");
while(1)
{
}
}
测试结果
基本函数功能正常,可以输出内容
3.3 重定向printf
为了方便打印数字,小数等内容,重定向printf函数。首先c语言的printf函数中不断循环调用fputc函数,所以需要重写fputc函数,这个函数的功能就是打印输出一个字符。
添加头文件
打开USATR.h
文件,在里面添加#include "stdio.h"
添加函数声明
然后再声明一下int fputc(int ch, FILE *f);
函数
重写fputc函数
在USART.c
中,重写fputc函数
/**
* ************************************************************************
* @brief 重定向printf函数
*
* @param[in] ch Comment
* @param[in] f Comment
*
* @return
* ************************************************************************
*/
int fputc(int ch, FILE *f)
{
usart_data_transmit(Printf_USART, (uint8_t) ch);
while(RESET == usart_flag_get(Printf_USART, USART_FLAG_TBE));
return ch;
}
3.4 测试printf
补充main函数
在main.c
中添加测试代码
/**
* ************************************************************************
*
* @file main.c
* @author GD32
* @brief
*
* ************************************************************************
* @copyright Copyright (c) 2024 GD32
* ************************************************************************
*/
#include "gd32e23x.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "USART.h"
/**
* ************************************************************************
* @brief 主函数main
*
*
* @return
* ************************************************************************
*/
int main(void)
{
USART_Init();
//USART_send_string("hello\n");
printf("hello\n");
printf("%d\n", 10);
while(1)
{
}
}
勾选微库
编译前记得勾选微库Use MicroLIB
如果勾选后编译报错,且报错内容为:
.\Objects\01_USART_Printf.axf: Error: L6218E: Undefined symbol __use_two_region_memory (referred from startup_gd32e23x.o).
和
.\Objects\01_USART_Printf.axf: Error: L6218E: Undefined symbol __initial_sp (referred from entry2.o).
解决办法可参考我的博文:关于keil中勾选微库"Use MicroLIB"调试printf时编译报错问题
编译烧录运行
串口调试助手正常显示
串口调试及printf调试成功