hehung · 2022年11月26日 · 四川

【GD32F427开发板试用】1. 串口实现scanf输入控制LED

前言

终于在这周四拿到板子了,本来周一就可以拿到的,因为疫情封控,在周四才拿到板子,但是周内太忙了,来不及上手,趁着周末赶紧玩一玩。

首先是弄一下串口,因为串口是比较核心的一个功能,在开发过程中可以方便我们调试。

本文主要实现下面两个功能

  1. 本文是基于MDK开发的,实现了串口的printf以及scanf功能,完善了MDK支持的fgetc功能用于支持scanf;
  2. 上位机发送串口指令open以及close,下位机收到了这两个指令之后打开LED或者关闭LED;
  3. 如果收到的指令不是open或者close,打印Unknow command。

硬件连接

串口硬件

在操作串口之前我们需要知道板子的引脚复用关系,,以便确定使用哪一路串口。
引脚复用关系表在《GD32F427xx\_Datasheet\_Rev1.2.pdf》中2.6.6. GD32F427xx pin alternate functions。
我们可以知道USART0可以复用的引脚有PA9,PA10以及PB6,PB7。
 title=
 title=
本来打算使用PA9与PA10的,但是查看原理图可知:PA9通过一个三极管与VCC连接到了一起,通过PD2进行控制,所以不能用来作为串口引脚使用了。
 title=

所以最终确定使用PB6与PB7作为串口的TX引脚与RX引脚。

LED硬件

GD32F427V-START开发板只支持LED2作为用户LED,原理图如下:
 title=

见原理图可知,PC6为高电平的时候LED亮,PC6为低电平的时候,LED灭。

软件实现

串口初始化

串口初始化可以参考Demo示例,见GD32F4xx\_Firmware\_Library\_V3.0.2\GD32F4xx\_Firmware\_Library\Examples\USART\Printf

这是将串口通过printf实现打印功能。

static void Uart_Init(void)
{
    /* USART interrupt configuration */
    nvic_irq_enable(USART0_IRQn, 0, 0);
    
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOB);

    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART0);

    /* configure the USART0 TX pin and USART0 RX pin */
    gpio_af_set(GPIOB, GPIO_AF_7, GPIO_PIN_6);
    gpio_af_set(GPIOB, GPIO_AF_7, GPIO_PIN_7);

    /* configure USART0 TX as alternate function push-pull */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);

    /* configure USART0 RX as alternate function push-pull */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);

    /* USART configure */
    usart_deinit(USART0);
    usart_baudrate_set(USART0, 115200U);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_enable(USART0);
}

fgetc函数实现

官方给的Demo示例中已经支持了printf重定向,其实也就是实现了fputc函数。
MDK也支持scanf的重定向,也就是需要实现fgetc函数,本文实现了fgetc函数,如下。
因为不需要支持文件系统,所以fgetc实现很简单,直接判断时候有串口数据,如果有数据则接收返回接收的数据。

int fgetc(FILE *stream) 
{
    while(RESET == usart_flag_get(USART0, USART_FLAG_RBNE))
    {}

    return usart_data_receive(USART0);
}

fputc函数实现

不做赘述,官方例程中已经实现.
实现该函数用于支持printf

int fputc(int ch, FILE *f)
{
    usart_data_transmit(USART0, (uint8_t)ch);
    while(RESET == usart_flag_get(USART0, USART_FLAG_TBE))
    {}
    
    return ch;
}

LED初始化

static void Led_Init(void)
{
    /* enable the LEDs GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOC);
    /* configure LED2 GPIO port */
    gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    /* reset LED2 GPIO pin */
    gpio_bit_reset(GPIOC, GPIO_PIN_6);
}

功能逻辑实现

使用scanf接收来自上位机的字符串,如果字符串为open,则打开LED2;如果字符串为close,则关闭LED2,否则打印UnKnow command。

注意:上位机再发送字符串的时候,字符串结束必须要写一个空格,不然scanf会认为输入没有结束。

#include "gd32f4xx.h"
#include "gd32f427v_start.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>

int main(void)
{
    char c[10]; 
        
    /* configure systick */
    systick_config();
    
    /* configure the usart */
    Uart_Init();
    
    /* configure the led */
    Led_Init();
    
    printf("Startup\n\n");
    while(1)
    {
        scanf("%s", &c[0]);
        printf("Input command is %s \n", c);
        
        if (!strcmp(&c[0], "open"))
        {
            gpio_bit_set(GPIOC, GPIO_PIN_6);
            printf("turn on LED2 \n");
        }
        else if (!strcmp(&c[0], "close"))
        {
            gpio_bit_reset(GPIOC, GPIO_PIN_6);
            printf("turn off LED2 \n");            
        }
        else
        {
            printf("Unknown command \n");
        }
    }
}

实现结果

实现效果如下。
 title=

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