莫离 · 2022年04月06日

【GD32F310开发板试用】入门向-usart的使用及printf函数的重定向

摘要

  • 首先感谢极术社区和兆易创新公司给我这次机会,入选GD32F310K-START开发板的测评和试用。
  • 本开发板板载一块GD32F310K8T6芯片,该芯片是ARM Cortes-M4的核心,片内内置64K的FLASH及8K的SRAM供开发者使用。板载一个用户LED及一个用户Wakeup按键,同时版上集成了GD-Link下载器,开箱即用。
  • 本人是微电子专业,所以在项目中,重点使用单片机对ASIC芯片进行测试,开发相应的测试程序。这对单片机的IO及外设性能和可靠性有较高的要求。本文站在入门的角度,从建立工程开始到配置工程再到USART外设的使用,重点提及printf的重定向问题。
  • 后续将会陆续完成对USART、IIC及SPI等外设的DEMO及功能测评。

正文

开发环境

  • 系统:windows 10 professional
  • 软件:keil uVision 5.36

开箱上电

拿到开发板,如果供电正确,即会开始执行板内程序,用户LED1会开始闪烁。
 title=

创建工程

打开Keil软件后新建工程
 title=
选择保存路径,注意不要出现中文
 title=
选择器件,选择GigaDevice -> GD32F3x0 -> GD32F310 -> GD32F310K8
 title=
这里不使用操作系统,cancel即可
 title=
之后,右键工程,配置工程
 title=
在这里可以重命名,可以对代码文件进行管理和添加删除。
 title=

库文件和源代码。

这里沿用固件库的文件组织方式,包括Application、CMSIS、Peripherals、Startup和Utilities几个组,其中CMSIS、Peripherals、Startup都是沿用固件库中的文件,将开发板配置文件夹中加入GD32F310K-START开发板的驱动文件,驱动文件可在开发板历程库中获取。
 title=
之后,在usart.c文件中配置usart的initial和config函数。

/*!
    \brief      configure the USART0 GPIO ports
    \param[in]  none
    \param[out] none
    \retval     none
*/
void usart0_gpio_config(void)
{
    /* enable COM GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);

    /* connect port to USARTx_Tx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);

    /* connect port to USARTx_Rx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10);

    /* configure USART Tx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_9);

    /* configure USART Rx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_10);
}

/*!
    \brief      configure the USART0
    \param[in]  none
    \param[out] none
    \retval     none
*/
void usart0_config(void)
{
    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART0);

    /* USART configure */
    usart_deinit(USART0);
    /* config data length */
    usart_word_length_set(USART0, USART_WL_8BIT);
    /* config stop bit(s) length */
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    /* config if has parity length */
    usart_parity_config(USART0, USART_PM_NONE);
    /* config usart speed(BPS) */
    usart_baudrate_set(USART0, 115200U);
    /* config receive mode enable */
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    /* config transmit mode enable */
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);

    usart_enable(USART0);
}

在usart.h中配置头文件

#ifndef USART_H
#define USART_H

/* configure the USART0 GPIO ports */
void usart0_gpio_config(void);
/* configure the USART0 */
void usart0_config(void);


#endif /* USART_H */

创建主函数文件main.c

#include "gd32f3x0.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "gd32f310k_start.h"

#include "usart.h"
#include "gpio.h"

/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
    /* initilize the USART  */
    usart0_gpio_config();
    usart0_config();
    /* print out */
    printf("Hello world!\n\r");
    while(1) {
    }
}

配置工程

之后配置工程,点开小锤子
 title=
在define中加入与开发板和芯片相关的define选项
 title=
之后查看include paths,将所需要的头文件include进工程。
 title=
之后将仿真器和下载器配置成板载的GD-Link,也就是CMSIS-DAP,下载器与仿真器一致即可。
 title=
 title=
之后进入setting,勾选reset and run,方便后续下载后即复位运行。
 title=
至此,配置完成,可以点击rebuild进行工程建立,无错后即可进行Download。但是,如果打开串口助手,并没有出现”Hello world”的输出。经对比库中例程发现,其相比较本工程,多配置了一个Use MicroLIB,即使用缺省C语言库。它可装入少量内存中,与嵌入式应用程序配合使用,且这些应用程序不在操作系统中运行。MicroLib提供了一个有限的stdio子系统,它仅支持未缓冲的stdin、stdout和stderr。勾选该选项后重写fputc函数即可实现printf输出到串口。实际上该问题有三种解决方法。

printf重定向

方法1

使用microLIB库
 title=
之后重定向fputc

/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
    usart_data_transmit(USART0, (uint8_t) ch);
    while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
    return ch;
}

方法2

不使用MicroLIB库,但要取消半主机模式,然后重定向fputc

#if __ARMCC_VERSION >= 6000000
    __asm(".global __use_no_semihosting");
#elif __ARMCC_VERSION >= 5000000
    #pragma import(__use_no_semihosting)
        struct __FILE { 
                int handle; 
        };
#endif

FILE __stdout;          
void _sys_exit(int x) 
{ 
    x = x; 
}

/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
    usart_data_transmit(USART0, (uint8_t) ch);
    while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
    return ch;
}

根据此处配置的编译器不同而编译不同的语句
 title=

方法3

如果使用gcc编译,则上两种方法都不可行,所以此时不用重定义fputc函数,而是重定义_write函数。

#include <stdio.h>

int _write(int fd, char *ptr, int len)  
{  
  HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, 0xFFFF);
  return len;
}

至此,通过编译及下载,连上串口助手,即可看到久违的“Hello World”。

结果展示

 title=

参考文档及blog

GD32F3x0_Firmware_Library_V2.2.0
GD32F3x0_Demo_Suites_V2.2.0
GD32F3x0_yonghushouce_Rev2.5.pdf
GD32F3x0_shiyongzhinan_Rev1.2.pdf
https://blog.csdn.net/toopoo/article/details/115287497
https://blog.csdn.net/zjutczj/article/details/115751191

推荐阅读
关注数
10711
内容数
187
中国高性能通用微控制器领域的领跑者兆易创新GD系列芯片技术专栏。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息