当前位置:   article > 正文

STM32之DMA_stm32 dma

stm32 dma

DMA介绍

DMA(Direct MemoryAccess,直接存储器访问)提供在外设与内存、存储器和存储器、外设与外设之间的高速数据传输使用。它允许不同速度的硬件装置来沟通,而不需要依赖于CPU,在这个时间中,CPU对于内存的工作来说就无法使用。

DMA的意义

  • 数据搬运的工作比较耗时间。

  • 数据搬运工作时效要求高(有数据来就要搬走) 。

  • 没啥技术含量(CPU节约出来的时间可以处理更重要的事)。

  • DMA是数据搬运工,代替CPU搬运数据,为CPU节省资源让CPU做其他操作。

DMA搬运的数据

  • 存储器:存储器包括自身的闪存(flash)或者内存(SRAM)以及外设的存储设备都可以作为访问的源或者目标。

  • 外设:外设指的是spi、usart、iic、adc 等基于APB1、APB2或AHB时钟的外设。

DMA搬运的地点

  • 存储器-->存储器(例如:复制某特别大的数据buf)

  • 存储-->外设(例:将某数据buf写入串口TDR寄存器)

  • 外设-->存储器(例如:将串口RDR寄存器写入某数据buf)

DMA通道

STM32F103C8T6有2个DMA控制器,DMA1有7个通道,DMA2有5个通道,一个通道每次只能搬运一个外设的数据,如果同时有多个外设的DMA请求,则按照通道优先级进行响应。

仲裁器

  • 仲裁器会通过DMA通道请求的优先级来启动对外设/内存的访问,也就是哪个通道的优先级最高,DMA就先响应哪个通道。

  • DMA通道优先级管理由软件优先级和硬件优先级组成:

  1. 软件优先级:每个通道的优先权可以在DMA_CCRx寄存器中设置,有4个等级:

  • 最高优先级(Very High)

  • 高优先级(High)

  • 中等优先级(Medium)

  • 低优先级(Low)

  1. 硬件优先级:如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优先权。

控制器

DMA1

DMA2

DMA处理

在发生一个DMA请求事件后,外设向DMA控制器发送一个请求信号。DMA控制器根据通道优先级处理请求。当DMA控制器开始访问发出DMA请求的外设时,DMA控制器立即发送给外设一个应答信号。当外设从DMA控制器得到应答信号时,立即释放它的DMA请求。一旦外设释放了这个请求,DMA控制器同时撤销应答信号。如果有更多的请求时,外设可以启动下一个周期。

DMA传输的三个操作

  1. 从外设数据寄存器或者从当前外设/存储器地址寄存器指示的存储器地址取数据,第一次传输时的开始地址是DMA_CPARx或DMA_CMARx寄存器指定的外设基地址或存储器单元。(从旧地点取数据)

  1. 存数据到外设数据寄存器或者当前外设/存储器地址寄存器指示的存储器地址,第一次传输时的开始地址是DMA_CPARx或DMA_CMARx寄存器指定的外设基地址或存储器单元。(到新地点存数据)

  1. 执行一次DMA_CNDTRx寄存器的递减操作,该寄存器包含未完成的操作数目。(操作数递减1次)

DMA传输的方式

正常模式(DMA Mode Normal)

  • 一次DMA数据传输完后,停止DMA传送,也就是只传输一次。

  • 要开始新的DMA传输,需要在关闭DMA通道的情况下,在DMA CNDTRx寄存器中重新写入传输数目。

循环传输模式(DMA Mode Circular)

  • 当传输结束时,硬件自动会将传输数据量寄存器进行重装,进行下一轮的数据传输。 也就是多次传输模式。

  • 主要用于处理循环缓冲区和连续的数据传输。

指针增量模式

外设和存储器指针在每次传输后可以自动向后递增或保持常量。当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值。

  • 源指针和目标指针都设置为增量模式

  • 源指针设置为增量模式

  • 一般设计存储器的都开启指针增量模式

DMA中断

每个DMA通道都有3个事件(DMA半传输、DMA传输完成和DMA传输错误),这3个事件都可以成为一个单独的中断请求。

中断事件

事件标志位

使能控制位

DMA半传输

HTIF

HTIE

DMA传输完成

TCIF

TCIE

DMA传输错误

TEIF

TEIE

DMA实验1(存储器 -> 存储器)

使用DMA的方式将数组A的内容复制到数组B中,搬运完之后将数组B的内容通过串口打印到屏幕,同时每隔0.5s翻转一次LED1的电平。

STM32的hal库关于DMA的函数

HAL_DMA_Start()

开启某个DMA通道的数据运输。

原型:HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)

参数:
DMA_HandleTypeDef *hdma:DMA通道句柄
uint32_t SrcAddress:源数据地址
DstAddress:目标数据地址
DataLength:数据长度

实例:
#define BUF_SIZE 16
uint32_t srcBuf[BUF_SIZE] = {
0x00000000,0x11111111,0x22222222,0x33333333,
0x44444444,0x55555555,0x66666666,0x77777777,
0x88888888,0x99999999,0xaaaaaaaa,0xbbbbbbbb,
0xcccccccc,0xdddddddd,0xeeeeeeee,0xffffffff
};
uint32_t desBuf[BUF_SIZE];

HAL_DMA_Start(&hdma_memtomem_dma1_channel1,(uint32_t)srcBuf,(uint32_t)desBuf,sizeof(uint32_t) * BUF_SIZE); //开启DMA1通道1的数据传输

__HAL_DMA_GET_FLAG

检测某个DMA通道的数据传输情况。

原型:__HAL_DMA_GET_FLAG(DMA_HandleTypeDef *hdma,__FLAG__)

参数:
DMA_HandleTypeDef *hdma:DMA通道句柄
__FLAG__:
DMA_FLAG_TCx:传输完成标志
DMA_FLAG_HTx:半传输完成标志
DMA_FLAG_TEx:传输错误标志
DMA_FLAG_GLx:全局中断标志

实例:__HAL_DMA_GET_FLAG(&hdma_memtomem_dma1_channel1,DMA_FLAG_TC1) //检测DMA1通道1的数据传输是否完成,完成返回RESET

使用STM32CubeMX创建工程

配置SYS

配置RCC

配置GPIO

PB8配置成输出高电平

配置串口信息(UART1)

配置DMA

使用DMA1的通道1,传输方向为内存到内存

配置工程名称、工程路径

选择固件库

生成工程

使用MicroLIB库

main.c文件编写

  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * Copyright (c) 2023 STMicroelectronics.
  10. * All rights reserved.
  11. *
  12. * This software is licensed under terms that can be found in the LICENSE file
  13. * in the root directory of this software component.
  14. * If no LICENSE file comes with this software, it is provided AS-IS.
  15. *
  16. ******************************************************************************
  17. */
  18. /* USER CODE END Header */
  19. /* Includes ------------------------------------------------------------------*/
  20. #include "main.h"
  21. #include "dma.h"
  22. #include "usart.h"
  23. #include "gpio.h"
  24. /* Private includes ----------------------------------------------------------*/
  25. /* USER CODE BEGIN Includes */
  26. #include <stdio.h>
  27. #define BUF_SIZE 16
  28. /* USER CODE END Includes */
  29. /* Private typedef -----------------------------------------------------------*/
  30. /* USER CODE BEGIN PTD */
  31. /* USER CODE END PTD */
  32. /* Private define ------------------------------------------------------------*/
  33. /* USER CODE BEGIN PD */
  34. /* USER CODE END PD */
  35. /* Private macro -------------------------------------------------------------*/
  36. /* USER CODE BEGIN PM */
  37. /* USER CODE END PM */
  38. /* Private variables ---------------------------------------------------------*/
  39. /* USER CODE BEGIN PV */
  40. /* USER CODE END PV */
  41. /* Private function prototypes -----------------------------------------------*/
  42. void SystemClock_Config(void);
  43. /* USER CODE BEGIN PFP */
  44. /* USER CODE END PFP */
  45. /* Private user code ---------------------------------------------------------*/
  46. /* USER CODE BEGIN 0 */
  47. //重写stdio.h文件中的prinft()里的fputc()函数
  48. int fputc(int my_data,FILE *p)
  49. {
  50. unsigned char temp = my_data;
  51. //改写后,使用printf()函数会将数据通过串口一发送出去
  52. HAL_UART_Transmit(&huart1,&temp,1,0xffff); //0xfffff为最大超时时间
  53. return my_data;
  54. }
  55. //源数组
  56. uint32_t srcBuf[BUF_SIZE] = {
  57. 0x00000000,0x11111111,0x22222222,0x33333333,
  58. 0x44444444,0x55555555,0x66666666,0x77777777,
  59. 0x88888888,0x99999999,0xaaaaaaaa,0xbbbbbbbb,
  60. 0xcccccccc,0xdddddddd,0xeeeeeeee,0xffffffff
  61. };
  62. //目标数组
  63. uint32_t desBuf[BUF_SIZE];
  64. /* USER CODE END 0 */
  65. /**
  66. * @brief The application entry point.
  67. * @retval int
  68. */
  69. int main(void)
  70. {
  71. /* USER CODE BEGIN 1 */
  72. int i = 0;
  73. /* USER CODE END 1 */
  74. /* MCU Configuration--------------------------------------------------------*/
  75. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  76. HAL_Init();
  77. /* USER CODE BEGIN Init */
  78. /* USER CODE END Init */
  79. /* Configure the system clock */
  80. SystemClock_Config();
  81. /* USER CODE BEGIN SysInit */
  82. /* USER CODE END SysInit */
  83. /* Initialize all configured peripherals */
  84. MX_GPIO_Init();
  85. MX_DMA_Init();
  86. MX_USART1_UART_Init();
  87. /* USER CODE BEGIN 2 */
  88. //①:开启DMA1通道1的数据传输
  89. HAL_DMA_Start(&hdma_memtomem_dma1_channel1,(uint32_t)srcBuf,(uint32_t)desBuf,sizeof(uint32_t) * BUF_SIZE); //DMA1通道1的数据开始传输
  90. //②:等待DMA1通道1数据传输完成
  91. while(__HAL_DMA_GET_FLAG(&hdma_memtomem_dma1_channel1,DMA_FLAG_TC1) == RESET); //等待某个通道的数据传输完成,flag标志位置位RESET
  92. //③:打印数组内容
  93. for(i = 0;i < BUF_SIZE;i++){
  94. printf("Buf[%d] = %X\r\n",i,desBuf[i]);
  95. }
  96. /* USER CODE END 2 */
  97. /* Infinite loop */
  98. /* USER CODE BEGIN WHILE */
  99. while (1)
  100. {
  101. /* USER CODE END WHILE */
  102. /* USER CODE BEGIN 3 */
  103. HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
  104. HAL_Delay(500);
  105. }
  106. /* USER CODE END 3 */
  107. }
  108. /**
  109. * @brief System Clock Configuration
  110. * @retval None
  111. */
  112. void SystemClock_Config(void)
  113. {
  114. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  115. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  116. /** Initializes the RCC Oscillators according to the specified parameters
  117. * in the RCC_OscInitTypeDef structure.
  118. */
  119. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  120. RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  121. RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  122. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  123. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  124. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  125. RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  126. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  127. {
  128. Error_Handler();
  129. }
  130. /** Initializes the CPU, AHB and APB buses clocks
  131. */
  132. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  133. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  134. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  135. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  136. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  137. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  138. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  139. {
  140. Error_Handler();
  141. }
  142. }
  143. /* USER CODE BEGIN 4 */
  144. /* USER CODE END 4 */
  145. /**
  146. * @brief This function is executed in case of error occurrence.
  147. * @retval None
  148. */
  149. void Error_Handler(void)
  150. {
  151. /* USER CODE BEGIN Error_Handler_Debug */
  152. /* User can add his own implementation to report the HAL error return state */
  153. __disable_irq();
  154. while (1)
  155. {
  156. }
  157. /* USER CODE END Error_Handler_Debug */
  158. }
  159. #ifdef USE_FULL_ASSERT
  160. /**
  161. * @brief Reports the name of the source file and the source line number
  162. * where the assert_param error has occurred.
  163. * @param file: pointer to the source file name
  164. * @param line: assert_param error line source number
  165. * @retval None
  166. */
  167. void assert_failed(uint8_t *file, uint32_t line)
  168. {
  169. /* USER CODE BEGIN 6 */
  170. /* User can add his own implementation to report the file name and line number,
  171. ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  172. /* USER CODE END 6 */
  173. }
  174. #endif /* USE_FULL_ASSERT */

DMA实验2(存储器 -> 外设:UART1)

使用DMA的方式将存储器的内容发送到串口1,同时每隔0.5s翻转一次LED1的电平。

STM32的hal库关于DMA的函数

HAL_UART_Transmit_DMA()

使用DMA将其他地方的数据搬运到串口。

原型:HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

参数:
UART_HandleTypeDef *huart:串口句柄
uint8_t *pData:传输数据地址
uint16_t Size:传输数据大小

实例:
#define BUF_SIZE 1000

unsigned char sendBuf[BUF_SIZE] = {0};

for(i = 0;i < BUF_SIZE;i++){
sendBuf[i] = 'h';
}

HAL_UART_Transmit_DMA(&huart1,sendBuf,BUF_SIZE); //将数据通过串口DMA发送

使用STM32CubeMX创建工程

配置SYS

配置RCC

配置GPIO

PB8配置成输出高电平

配置串口信息(UART1)

配置DMA

  • 使用DMA1的通道4,传输方向为内存到外设(串口1)

  • 配置成正常模式只会向串口发送一次数组内容,而配置成循环模式将不断向串口发送数组内容

配置工程名称、工程路径

选择固件库

生成工程

使用MicroLIB库

main.c文件编写

  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * Copyright (c) 2023 STMicroelectronics.
  10. * All rights reserved.
  11. *
  12. * This software is licensed under terms that can be found in the LICENSE file
  13. * in the root directory of this software component.
  14. * If no LICENSE file comes with this software, it is provided AS-IS.
  15. *
  16. ******************************************************************************
  17. */
  18. /* USER CODE END Header */
  19. /* Includes ------------------------------------------------------------------*/
  20. #include "main.h"
  21. #include "dma.h"
  22. #include "usart.h"
  23. #include "gpio.h"
  24. /* Private includes ----------------------------------------------------------*/
  25. /* USER CODE BEGIN Includes */
  26. #define BUF_SIZE 1000
  27. /* USER CODE END Includes */
  28. /* Private typedef -----------------------------------------------------------*/
  29. /* USER CODE BEGIN PTD */
  30. /* USER CODE END PTD */
  31. /* Private define ------------------------------------------------------------*/
  32. /* USER CODE BEGIN PD */
  33. /* USER CODE END PD */
  34. /* Private macro -------------------------------------------------------------*/
  35. /* USER CODE BEGIN PM */
  36. /* USER CODE END PM */
  37. /* Private variables ---------------------------------------------------------*/
  38. /* USER CODE BEGIN PV */
  39. /* USER CODE END PV */
  40. /* Private function prototypes -----------------------------------------------*/
  41. void SystemClock_Config(void);
  42. /* USER CODE BEGIN PFP */
  43. /* USER CODE END PFP */
  44. /* Private user code ---------------------------------------------------------*/
  45. /* USER CODE BEGIN 0 */
  46. //待发送数据
  47. unsigned char sendBuf[BUF_SIZE] = {0};
  48. /* USER CODE END 0 */
  49. /**
  50. * @brief The application entry point.
  51. * @retval int
  52. */
  53. int main(void)
  54. {
  55. /* USER CODE BEGIN 1 */
  56. int i = 0;
  57. /* USER CODE END 1 */
  58. /* MCU Configuration--------------------------------------------------------*/
  59. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  60. HAL_Init();
  61. /* USER CODE BEGIN Init */
  62. /* USER CODE END Init */
  63. /* Configure the system clock */
  64. SystemClock_Config();
  65. /* USER CODE BEGIN SysInit */
  66. /* USER CODE END SysInit */
  67. /* Initialize all configured peripherals */
  68. MX_GPIO_Init();
  69. MX_DMA_Init();
  70. MX_USART1_UART_Init();
  71. /* USER CODE BEGIN 2 */
  72. //①:准备数据
  73. for(i = 0;i < BUF_SIZE;i++){
  74. sendBuf[i] = 'h';
  75. }
  76. //②:将数据通过串口DMA发送
  77. HAL_UART_Transmit_DMA(&huart1,sendBuf,BUF_SIZE); //将数据通过串口DMA发送
  78. /* USER CODE END 2 */
  79. /* Infinite loop */
  80. /* USER CODE BEGIN WHILE */
  81. while (1)
  82. {
  83. /* USER CODE END WHILE */
  84. /* USER CODE BEGIN 3 */
  85. HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
  86. HAL_Delay(500);
  87. }
  88. /* USER CODE END 3 */
  89. }
  90. /**
  91. * @brief System Clock Configuration
  92. * @retval None
  93. */
  94. void SystemClock_Config(void)
  95. {
  96. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  97. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  98. /** Initializes the RCC Oscillators according to the specified parameters
  99. * in the RCC_OscInitTypeDef structure.
  100. */
  101. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  102. RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  103. RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  104. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  105. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  106. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  107. RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  108. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  109. {
  110. Error_Handler();
  111. }
  112. /** Initializes the CPU, AHB and APB buses clocks
  113. */
  114. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  115. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  116. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  117. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  118. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  119. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  120. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  121. {
  122. Error_Handler();
  123. }
  124. }
  125. /* USER CODE BEGIN 4 */
  126. /* USER CODE END 4 */
  127. /**
  128. * @brief This function is executed in case of error occurrence.
  129. * @retval None
  130. */
  131. void Error_Handler(void)
  132. {
  133. /* USER CODE BEGIN Error_Handler_Debug */
  134. /* User can add his own implementation to report the HAL error return state */
  135. __disable_irq();
  136. while (1)
  137. {
  138. }
  139. /* USER CODE END Error_Handler_Debug */
  140. }
  141. #ifdef USE_FULL_ASSERT
  142. /**
  143. * @brief Reports the name of the source file and the source line number
  144. * where the assert_param error has occurred.
  145. * @param file: pointer to the source file name
  146. * @param line: assert_param error line source number
  147. * @retval None
  148. */
  149. void assert_failed(uint8_t *file, uint32_t line)
  150. {
  151. /* USER CODE BEGIN 6 */
  152. /* User can add his own implementation to report the file name and line number,
  153. ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  154. /* USER CODE END 6 */
  155. }
  156. #endif /* USE_FULL_ASSERT */

DMA实验3(外设:UART1 -> 存储器)

使用DMA的方式将串口1接收缓存寄存器的数据搬运到存储器中,再通过串口打印存储器数据,同时每隔0.5s翻转一次LED1的电平。

实现流程

  • 使能IDLE空闲中断,当检测到串口空闲时(串口每接收完一份数据)就会调用一次串口中断。

  • 将串口数据使用DMA搬运到内存。

  • 在串口的中断处理函数USART1_IRQHandler()中将内存的数据显示在串口中:

  1. 判断是否是串口空闲触发的中断,即判断IDLE标志位是否置位SET。

  1. 停止DMA从串口搬运数据到内存。

  1. 获取DMA从串口搬运的数据大小。

  • 将DMA从串口搬运的内存数据打印在串口。

  • 重新将串口数据使用DMA搬运到内存,准备下一次的重复操作。

STM32的hal库关于DMA的函数

HAL_UART_Receive_DMA()

使用DMA搬运串口数据到其他地方

原型:
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

参数:
UART_HandleTypeDef *huart:串口句柄
uint8_t *pData:传输数据地址
uint16_t Size:传输数据大小

实例:
#define BUF_SIZE 1000

uint8_t rcvBuf[BUF_SIZE] = {0};

HAL_UART_Receive_DMA(&huart1,rcvBuf,BUF_SIZE); //将串口数据通过DMA接收到内存

__HAL_UART_ENABLE_IT()

使能某个串口标志位的中断。

原型:
__HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__)

参数:
__HANDLE__:串口句柄
__INTERRUPT__:
UART_IT_CTS: CTS change interrupt
UART_IT_LBD: LIN Break detection interrupt
UART_IT_TXE: Transmit Data Register empty interrupt
UART_IT_TC: Transmission complete interrupt
UART_IT_RXNE: Receive Data register not empty interrupt
UART_IT_IDLE: 串口空闲中断
UART_IT_PE: Parity Error interrupt
UART_IT_ERR: Error interrupt(Frame error, noise error, overrun error)

实例:
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); //使能IDLE空闲中断

__HAL_UART_GET_FLAG()

获取串口的某个标志位的状态

原型:
#define __HAL_UART_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->SR & (__FLAG__)) == (__FLAG__))

参数:
_HANDLE__:串口句柄
__FLAG__:
UART_FLAG_CTS: CTS Change flag (not available for UART4 and UART5)
UART_FLAG_LBD: LIN Break detection flag
UART_FLAG_TXE: Transmit data register empty flag
UART_FLAG_TC: Transmission Complete flag
UART_FLAG_RXNE: Receive data register not empty flag
UART_FLAG_IDLE: 串口空闲标志位
UART_FLAG_ORE: Overrun Error flag
UART_FLAG_NE: Noise Error flag
UART_FLAG_FE: Framing Error flag
UART_FLAG_PE: Parity Error flag

实例:
__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) //获取IDLE标志位的状态,如果被置位了为SET

HAL_UART_DMAStop()

停止DMA从串口搬运数据或者停止DMA搬运数据到串口。

原型:
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)

参数:
UART_HandleTypeDef *huart:串口句柄

实例:
HAL_UART_DMAStop(&huart1); //停止DMA从串口搬运数据

使用STM32CubeMX创建工程

配置SYS

配置RCC

配置GPIO

PB8配置成输出高电平

配置串口信息(UART1)

配置DMA

使用DMA1的通道5,传输方向为外设(串口1)到内存

配置工程名称、工程路径

选择固件库

生成工程

使用MicroLIB库

main.c文件编写

  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * Copyright (c) 2023 STMicroelectronics.
  10. * All rights reserved.
  11. *
  12. * This software is licensed under terms that can be found in the LICENSE file
  13. * in the root directory of this software component.
  14. * If no LICENSE file comes with this software, it is provided AS-IS.
  15. *
  16. ******************************************************************************
  17. */
  18. /* USER CODE END Header */
  19. /* Includes ------------------------------------------------------------------*/
  20. #include "main.h"
  21. #include "dma.h"
  22. #include "usart.h"
  23. #include "gpio.h"
  24. /* Private includes ----------------------------------------------------------*/
  25. /* USER CODE BEGIN Includes */
  26. #define BUF_SIZE 100
  27. /* USER CODE END Includes */
  28. /* Private typedef -----------------------------------------------------------*/
  29. /* USER CODE BEGIN PTD */
  30. /* USER CODE END PTD */
  31. /* Private define ------------------------------------------------------------*/
  32. /* USER CODE BEGIN PD */
  33. /* USER CODE END PD */
  34. /* Private macro -------------------------------------------------------------*/
  35. /* USER CODE BEGIN PM */
  36. /* USER CODE END PM */
  37. /* Private variables ---------------------------------------------------------*/
  38. /* USER CODE BEGIN PV */
  39. /* USER CODE END PV */
  40. /* Private function prototypes -----------------------------------------------*/
  41. void SystemClock_Config(void);
  42. /* USER CODE BEGIN PFP */
  43. /* USER CODE END PFP */
  44. /* Private user code ---------------------------------------------------------*/
  45. /* USER CODE BEGIN 0 */
  46. uint8_t rcvBuf[BUF_SIZE] = {0}; //接收数据缓存数组
  47. uint8_t rcvLen = 0; //接收一份数据的长度
  48. /* USER CODE END 0 */
  49. /**
  50. * @brief The application entry point.
  51. * @retval int
  52. */
  53. int main(void)
  54. {
  55. /* USER CODE BEGIN 1 */
  56. /* USER CODE END 1 */
  57. /* MCU Configuration--------------------------------------------------------*/
  58. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  59. HAL_Init();
  60. /* USER CODE BEGIN Init */
  61. /* USER CODE END Init */
  62. /* Configure the system clock */
  63. SystemClock_Config();
  64. /* USER CODE BEGIN SysInit */
  65. /* USER CODE END SysInit */
  66. /* Initialize all configured peripherals */
  67. MX_GPIO_Init();
  68. MX_DMA_Init();
  69. MX_USART1_UART_Init();
  70. /* USER CODE BEGIN 2 */
  71. //使能IDLE空闲中断,当检测到串口空闲时就会调用串口中断
  72. __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
  73. //DMA搬运串口数据到内存
  74. HAL_UART_Receive_DMA(&huart1,rcvBuf,BUF_SIZE);
  75. /* USER CODE END 2 */
  76. /* Infinite loop */
  77. /* USER CODE BEGIN WHILE */
  78. while (1)
  79. {
  80. /* USER CODE END WHILE */
  81. /* USER CODE BEGIN 3 */
  82. HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
  83. HAL_Delay(500);
  84. }
  85. /* USER CODE END 3 */
  86. }
  87. /**
  88. * @brief System Clock Configuration
  89. * @retval None
  90. */
  91. void SystemClock_Config(void)
  92. {
  93. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  94. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  95. /** Initializes the RCC Oscillators according to the specified parameters
  96. * in the RCC_OscInitTypeDef structure.
  97. */
  98. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  99. RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  100. RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  101. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  102. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  103. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  104. RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  105. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  106. {
  107. Error_Handler();
  108. }
  109. /** Initializes the CPU, AHB and APB buses clocks
  110. */
  111. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  112. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  113. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  114. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  115. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  116. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  117. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  118. {
  119. Error_Handler();
  120. }
  121. }
  122. /* USER CODE BEGIN 4 */
  123. /* USER CODE END 4 */
  124. /**
  125. * @brief This function is executed in case of error occurrence.
  126. * @retval None
  127. */
  128. void Error_Handler(void)
  129. {
  130. /* USER CODE BEGIN Error_Handler_Debug */
  131. /* User can add his own implementation to report the HAL error return state */
  132. __disable_irq();
  133. while (1)
  134. {
  135. }
  136. /* USER CODE END Error_Handler_Debug */
  137. }
  138. #ifdef USE_FULL_ASSERT
  139. /**
  140. * @brief Reports the name of the source file and the source line number
  141. * where the assert_param error has occurred.
  142. * @param file: pointer to the source file name
  143. * @param line: assert_param error line source number
  144. * @retval None
  145. */
  146. void assert_failed(uint8_t *file, uint32_t line)
  147. {
  148. /* USER CODE BEGIN 6 */
  149. /* User can add his own implementation to report the file name and line number,
  150. ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  151. /* USER CODE END 6 */
  152. }
  153. #endif /* USE_FULL_ASSERT */

stm32f1xx_it.c文件编写

  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file stm32f1xx_it.c
  5. * @brief Interrupt Service Routines.
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * Copyright (c) 2023 STMicroelectronics.
  10. * All rights reserved.
  11. *
  12. * This software is licensed under terms that can be found in the LICENSE file
  13. * in the root directory of this software component.
  14. * If no LICENSE file comes with this software, it is provided AS-IS.
  15. *
  16. ******************************************************************************
  17. */
  18. /* USER CODE END Header */
  19. /* Includes ------------------------------------------------------------------*/
  20. #include "main.h"
  21. #include "stm32f1xx_it.h"
  22. /* Private includes ----------------------------------------------------------*/
  23. /* USER CODE BEGIN Includes */
  24. /* USER CODE END Includes */
  25. /* Private typedef -----------------------------------------------------------*/
  26. /* USER CODE BEGIN TD */
  27. /* USER CODE END TD */
  28. /* Private define ------------------------------------------------------------*/
  29. /* USER CODE BEGIN PD */
  30. /* USER CODE END PD */
  31. /* Private macro -------------------------------------------------------------*/
  32. /* USER CODE BEGIN PM */
  33. /* USER CODE END PM */
  34. /* Private variables ---------------------------------------------------------*/
  35. /* USER CODE BEGIN PV */
  36. /* USER CODE END PV */
  37. /* Private function prototypes -----------------------------------------------*/
  38. /* USER CODE BEGIN PFP */
  39. /* USER CODE END PFP */
  40. /* Private user code ---------------------------------------------------------*/
  41. /* USER CODE BEGIN 0 */
  42. extern uint8_t rcvBuf[BUF_SIZE]; //接收数据缓存数组
  43. extern uint8_t rcvLen; //接收一帧数据的长度
  44. /* USER CODE END 0 */
  45. /* External variables --------------------------------------------------------*/
  46. extern DMA_HandleTypeDef hdma_usart1_rx;
  47. extern DMA_HandleTypeDef hdma_usart1_tx;
  48. extern UART_HandleTypeDef huart1;
  49. /* USER CODE BEGIN EV */
  50. /* USER CODE END EV */
  51. /******************************************************************************/
  52. /* Cortex-M3 Processor Interruption and Exception Handlers */
  53. /******************************************************************************/
  54. /**
  55. * @brief This function handles Non maskable interrupt.
  56. */
  57. void NMI_Handler(void)
  58. {
  59. /* USER CODE BEGIN NonMaskableInt_IRQn 0 */
  60. /* USER CODE END NonMaskableInt_IRQn 0 */
  61. /* USER CODE BEGIN NonMaskableInt_IRQn 1 */
  62. while (1)
  63. {
  64. }
  65. /* USER CODE END NonMaskableInt_IRQn 1 */
  66. }
  67. /**
  68. * @brief This function handles Hard fault interrupt.
  69. */
  70. void HardFault_Handler(void)
  71. {
  72. /* USER CODE BEGIN HardFault_IRQn 0 */
  73. /* USER CODE END HardFault_IRQn 0 */
  74. while (1)
  75. {
  76. /* USER CODE BEGIN W1_HardFault_IRQn 0 */
  77. /* USER CODE END W1_HardFault_IRQn 0 */
  78. }
  79. }
  80. /**
  81. * @brief This function handles Memory management fault.
  82. */
  83. void MemManage_Handler(void)
  84. {
  85. /* USER CODE BEGIN MemoryManagement_IRQn 0 */
  86. /* USER CODE END MemoryManagement_IRQn 0 */
  87. while (1)
  88. {
  89. /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
  90. /* USER CODE END W1_MemoryManagement_IRQn 0 */
  91. }
  92. }
  93. /**
  94. * @brief This function handles Prefetch fault, memory access fault.
  95. */
  96. void BusFault_Handler(void)
  97. {
  98. /* USER CODE BEGIN BusFault_IRQn 0 */
  99. /* USER CODE END BusFault_IRQn 0 */
  100. while (1)
  101. {
  102. /* USER CODE BEGIN W1_BusFault_IRQn 0 */
  103. /* USER CODE END W1_BusFault_IRQn 0 */
  104. }
  105. }
  106. /**
  107. * @brief This function handles Undefined instruction or illegal state.
  108. */
  109. void UsageFault_Handler(void)
  110. {
  111. /* USER CODE BEGIN UsageFault_IRQn 0 */
  112. /* USER CODE END UsageFault_IRQn 0 */
  113. while (1)
  114. {
  115. /* USER CODE BEGIN W1_UsageFault_IRQn 0 */
  116. /* USER CODE END W1_UsageFault_IRQn 0 */
  117. }
  118. }
  119. /**
  120. * @brief This function handles System service call via SWI instruction.
  121. */
  122. void SVC_Handler(void)
  123. {
  124. /* USER CODE BEGIN SVCall_IRQn 0 */
  125. /* USER CODE END SVCall_IRQn 0 */
  126. /* USER CODE BEGIN SVCall_IRQn 1 */
  127. /* USER CODE END SVCall_IRQn 1 */
  128. }
  129. /**
  130. * @brief This function handles Debug monitor.
  131. */
  132. void DebugMon_Handler(void)
  133. {
  134. /* USER CODE BEGIN DebugMonitor_IRQn 0 */
  135. /* USER CODE END DebugMonitor_IRQn 0 */
  136. /* USER CODE BEGIN DebugMonitor_IRQn 1 */
  137. /* USER CODE END DebugMonitor_IRQn 1 */
  138. }
  139. /**
  140. * @brief This function handles Pendable request for system service.
  141. */
  142. void PendSV_Handler(void)
  143. {
  144. /* USER CODE BEGIN PendSV_IRQn 0 */
  145. /* USER CODE END PendSV_IRQn 0 */
  146. /* USER CODE BEGIN PendSV_IRQn 1 */
  147. /* USER CODE END PendSV_IRQn 1 */
  148. }
  149. /**
  150. * @brief This function handles System tick timer.
  151. */
  152. void SysTick_Handler(void)
  153. {
  154. /* USER CODE BEGIN SysTick_IRQn 0 */
  155. /* USER CODE END SysTick_IRQn 0 */
  156. HAL_IncTick();
  157. /* USER CODE BEGIN SysTick_IRQn 1 */
  158. /* USER CODE END SysTick_IRQn 1 */
  159. }
  160. /******************************************************************************/
  161. /* STM32F1xx Peripheral Interrupt Handlers */
  162. /* Add here the Interrupt Handlers for the used peripherals. */
  163. /* For the available peripheral interrupt handler names, */
  164. /* please refer to the startup file (startup_stm32f1xx.s). */
  165. /******************************************************************************/
  166. /**
  167. * @brief This function handles DMA1 channel4 global interrupt.
  168. */
  169. void DMA1_Channel4_IRQHandler(void)
  170. {
  171. /* USER CODE BEGIN DMA1_Channel4_IRQn 0 */
  172. /* USER CODE END DMA1_Channel4_IRQn 0 */
  173. HAL_DMA_IRQHandler(&hdma_usart1_tx);
  174. /* USER CODE BEGIN DMA1_Channel4_IRQn 1 */
  175. /* USER CODE END DMA1_Channel4_IRQn 1 */
  176. }
  177. /**
  178. * @brief This function handles DMA1 channel5 global interrupt.
  179. */
  180. void DMA1_Channel5_IRQHandler(void)
  181. {
  182. /* USER CODE BEGIN DMA1_Channel5_IRQn 0 */
  183. /* USER CODE END DMA1_Channel5_IRQn 0 */
  184. HAL_DMA_IRQHandler(&hdma_usart1_rx);
  185. /* USER CODE BEGIN DMA1_Channel5_IRQn 1 */
  186. /* USER CODE END DMA1_Channel5_IRQn 1 */
  187. }
  188. /**
  189. * @brief This function handles USART1 global interrupt.
  190. */
  191. void USART1_IRQHandler(void)
  192. {
  193. /* USER CODE BEGIN USART1_IRQn 0 */
  194. /* USER CODE END USART1_IRQn 0 */
  195. HAL_UART_IRQHandler(&huart1);
  196. /* USER CODE BEGIN USART1_IRQn 1 */
  197. //如果是串口1空闲触发的中断,IDLE标志位会置位SET
  198. if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) == SET){
  199. //__HAL_UART_CLEAR_FEFLAG(&huart1); //清除帧错误标志位FE,该位会提醒当前字符是否存在帧错误
  200. HAL_UART_DMAStop(&huart1); //停止DMA从串口1中搬运数据
  201. uint8_t tempLen = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); //获取DMA未搬运的数据大小
  202. rcvLen = BUF_SIZE - tempLen; //DMA当前搬运了的数据大小
  203. HAL_UART_Transmit(&huart1,rcvBuf,rcvLen,0xffff); //将内存数据通过DNA发送到串口
  204. HAL_UART_Receive_DMA(&huart1,rcvBuf,BUF_SIZE); //重新开始DMA搬运串口数据到内存
  205. }
  206. /* USER CODE END USART1_IRQn 1 */
  207. }
  208. /* USER CODE BEGIN 1 */
  209. /* USER CODE END 1 */

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/369047
推荐阅读
相关标签
  

闽ICP备14008679号