STM32高端MCU(F4、F7等)才支持DMA双缓冲,低端MCU(F1)不支持DMA双缓冲,不过有替代方案可实现类型效果。

一、MCU支持DMA双缓冲的情形

不再赘述,参见博客 STM32 串口DMA发送+DMA接收+硬件双缓冲区切换功能实现

二、MCU不支持DMA双缓冲,但可通过DMA传输半完成中断替代,以下代码已在F103上验证通过。

1.先通过STM32CubeMX生成串口初始化代码

串口接收DMA一定要选择Circular模式,并且使能串口接收中断

2.使能空闲中断,空闲中断中取出接收数据

3.在DAM接收半完成、完成中断中取出接收数据

usart.c:

/* Includes ------------------------------------------------------------------*/
#include "usart.h"/* USER CODE BEGIN 0 */#define DE_UART_DMA_BUF_LEN    0x1E
static uint8_t RecvDMABuf[DE_UART_DMA_BUF_LEN];/* USER CODE END 0 */UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_tx;
DMA_HandleTypeDef hdma_usart1_rx;/* USART1 init function */void MX_USART1_UART_Init(void)
{huart1.Instance = USART1;huart1.Init.BaudRate = 115200;huart1.Init.WordLength = UART_WORDLENGTH_8B;huart1.Init.StopBits = UART_STOPBITS_1;huart1.Init.Parity = UART_PARITY_NONE;huart1.Init.Mode = UART_MODE_TX_RX;huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart1.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart1) != HAL_OK){Error_Handler();}}void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(uartHandle->Instance==USART1){/* USER CODE BEGIN USART1_MspInit 0 *//* USER CODE END USART1_MspInit 0 *//* USART1 clock enable */__HAL_RCC_USART1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**USART1 GPIO ConfigurationPA9     ------> USART1_TXPA10     ------> USART1_RX*/GPIO_InitStruct.Pin = GPIO_PIN_9;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_10;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USART1 DMA Init *//* USART1_TX Init */hdma_usart1_tx.Instance = DMA1_Channel4;hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_usart1_tx.Init.Mode = DMA_NORMAL;hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK){Error_Handler();}__HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);/* USART1_RX Init */hdma_usart1_rx.Instance = DMA1_Channel5;hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK){Error_Handler();}__HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);/* USART1 interrupt Init */HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);HAL_NVIC_EnableIRQ(USART1_IRQn);/* USER CODE BEGIN USART1_MspInit 1 *//*Enable the IDLE Interrupt*/__HAL_UART_ENABLE_IT(uartHandle,UART_IT_IDLE);__HAL_UART_CLEAR_IDLEFLAG(uartHandle);/* USER CODE END USART1_MspInit 1 */}
}void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{if(uartHandle->Instance==USART1){/* USER CODE BEGIN USART1_MspDeInit 0 *//* USER CODE END USART1_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_USART1_CLK_DISABLE();/**USART1 GPIO ConfigurationPA9     ------> USART1_TXPA10     ------> USART1_RX*/HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);/* USART1 DMA DeInit */HAL_DMA_DeInit(uartHandle->hdmatx);HAL_DMA_DeInit(uartHandle->hdmarx);/* USART1 interrupt Deinit */HAL_NVIC_DisableIRQ(USART1_IRQn);/* USER CODE BEGIN USART1_MspDeInit 1 *//* USER CODE END USART1_MspDeInit 1 */}
}/* USER CODE BEGIN 1 *//** This function is called on DMA TC or HT events, and on UART IDLE (if enabled) event.*/
void  UsartProcessData(const void* data, size_t len)
{uint8_t* pData = (uint8_t*)data;
//    DebugPrintf("RecvLen:%d\n",len);
//    DebugHexPrint(pData,len);
}void  UsartRxCheck(UART_HandleTypeDef *huart)
{static uint16_t OldPos = 0;/* Calculate current position in buffer and check for new data available */uint16_t NewPos = DE_UART_DMA_BUF_LEN - __HAL_DMA_GET_COUNTER(huart->hdmarx);if (NewPos != OldPos)     /* Check change in received data */{                       if (NewPos > OldPos)  /* Current position is over previous one */{                    /** Processing is done in "linear" mode.** Application processing is fast with single data block,* length is simply calculated by subtracting pointers*/UsartProcessData(&RecvDMABuf[OldPos], NewPos - OldPos);}else{/** Processing is done in "overflow" mode..** Application must process data twice,* since there are 2 linear memory blocks to handle*/UsartProcessData(&RecvDMABuf[OldPos], DE_UART_DMA_BUF_LEN - OldPos);if (NewPos > 0) {UsartProcessData(&RecvDMABuf[0], NewPos);}}OldPos = NewPos;   /* Save current position as old for next transfers */}
}/*** @brief  Rx Half Transfer completed callbacks.* @param  huart  Pointer to a UART_HandleTypeDef structure that contains*                the configuration information for the specified UART module.* @retval None*/
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == huart1.Instance){//DebugPrintf("HAL_UART_RxHalfCpltCallback\n");UsartRxCheck(huart);}
}/*** @brief  Rx Transfer completed callbacks.* @param  huart  Pointer to a UART_HandleTypeDef structure that contains*                the configuration information for the specified UART module.* @retval None*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == huart1.Instance){//DebugPrintf("HAL_UART_RxCpltCallback\n");UsartRxCheck(huart);}
}/*** @brief  Rx IDLE callback* @param  huart: UART handle. * @note   This example shows a simple way to report end of DMA Tx transfer, and *         you can add your own implementation. * @retval None*/
static void UART_RxIdleCallBack(UART_HandleTypeDef *huart)
{if(huart->Instance == huart1.Instance){//DebugPrintf("UART_IDLE_CallBack\n");UsartRxCheck(huart);}
}/*** @brief  UART_IDLE_IRQHandler* @param  huart  Pointer to a UART_HandleTypeDef structure that contains*                the configuration information for the specified UART module.* @retval HAL status*/
void UART_IDLE_IRQHandler(UART_HandleTypeDef *huart)
{if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET){__HAL_UART_CLEAR_IDLEFLAG(huart);__HAL_UART_FLUSH_DRREGISTER(huart);UART_RxIdleCallBack(huart);}
}void UART_StartReceive(void)
{HAL_UART_Receive_DMA(&huart1,RecvDMABuf,sizeof(RecvDMABuf));
}/* USER CODE BEGIN 1 *//* USER CODE END 1 */

1、此时DMA缓冲区类似一个循环buffer,接收满后自动从头部接收。
2、在DMA接收半完成中断和DMA接收完成中断之后的空闲中断中不能重复取接收数据。
3、该方法也适用于F4、F7等高端MCU。

STM32串口DMA接收双缓冲相关推荐

  1. STM32 串口DMA接收 Openmv / K210 整数、小数字符串数据 (基于HAL库)

    目录 前言 一.工程配置 二.串口DMA部分代码 1.源文件UART_DMA.c 2.头文件UART_DMA.h 3.stm32f1xx_it.c的修改 4.串口收发DMA测试 三.字符串数字提取代码 ...

  2. STM32 USART串口DMA 接收和发送的源码详解!

    硬件平台:STM32F103ZET6: 开发环境:KEIL 4: 先说说应用通讯模式,串口终端的工作方式和迪文屏差不多,终端被动接受MCU发的指令,终端会偶尔主动发送一些数据给MCU(像迪文屏的触摸信 ...

  3. STM32使用DMA接收串口数据

    目录 01.概述 02.DMA接收 03.中断 04.代码 01.概述 在之前的文章里<STM32串口详解>和<STM32 DMA详解>文章中,详细讲解了STM32的串口和DM ...

  4. FPGA 串口中断_一个严谨的STM32串口DMA发送amp;接收(1.5Mbps波特率)机制

    昨天分享的<嵌入式大杂烩读者福利:第一期>大家有去抽奖吗,没抽的可参与抽奖,碰碰运气.我最喜欢抽奖了,还记得前几个月疫情严重时期连抽中了3包口罩,真刺激,哈哈.之后多多安排抽奖,敬请期待. ...

  5. 一个严谨的STM32串口DMA发送接收(1.5Mbps波特率)机制

    文章目录 1 前言 2 串口有必要使用DMA吗 3 实现方式 4 STM32串口使用DMA 5 串口DMA接收 5.1 基本流程 5.2 相关配置 5.3 接收处理 5.3 .1 接收数据大小 5.3 ...

  6. STM32 HAL库 串口DMA接收不定长数据

    STM32 HAL库 串口DMA接收不定长数据 整体思路:我是用的CUBEMX软件生成的工程,使能了两个串口,串口2用来接收不定长的数据,串口1用来发送串口2接收到的数据:串口2我找了一个UBLOX卫 ...

  7. android 串口一直打开_STM32之串口DMA接收不定长数据

    STM32之串口DMA接收不定长数据 引言 在使用stm32或者其他单片机的时候,会经常使用到串口通讯,那么如何有效地接收数据呢?假如这段数据是不定长的有如何高效接收呢? 同学A:数据来了就会进入串口 ...

  8. STM32 串口DMA收发(二)

    STM32 串口DMA收发数据 一.STM32 DMA简介与功能说明 1.STM32F4 DMA简介 DMA(Direct memory access),即直接存储器访问.用于在外设与存储器之间以及存 ...

  9. 【32单片机学习】(6)STM32串口+DMA收发不定长数据

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 1.DMA介绍 2.串口接收数据 3.实验现象 1.实验电路图 2.串口收发不定长数据视频演示 3.OLED 显示接收数据 ...

最新文章

  1. jvm性能调优 - 08什么情况下对象会被GC
  2. dubbo源码分析二:服务发布
  3. web.xml文件报红,怎么解决???
  4. html上拉下拉查看文字内容,html5上拉下拉事件效果演示
  5. 利用cookies实现对弹出窗口频率的控制
  6. Swift Basic 3
  7. PTA-1015——Reversible Primes
  8. python统计图的三层结构设计_中大型LABVIEW软件三层设计架构(带图片目录完整版)...
  9. php网页缩略图api,美图WEB开放平台 - 开发文档
  10. java 营业执照验证_基于Java的营业执照识别示例代码-六派数据
  11. forEach空指针异常问题
  12. 用esp8266驱动0.96寸OLED屏幕 太空人动画
  13. ILI9341的使用之【四】RGB接口操作详解
  14. UnhandledPromiseRejectionWarning: MongoError: command insert requir es authentication
  15. GSM Communication on EBox4300--(1)
  16. 纯前端实行—简单的用户信息记录界面
  17. Python有哪些就业方向?
  18. 数字化转型大咖群研讨实录20210506
  19. Linux中下载 java 8 安装包 直接看图 简单易操作
  20. 上海无印良品地理空间分布特征与选址策略可视化研究

热门文章

  1. 一种可以使身体感受生死法则的电脑
  2. -bash: insmod: command not found
  3. 开放原子教育高校师资培训(OpenHarmony物联网理论+实践)成功举办
  4. java调用kotlin的内联函数_Kotlin内联函数
  5. EF框架-SQL语句 查询与修改
  6. 线性回归(Linear Regression)
  7. P4365 [九省联考2018]秘密袭击coat
  8. c语言中的find用法,find用法
  9. STM32管脚模拟协议驱动双路16位DAC芯片TM8211
  10. 被一位行业大佬骗了,很崩溃......