Bootstrap

【6】STM32·HAL库·串口

目录

一、数据通信的基础概念

1.1、串行/并行通信

1.2、单工/半双工/全双工通信

1.3、同步/异步通信

1.4、波特率

1.5、常见的串行通信接口

二、串口(RS-232)

2.1、什么是串口

2.2、RS-232电平与COMS/TTL电平对比

2.3、设备间的RS-232通信示意图

2.4、STM32串口与电脑USB口通信示意图

2.5、RS-232异步通信协议

三、STM32的USART

3.1、STM32的USART简介

3.2、STM32的USART主要特性

3.3、STM32F1/F4/F7的USART框图

3.4、设置USART波特率(F4)

3.5、USART寄存器介绍

四、HAL库外设初始化MSP回调机制

五、HAL库中断回调机制

六、USART/UART异步通信配置步骤

6.1、配置串口工作参数

6.2、串口底层初始化

6.3、开启串口异步接收中断

6.4、设置优先级、使能中断

6.5、编写中断服务函数

6.6、串口数据发送

七、IO引脚复用功能

7.1、通用与复用

7.2、STM32F4/F7/H7的IO引脚复用

八、编程实战

串口实验


一、数据通信的基础概念

1.1、串行/并行通信

按数据通信方式分类:串行通信、并行通信

串行通信

并行通信

1.2、单工/半双工/全双工通信

按数据传输方向分类:单工通信、半双工通信、全双工通信

单工通信                                 半双工通信                                 全双工通信

单工通信:数据只能沿一个方向传输

半双工通信:数据可以沿两个方向传输,但需要分时进行

全双工通信:数据可以同时进行双向传输

1.3、同步/异步通信

按数据同步方式分类:同步通信、异步通信

同步通信:共用同一时钟信号

异步通信:没有时钟信号,通过在数据信号中加入起始位和停止位等一些同步信号

1.4、波特率

1、比特率:每秒钟传送的比特数,单位 bit/s

2、波特率:每秒钟传送的码元数,单位 Baud

3、比特率 = 波特率 * log2 M,M 表示每个码元承载的信息量

二进制系统中,码元承载的信息量为二,波特率数值上等于比特率

1.5、常见的串行通信接口

二、串口(RS-232)

2.1、什么是串口

串行通信接口:指按位发送和接收的接口。如:RS-232/422/485 等

RS-232接口(DB9)

数据:

TXD(pin 3):串口数据输出

RXD(pin 2):串口数据输入

握手:

RTS(pin 7):请求发送

CTS(pin 8):清除发送

DSR(pin 6):数据发送就绪

DCD(pin 1):数据载波检测

DTR(pin 4):数据终端就绪

地线:

GND(pin 5):信号地

其他:

RI(pin 9):振铃指示

2.2、RS-232电平与COMS/TTL电平对比

逻辑1逻辑0
RS-232电平-15V ~ -3V+3V ~ +15V
COMS电平(3.3V)3.3V0V
TTL电平(5V)5V0V

结论:COMS/TTL 电平不能与 RS-232 电平直接交换信息

2.3、设备间的RS-232通信示意图

特别注意:两个设备之间的 TXD 和 RXD,必须交差连接,方可正常通信

2.4、STM32串口与电脑USB口通信示意图

特别注意:两个设备之间的 TXD 和 RXD,必须交差连接,方可正常通信

2.5、RS-232异步通信协议

启动位:必须占 1 个位长,保持逻辑 0 电平

有效数据位:可选 5、6、7、8、9 个位长,LSB(最低有效位)在前,MSB(最高有效位)在后

校验位:可选占 1 个位长,也可以没有该位

停止位:必须有,可选占 0.5、1、1.5、2 个位长,保持逻辑 1 电平

三、STM32的USART

3.1、STM32的USART简介

USART(Universal synchronous asynchronous receiver transmitter),通用同步异步收发器

UART(Universal asynchronous receiver transmitter),通用异步收发器

USART/UART 都可以与外部设备进行全双工异步通信

USART,我们常用的也是异步通信

3.2、STM32的USART主要特性

1,全双工异步通信

2,单线半双工通信

3,单独的发送器和接收器使能位

4,可配置使用 DMA 的多缓冲器通信

5,多个带标志的中断源

3.3、STM32F1/F4/F7的USART框图

STM32F407xx 数据手册 USART 框图

USART 框图简化版

3.4、设置USART波特率(F4)

波特率计算公式:band=\frac{f_{CK}}{8*\left ( 2 - OVER8 \right )*USARTDIV},其中 f_{CK} 是串口的时钟

对于 F4,我们把 USART_CR1 寄存器的位 15 设置为 0,即使用 16 倍过采样

3.5、USART寄存器介绍

1、控制寄存器1(CR1)

该寄存器需要完成的配置

位13:使能USART

位12:配置8个数据位

位10:禁止检验控制

位5:使能接收缓冲区非空中断

位3:使能发送

位2:使能接收

2、控制寄存器2(CR2)

该寄存器需要完成的配置

位13:12:配置1个停止位

3、控制寄存器3(CR3)

该寄存器需要完成的配置

位3:配置不选择半双工模式

4、数据寄存器(DR)

设置好控制和波特率寄存器后,往该寄存器写入数据即可发送,接收数据则读该寄存器

5、状态寄存器(SR)

根据 TC 位可以知道能否发数据,根据 RXNE 位知道是否收到数据

四、HAL库外设初始化MSP回调机制

以 USART 为例

五、HAL库中断回调机制

以 USART 为例

六、USART/UART异步通信配置步骤

6.1、配置串口工作参数

HAL库驱动函数:HAL_UART_Init()

/**
  * @brief  Initializes the UART mode according to the specified parameters in
  *         the UART_InitTypeDef and create the associated handle.
  * @param  huart  Pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);

关键结构体

typedef struct 
{    uint32_t BaudRate; 		/* 波特率 */ 
     uint32_t WordLength; 	    /* 字长 */
     uint32_t StopBits; 		/* 停止位 */ 
     uint32_t Parity; 			/* 奇偶校验位 */ 
     uint32_t Mode; 			/* UART 模式 */ 
     uint32_t HwFlowCtl; 		/* 硬件流设置 */ 
     uint32_t OverSampling; 	/* 过采样设置 */ 
}UART_InitTypeDef

6.2、串口底层初始化

HAL库驱动函数:HAL_UART_MspInit()

/**
  * @brief  UART MSP Init.
  * @param  huart  Pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval None
  */
__weak void HAL_UART_MspInit(UART_HandleTypeDef *huart);

用于配置 GPIO、NVIC、CLOCK 等

6.3、开启串口异步接收中断

HAL库驱动函数:HAL_UART_Receive_IT()

/**
  * @brief  Receives an amount of data in non blocking mode.
  * @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
  *         the received data is handled as a set of u16. In this case, Size must indicate the number
  *         of u16 available through pData.
  * @param  huart Pointer to a UART_HandleTypeDef structure that contains
  *               the configuration information for the specified UART module.
  * @param  pData Pointer to data buffer (u8 or u16 data elements).
  * @param  Size  Amount of data elements (u8 or u16) to be received.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

作用:以中断的方式接收指定字节的数据

形参 1:是 UART_HandleTypeDef 结构体类型指针变量

形参 2:是指向接收数据缓冲区

形参 3:是要接收的数据大小,以字节为单位

6.4、设置优先级、使能中断

HAL库驱动函数:设置优先级 HAL_NVIC_SetPriority()、使能中断 HAL_NVIC_EnableIRQ()

HAL_NVIC_SetPriority()

/**
  * @brief  Sets the priority of an interrupt.
  * @param  IRQn External interrupt number.
  *         This parameter can be an enumerator of IRQn_Type enumeration
  *         (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f4xxxx.h))
  * @param  PreemptPriority The preemption priority for the IRQn channel.
  *         This parameter can be a value between 0 and 15
  *         A lower priority value indicates a higher priority 
  * @param  SubPriority the subpriority level for the IRQ channel.
  *         This parameter can be a value between 0 and 15
  *         A lower priority value indicates a higher priority.          
  * @retval None
  */
void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority);

HAL_NVIC_EnableIRQ()

/**
  * @brief  Enables a device specific interrupt in the NVIC interrupt controller.
  * @note   To configure interrupts priority correctly, the NVIC_PriorityGroupConfig()
  *         function should be called before. 
  * @param  IRQn External interrupt number.
  *         This parameter can be an enumerator of IRQn_Type enumeration
  *         (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f4xxxx.h))
  * @retval None
  */
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);

这两个函数在【5】STM32·HAL库·中断 中有详细讲解

6.5、编写中断服务函数

编写 USARTx_IRQHandler()UARTx_IRQHandler() 函数处理接收到的数据

在中断向量表中有定义

                DCD     USART1_IRQHandler                 ; USART1                                          
                DCD     USART2_IRQHandler                 ; USART2                                          
                DCD     USART3_IRQHandler                 ; USART3                               
                DCD     UART4_IRQHandler                  ; UART4                                           
                DCD     UART5_IRQHandler                  ; UART5                              
                DCD     USART6_IRQHandler                 ; USART6                                                                 

6.6、串口数据发送

HAL库驱动函数:HAL_UART_Transmit()

/**
  * @brief  Sends an amount of data in blocking mode.
  * @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
  *         the sent data is handled as a set of u16. In this case, Size must indicate the number
  *         of u16 provided through pData.
  * @param  huart Pointer to a UART_HandleTypeDef structure that contains
  *               the configuration information for the specified UART module.
  * @param  pData Pointer to data buffer (u8 or u16 data elements).
  * @param  Size  Amount of data elements (u8 or u16) to be sent
  * @param  Timeout Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

作用:以阻塞的方式发送指定字节的数据

形参 1 :UART_HandleTypeDef 结构体类型指针变量

形参 2:指向要发送的数据地址

形参 3:要发送的数据大小,以字节为单位

形参 4:设置的超时时间,以ms单位

七、IO引脚复用功能

7.1、通用与复用

通用:IO 端口的输入或输出是由 GPIO 外设控制

复用:IO 端口的输入或输出是由其它非 GPIO 外设控制

7.2、STM32F4/F7/H7的IO引脚复用

为了解决 F1 系列存在的 IO 复用功能冲突问题,F4 往后的系列都加入了复用器

复用器特点

1、每个 IO 引脚都有一个复用器

2、复用器采用 16 路复用功能输入(AF0 到 AF15)

3、复用器一次仅允许一个外设的复用功能 (AF) 连接到 IO 引脚

4、通过GPIOx_AFRL和GPIOx_AFRH寄存器进行配置

温馨提示:复位完成后,所有 IO 都会连接到系统的复用功能 0 (AF0)

IO 引脚复用映射示意图

GPIO 复用功能低位寄存器(AFRL)

GPIO 复用功能高位寄存器(AFRH)

八、编程实战

串口实验

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"

int main(void)
{
    uint8_t len;
    uint16_t times = 0;
    
    HAL_Init();                             /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7);     /* 设置时钟,168Mhz */
    delay_init(168);                        /* 延时初始化 */
    usart_init(115200);                     /* 串口初始化为115200 */
    led_init();                             /* 初始化LED */

    while(1)
    {
       if (g_usart_rx_sta & 0x8000)         /* 接收到了数据? */
        {
            len = g_usart_rx_sta & 0x3fff;  /* 得到此次接收到的数据长度 */
            printf("\r\n您发送的消息为:\r\n");

            HAL_UART_Transmit(&g_uart1_handle,(uint8_t*)g_usart_rx_buf,len,1000);    /* 发送接收到的数据 */
            while(__HAL_UART_GET_FLAG(&g_uart1_handle,UART_FLAG_TC)!=SET);           /* 等待发送结束 */
            printf("\r\n\r\n");             /* 插入换行 */
            g_usart_rx_sta = 0;
        }
        else
        {
            times++;

            if (times % 5000 == 0)
            {
                printf("\r\n正点原子 STM32开发板 串口实验\r\n");
                printf("正点原子@ALIENTEK\r\n\r\n\r\n");
            }

            if (times % 200 == 0) printf("请输入数据,以回车键结束\r\n");

            if (times % 30  == 0) LED0_TOGGLE(); /* 闪烁LED,提示系统正在运行. */

            delay_ms(10);
        }
    }
}

usart 文件使用【1】STM32·HAL库·新建工程模板【一步到位】中导入的即可

如果是使用 VScode 出现串口输出以下乱码,需要修改编码方式为 GB2312 重新保存

;