UART_HelloWorld工程实现的功能是,通过UART串口向上位机发送“HelloWorld”字符串,并且捕捉上位机的通信终端发出的字符(串)后回发给上位机,显示在上位机的串口终端界面。为了满足这些需求,需要考虑到几个设计要点: (1)应用UART串口驱动调用底层硬件实现UART串口接口的收发功能。 (2)为了利用printf/scanf等stdio标准库中的算法处理UART串口通信的数据流,主要是使用其中的格式化字符串处理功能,需要将操作底层硬件的UART串口驱动程序同stdio功能函数对接。 (3)使用上位机串口终端软件建立上位机到开发板之间的UART串行通信连接。
对UART_HelloWorld工程的功能进行简单分析后,开始编程。
步骤一:创建工程 在项目代码树的“\example”目录下,复制之前创建的模板工程目录“00_Template”,改名为“UART_HelloWorld”。
步骤二:添加应用代码 为了简化文件结构,绝大多数的程序代码将被存放在包含了main函数的main.c文件中,但是考虑到本样例工程的串口输入输出功能将在后续的工程中多次使用,因此特别将串口输入输出功能的代码存放在多工程共享的bsp_config.h/.c文件中,被存放在“\board”目录下。 创建bsp_config.h文件并添加代码如下: - /* bsp_config.h */
- #ifndef __BSP_CONFIG_H__
- #define __BSP_CONFIG_H__
- #include <stdint.h>
- #include <stdio.h>
- #include <stdbool.h>
- #include "gd32f20x_conf.h"
- void BSP_InitStdioUART(uint32_t baudrate);
- #endif /* __BSP_CONFIG_H__ */
复制代码目前,在该文件中只是声明了初始化标准输入输出串口通道的函数BSP_InitStdioUART(),在后续开发中,所有同板子电路相关的、公共功能的配置函数的声明也均会存放在此处,对应代码实现也对应存放在bsp_config.c文件中。
创建bsp_config.c文件并添加程序代码如下: - /* bsp_config.c */
- #include "bsp_config.h"
- void BSP_InitStdioUART(uint32_t baudrate)
- {
- /* Configure the GPIO ports */
- GPIO_InitPara GPIO_InitStructure;
- USART_InitPara USART_InitStructure;
- /* Enable GPIOA clock */
- RCC_APB2PeriphClock_Enable( RCC_APB2PERIPH_GPIOB, ENABLE );
- /* Enable USART1 APB clock */
- RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_USART1, ENABLE );
- RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_AF, ENABLE);
- GPIO_InitStructure.GPIO_Pin = GPIO_PIN_6 ;
- GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
- GPIO_Init( GPIOB , &GPIO_InitStructure);
- GPIO_InitStructure.GPIO_Pin = GPIO_PIN_7;
- GPIO_InitStructure.GPIO_Mode = GPIO_MODE_IN_FLOATING;;
- GPIO_Init( GPIOB , &GPIO_InitStructure);
- GPIO_PinRemapConfig(GPIO_REMAP_USART1, ENABLE);
-
- USART_InitStructure.USART_BRR = baudrate;
- USART_InitStructure.USART_WL = USART_WL_8B;
- USART_InitStructure.USART_STBits = USART_STBITS_1;
- USART_InitStructure.USART_Parity = USART_PARITY_RESET;
- USART_InitStructure.USART_HardwareFlowControl = USART_HARDWAREFLOWCONTROL_NONE;
- USART_InitStructure.USART_RxorTx = USART_RXORTX_RX | USART_RXORTX_TX;
- USART_Init(USART1, &USART_InitStructure);
- /* USART enable */
- USART_Enable(USART1, ENABLE);
- }
- int fputc(int c, FILE *f)
- {
- while (USART_GetBitState(USART1, USART_FLAG_TBE) == RESET)
- {
- }
- USART_DataSend(USART1, c);
- return c;
- }
- int fgetc(FILE *f)
- {
- while (USART_GetBitState(USART1, USART_FLAG_RBNE) == RESET)
- {
- }
- return USART_DataReceive(USART1);
- }
- /* EOF. */
复制代码这里要特别注意fputc()和fgetc()函数的实现,这两个函数就是标准输入输出库函数同底层硬件对接的适配函数,在此处的实现是将stdio的通信通道绑定在USART1串口的收发引擎上,之后在程序中使用printf、scanf、putchar、getchar等标准输入输出函数时,实际上就是通过UART1的串口在底层完成数据收发的。同时,为了将stdio的库包含到工程中,需要在Keil工程中选择使用“MicroLib”,这是一个特别为嵌入式应用实现的一个简装版的stdio库。具体操作见图1。
图1
步骤三:编写main函数 在main函数中,将调用初始化标准输入输出通信信道的函数,然后调用stdio的函数实现用户交互。在工程的main.c文件中编写应用程序的代码如下: - /* main.c */
- #include "app_inc.h"
- int main(void)
- {
- char ch;
- BSP_InitStdioUART(115200U);
- printf("Hello, World ...\r\n");
-
- while (1)
- {
- ch = getchar();
- putchar(ch);
- }
- }
- /* EOF. */
复制代码啊哈,程序好简单,只要初始化了stdio,就可以像编写上位机运行的C程序一样自由调用printf、getchar和putchar。
步骤四:在上位机启动串口通信终端软件与开发板建立通信 在用过了各种各样的上位机串口调试类软件之后,我选择了专业并且免费的Tera Term软件作为的的上位机串口调试工具。 将开发板的串口同上位机对接之后,启动Tera Term软件并打开串口,Tera Term会自动识别当前的可用串口端口,这个实用的小功能是我选择Tera Term的主要原因之一。如图2所示。
图2
建立连接之后,在Keil中编译工程,下载,然后复位开发板,运行程序,就可以在Tera Term的串口终端中看到开发通过printf打印出的“Hello, World ...”了。此时,在串口终端中键入任何字符,都将被回显出来,正如我输入的“Hello, board”一样。如图3所示。
图3
Bingo!至此,大功告成。在第一个样例程序中,遵循学习程序语言的习惯,编写了一个通过串口打印到上位机串口终端的“HelloWorld”工程,建立了人机交互的基础。在后续的样例工程中,将会大量地使用stdio的标准输入输出函数作为基本的人机交互手段。
|