【STM32+HAL库+CubeMX】UART轮询收发、中断收发、DMA收发方法及空闲中断详解

您所在的位置:网站首页 安装cubemx 【STM32+HAL库+CubeMX】UART轮询收发、中断收发、DMA收发方法及空闲中断详解

【STM32+HAL库+CubeMX】UART轮询收发、中断收发、DMA收发方法及空闲中断详解

2023-07-06 14:46| 来源: 网络整理| 查看: 265

Author: DrinkCat([email protected]) Copyright © 2023 DrinkCat Original link: DrinkCat’s Blog

1. 什么是UART?

UART是一种异步串行通信接口,常用于通过串口与外部设备进行通信。它通过发送和接收数据帧来实现数据传输,使用起来相对简单。UART通常包含发送器(Transmitter)和接收器(Receiver),通过两根信号线(传输线)进行双向通信。

2. UART协议内容简介

image

UART协议将一长串数据切成很多固定长度的小段,分别发送。每小段数据前后会加上一些附加数据以保证通信的实时性和准确性,最后形成的每个小段叫做一个数据包——即1帧数据。

起始位:发出1位低电平信号,表示开始传输字符。数据位:真正发送的数据,一般为8位(1个字节),常采用ASCII编码,从最低位开始发送。校验位:用于检验接收到的数据是否正确,分为奇校验和偶校验。停止位:一组数据的结束传输的标志。可以是1位、1.5位、2位的高电平。空闲位:空闲时数据线为高电平状态,代表无数据传输。波特率:衡量传输速率的指标。UART通信中波特率等于比特率。

UART通信的两个设备间,以上因素必须完全一致才能实现数据通信。

3. UART轮询收发

UART轮询收发时,CPU会不断检测串口的状态位来判断数据收发的情况。

3.1 UART轮询收发的优缺点

UART轮询收发是一种简单直接的UART通信方式,它具有以下优点和缺点:

优点

简单易实现:相比于中断或DMA方式进行数据收发,UART轮询收发的实现相对简单,不需要额外配置中断或DMA控制器,减少了开发的复杂性。低延迟:由于没有中断处理程序的介入和数据传输的等待时间,UART轮询收发可以实现较低的延迟,对实时性要求较高的应用场景较为适用。占用CPU资源,效能低:UART轮询收发需要通过不断的轮询来检查发送和接收缓冲区的状态,这会占用CPU的资源,导致CPU无法充分利用来执行其他任务。

缺点

占用CPU资源,效能低:UART轮询收发需要通过不断的轮询来检查发送和接收缓冲区的状态,这会占用CPU的资源,导致CPU无法充分利用来执行其他任务。

UART轮询收发适用于简单的、对实时性要求不高的低速通信场景。但在对实时性、效率和灵活性要求较高的应用中,中断或DMA方式可能更加适合。在选择UART通信方式时,需要根据具体应用需求进行权衡和选择。

3.2 UART轮询收发相关的函数

初始化UART参数:首先,需要对UART进行初始化,包括波特率(Baud rate)、数据位数、校验位、停止位等参数的设置。这些参数决定了数据的传输格式。

初始化函数HAL_UART_Init(UART_HandleTypeDef *huart);功能根据串口句柄指定的参数进行串口初始化。入口参数huart:串口句柄的地址指针。返回值HAL状态值。说明使用CubeMX配置工程时,初始化代码会自动生成,我们不需要再对串口进行初始化。

发送数据:要发送数据,首先将待发送的数据写入UART发送缓冲区,然后调用轮询发送函数。在轮询方式下,单片机会一直检查是否完成发送,直到超过设定时间或数据发送完成。

轮询发送函数HAL_UART_Transmit(UART_Handle TypeDef *huart, uint 8_t *pData, uint 16_t Size, uint 32_t Timeout);功能在轮询方式下发送一定数量的数据。入口参数huart:串口句柄的地址。pData:待发送数据的首地址。Size:发送的字节数。Timeout:超时等待时间, 以毫秒为单位。返回值HAL状态值。

接收数据:要接收数据,需要从UART接收缓冲区读取数据。同样,在轮询方式下,单片机会一直检查是否完成接收,直到超过设定时间或接收到所有数据。

轮询接收函数HAL_UART_Receive(UART_Handle TypeDef *huart, uint 8_t *pData, uint 16_t Size, uint 32_t Timeout);功能在轮询方式下接收一定数量的数据。入口参数huart:串口句柄的地址。pData:存放数据的首地址。Size:接收数据的字节数。Timeout:超时等待时间, 以毫秒为单位。返回值HAL状态值。 3.3 【实践】使用蓝牙模块发送数据

使用UART协议,向手机循环发送“Hello World”语句。

3.3.1 配置UART

image

左侧connectivity中点击USART1。右侧Mode,选择为Asynchronous(异步通信)配置参数: Baud Rate(波特率):9600Bits/sWord Length(字长):8 BitsParity(奇偶校验位):无校验位Stop Bits(停止位):1位

USART包括UART与USRT。我们使用USART的UART模式,即Asynchronous。

3.3.2 连接单片机与蓝牙模块 单片机蓝牙模块RXTXTXRX5VVCCGNDGND 3.3.3 代码实现

在main.c中添加如下语句:

/* 添加至引用区 */ #include "string.h" // strlen函数依赖该头文件 /* 添加至变量定义区*/ char txBuffer[] = "Hello World"; // 需要发送的数据 /* 写在main()的while(1)循环内 */ while(1) { HAL_UART_Transmit(&huart1, (uint8_t *)txBuffer, strlen(txBuffer), 1000); HAL_Delay(1000); } 4. UART中断收发 4.1 UART中断收发的优缺点

优点

提高系统效率:相比于UART轮询收发方式,UART中断收发可以提高系统的效率。当每完成发送或接收一帧数据时,中断会通知CPU进行相应的处理,而不需要CPU不断地轮询发送或接收缓冲区,释放了CPU资源,使CPU可以同时执行其他任务;系统响应更快:通过使用中断机制,UART中断收发可以提供更快的系统响应时间。一旦有数据可发送或可接收时,中断立即触发,通知CPU进行相应操作,减少了数据传输的延迟。灵活性:UART中断收发具有较高的灵活性。中断处理程序可以对数据进行灵活的处理和控制,可以根据实际需求进行相应的操作,如解析数据、执行特定任务等。复杂性增加:相对于UART轮询收发方式,UART中断收发的实现相对复杂一些。需要正确配置中断触发条件和中断优先级,同时编写中断处理程序进行数据的发送和接收操作。

缺点

中断开销:中断处理程序的执行会占用一定的CPU时间和系统资源。频繁的中断触发可能会增加系统的开销。实时性限制:尽管UART中断收发可以提高系统的响应时间,但它仍然受限于中断处理程序的执行时间和优先级。在高实时性要求的应用中,中断处理程序的执行时间必须保持足够短,以确保数据的及时处理和传输。占用CPU资源:在传输数据量较大时,如果采用中断方式,每收发一帧的数据,CPU都会被打断,造成CPU无法处理其他事务。因此在批量数据传输,通信波特率较高时,建议采用DMA方式。

UART中断收发相较于UART轮询收发,提高了系统的效率,但是遇到大量、高速的数据传输时仍然会对CPU的性能产生影响。

4.2 UART中断收发时触发中断的流程

image

使能中断后,每收发1帧数据后,UART会触发UART全局中断。此时程序会进入到中断处理函数 USART1_IRQHandler()。在这个函数中,又调用了HAL库的中断处理函数HAL_UART_IRQHandler(&huart1),该函数会通过判断中断类型来决定调用哪个函数。

如果收发完成 -> 进入发送/接收回调函数; 如果产生错误 -> 进入错误回调函数; 如果未收发完 -> 继续发送/接收。

简而言之,每完成一帧数据的收发,都会调用一次中断处理函数,但只有当收发完成时才会调用发送/接收回调函数。在实际操作中,我们一般不需要对中断处理函数HAL_UART_IRQHandler()进行修改。我们将收发完成时的操作逻辑写在回调函数中即可。

4.3 UART中断收发相关的函数 4.3.1 发送相关函数 中断发送函数HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);功能在中断方式下发送一定数量的数据。入口参数huart:串口句柄的地址。pData:发送数据的首地址。Size:发送数据的字节数。返回值HAL状态值。 发送回调函数HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);功能本函数会在中断发送完成时被调用。入口参数huart:串口句柄的地址。返回值无 4.3.2 接收相关函数 中断接收函数HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);功能在中断方式下接收一定数量的数据。入口参数huart:串口句柄的地址。pData:存放数据的首地址。Size:接收数据的字节数。返回值HAL状态值。 接收回调函数HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);功能本函数会在中断接收完成时被调用。入口参数huart:串口句柄的地址。返回值无 4.4 回调函数的使用方式

在stm32f1xx_hal_uart.c文件中,我们可以找到回调函数的声明方式(下以接收回调函数为例)。

image

关注到函数声明前带有__weak修饰,我们一般将这种函数称之为“弱函数”。含有__weak标识的函数,我们可以自行声明一个同名函数,最终编译器在编译的时候会选择我们自己定义的函数。如果我们没有声明该函数,则会调用有__weak修饰的函数。因此,我们只需要在合适的位置自己声明一个回调函数即可,不必在该文件中进行修改。

4.5 【实践】使用中断方式收发数据

通过蓝牙向单片机发送三个英文字母,单片机将大小写翻转后发回。

4.5.1 配置UART

在上一节配置的基础上,我们打开UART1的全局中断。

image

4.5.2 代码实现

我们在main.c中添加如下代码

/* 添加至宏定义区 */ #define rxDataLen 3 //接收三个字节的数据 /* 添加至变量定义区*/ char rxBuffer[rxDataLen]; // 存储接收到的数据的数组 int main() { /* 添加至while(1)循环前*/ HAL_UART_Receive_IT(&huart1, (uint8_t *)rxBuffer, rxDataLen); // 中断方式接收三个字节数据 while(1) // 注意不要将中断接收写在while循环内 { HAL_Delay(1); } }

在完成一次接收后,我们需要将接收到的字母大小写翻转并输出。我们需要在接收回调函数中实现这一功能,定义接收回调函数如下。

// 接收回调函数(由于需要覆盖原先的弱函数,本函数名称不能更改) void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart == &huart1) // 如果是串口1 { for(int i = 0; i rxBuffer[i] += 'A' - 'a'; } else if(rxBuffer[i] >= 'A' && rxBuffer[i] __HAL_UART_CLEAR_IDLEFLAG(&huart1); // 清除空闲中断标志位 __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); // 开启UART的空闲中断 HAL_UART_Receive_DMA(&huart1, (uint8_t*)rxBuffer, rxBufferLen ); // 启动DMA接收 }

每当发生空闲中断或接收到的数据超过缓存区大小时,会产生一次中断。我们首先需要自行编写中断回调函数。

void UART_DMAIdleCallback(UART_HandleTypeDef *huart) { if(huart == &huart1) { // 停止DMA接收 __HAL_DMA_DISABLE(huart->hdmarx); // 计算接收到的数据长度 uint8_t dataLen = rxBufferLen - __HAL_DMA_GET_COUNTER(huart->hdmarx) + '0'; // 发送数据长度,使用轮询方法 HAL_UART_Transmit(&huart1, &dataLen, 1, 10); // 重启DMA接收 __HAL_DMA_SET_COUNTER(huart->hdmarx, rxBufferLen); // 重设DMA计数器 __HAL_DMA_ENABLE(huart->hdmarx); // 使能DMA接收 } }

我们在中断处理函数内添加如下内容(该函数位于文件stm32g4xx_it.c内)。

void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET) // 判断中断是否为空闲中断 { __HAL_UART_CLEAR_IDLEFLAG(&huart1); // 清除空闲中断标志位 UART_DMAIdleCallback(&huart1); // 空闲回调函数 } /* USER CODE END USART1_IRQn 1 */ }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3