笔记(STM32篇)day13——USART串口与PC通信实例

USART 常用来实现控制器与电脑之间的数据传输。这使得我们调试程序非常方便,比如我们可以把一些变量的值、函数的返回值、寄存器标志位等等通过 USART 发送到串口调试助手,这样我们可以非常清楚程序的运行状态,当我们正式发布程序时再把这些调试信息去除即可。

本实例要实现开发板与电脑通信,在开发板上电时通过 USART 发送一串字符串给电脑,然后开发板进入中断接收等待状态,如果电脑有发送数据过来,开发板就会产生中断,我们在中断服务函数接收数据,并马上把数据返回发送给电脑。

一、使能RX、TX引脚GPIO与USART时钟

bsp_usart的创建同前面外设一样,需要c文件和h文件,包含stm32f10x、防止重复定义的宏定义等。此外,需要对USART的RCC时钟、波特率、RXTX的引脚、GPIO的RCC时钟、USART中断进行一些宏定义,增加程序可读性的同时,提高可移植性。

此处注意USART的PA9、PA10对应RXTX,开了GPIOA的时钟后,记得还有USART1的时钟要开,USART和GPIO一样都是外设,用外设就要开外设的时钟,像前面用中断配置信号源就要用到AFIO,要开AFIO的时钟。

二、配置USART、优先级分组NVIC配置

  1. USART输入输出RX、TX配置

模式配置:输出TX因为要直接输出不经过寄存器,而是直接从片上外设输出,需要复用推挽输出;输入RX要读取因此用浮空输入;

引脚配置:USART1对应的是PA9、PA10;

配置好后调用GPIO的初始化函数即可。

    // 将USART Tx的GPIO配置为推挽复用模式
    GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  // 将USART Rx的GPIO配置为浮空输入模式
    GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure); 
  1. USART通信参数配置

波特率 115200,字长为 8,1 个停止位,没有校验位,不使用硬件流控制,收发一体工作模式,然后调用 USART 初始化函数完成配置。

    // 配置串口的工作参数
    // 配置波特率
    USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
    // 配置 针数据字长
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    // 配置停止位
    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_Rx | USART_Mode_Tx;
    // 完成串口的初始化配置
    USART_Init(DEBUG_USARTx, &USART_InitStructure);
  1. NVIC配置、串口接收中断使能以及串口使能

USART 接收中断,需要配置 NVIC,这里调用 NVIC_Configuration 函数完成配置。配置完 NVIC 之后调用 USART_ITConfig 函数使能 USART 接收中断。

最后调用 USART_Cmd 函数使能 USART,这个函数最终配置的是 USART_CR1 的 UE 位,具体的作用是开启 USART 的工作时钟,没有时钟那 USART 这个外设自然就工作不了

    // 串口中断优先级配置
    NVIC_Configuration();
    
    // 使能串口接收中断
    USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);    
    
    // 使能串口
    USART_Cmd(DEBUG_USARTx, ENABLE);      

三、字符发送

  1. 上电发送字符

在bsp_usart.c文件中,编写一个数据发送函数,Usart_SendByte 函数用来在指定 USART 发送一个 ASCLL 码值字符,它有两个形参,第一个为USART,第二个为待发送的字符。它是通过调用库函数 USART_SendData 来实现的,并且增加了等待发送完成功能。通过使用 USART_GetFlagStatus 函数来获取 USART 事件标志来实现发送完成功能等待,它接收两个参数,一个是 USART,一个是事件标志。这里我们循环检测发送数据寄存器为空这个标志,当跳出 while 循环时说明发送数据寄存器为空这个事实。

void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
3 {
4     /* 发送一个字节数据到 USART */
5     USART_SendData(pUSARTx,ch);
6
7     /* 等待发送数据寄存器为空 */
8     while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
9 }

发送字符功能函数完成后,在主程序中先调用USART配置函数进行初始化,后调用此字符发送函数即可完成功能。

nt main(void)
{    
    USART_Config();
    Usart_SendByte(DEBUG_USARTx , 100);
}
  1. 返回8位的数组

同样在bsp_usart.c中声明一个传数组函数,参数位USART结构体类型指针、数组名、数量,用for循环执行上面的发送字节函数。通过USARAT_FlagStatus函数获取状态寄存器SR的TC状态,若为0表明没传输完成,为1则结束等待。

注:单个字符发送使用SR的TXE判断发送是否完成,多字符发送用SR的TC判断是否完成发送。

void Usart_SendArray(USART_TypeDef* pUSARTx, uint8_t *array, uint8_t num)
{
    uint8_t i;
    for( i = 0; i < num; i++)
    {
        Usart_SendByte(pUSARTx, array[i]);
    }
    while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET );
}    
  1. 返回字符串

在c中,字符串是以char数组形式储存,当然返回字符串可以用上面返回数组的方式,这里用另一种do while循环实现。

void Usart_SendString(USART_TypeDef* pUSARTx, char *str)
{
    unsigned int k=0; 
    do
    {
        Usart_SendByte(pUSARTx, *(str + k));
        k++;
    }while(*(str + k) != '\0');

    /* 等待发送完成 */
    while (USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}
  1. printf函数重定向到串口

重定向:c语言中标准io函数都是使用标准io流(stdin,stdout,stderr)进行输入输出的,在默认情况下,stdin是读取键盘输入,stdout和stderr是输出到屏幕。一般来说,io设备被看做文件,所以这些io流实际上都是FILE*,也就是说,他们可以指向其他文件,这就是重定向的功能,可以将信息打印到串口。

因为printf函数内部就是调用的fputc,因此在bsp_usart.c中定义fputc,在fputc中使用上面

的USART_SendData函数将信息从串口发送,这样在主函数中直接printf("Hello")即可在串口打印内容。

int fputc(int ch, FILE *f)
{
        /* 发送一个字节数据到串口 */
        USART_SendData(DEBUG_USARTx, (uint8_t) ch);
        
        /* 等待发送完毕 */
        while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);        
    
        return (ch);  
}

参考

https://doc.embedfire.com/mcu/stm32/f103zhinanzhe/std/zh/latest/index.html

你可能感兴趣的:(STM32基础知识,stm32,单片机)