[其他ST产品] STM32CubeMX 串口空闲中断加DMA 实现不定长度收发数据

[复制链接]
2128|19
 楼主| kzlzqi 发表于 2023-9-20 15:04 | 显示全部楼层 |阅读模式
这里教程是选择的STM32F407。STM32F103也测试过。

1.首先选择串口,选择异步通信。


2.添加DMA


3.打开中断


4.生成代码,生成代码选择了每个外设单独使用.c/.h


5.我使用的是Keil5。打开工程,首先注释掉dma.c里的DMA接收中断,因为不需要DMA接收中断,DMA发送中断是需要的。(dma.c)


  1. void MX_DMA_Init(void)
  2. {
  3.   /* DMA controller clock enable */
  4.   __HAL_RCC_DMA2_CLK_ENABLE();

  5.   /* DMA interrupt init */
  6.   /* DMA2_Stream0_IRQn interrupt configuration */
  7.   HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 2, 0);
  8.   HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
  9.   /* DMA2_Stream2_IRQn interrupt configuration */
  10. //  HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
  11. //  HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
  12.   /* DMA2_Stream7_IRQn interrupt configuration */
  13.   HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 1, 0);
  14.   HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);

  15. }


 楼主| kzlzqi 发表于 2023-9-20 16:00 | 显示全部楼层
6.在usart.h文件里定义串口接收数据类型我是如下定义的(usart.h)
 楼主| kzlzqi 发表于 2023-9-20 16:02 | 显示全部楼层
/* USER CODE BEGIN Private defines */
#define RECEIVELEN 1024
#define USART_DMA_SENDING 1//发送未完成
#define USART_DMA_SENDOVER 0//发送完成
typedef struct
{
uint8_t receive_flag:1;//空闲接收标记
uint8_t dmaSend_flag:1;//发送完成标记
uint16_t rx_len;//接收长度
uint8_t usartDMA_rxBuf[RECEIVELEN];//DMA接收缓存
}USART_RECEIVETYPE;

extern USART_RECEIVETYPE UsartType1;


/* USER CODE END Private defines */
 楼主| kzlzqi 发表于 2023-9-20 16:02 | 显示全部楼层
7.然后在usart.c里需要添加空闲中断处理函数,以及DMA发送函数等。(usart.c)
首先定义串口数据类型:
  1. /* USER CODE BEGIN 0 */

  2. USART_RECEIVETYPE UsartType1;

  3. /* USER CODE END 0 */
 楼主| kzlzqi 发表于 2023-9-20 16:02 | 显示全部楼层
然后定义空闲中断处理函数和DMA发送函数
  1. /* USER CODE BEGIN 1 */
  2. #ifdef __GNUC__

  3.   /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
  4. set to 'Yes') calls __io_putchar() */
  5. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
  6. #else

  7.   #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
  8. #endif /* __GNUC__ */
  9.        
  10. PUTCHAR_PROTOTYPE
  11. {
  12.         HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
  13.         return ch;
  14. }

  15. //DMA发送函数
  16. void Usart1SendData_DMA(uint8_t *pdata, uint16_t Length)
  17. {
  18.         while(UsartType1.dmaSend_flag == USART_DMA_SENDING);
  19.         UsartType1.dmaSend_flag = USART_DMA_SENDING;
  20.         HAL_UART_Transmit_DMA(&huart1, pdata, Length);
  21. }

  22. //DMA发送完成中断回调函数
  23. void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
  24. {
  25.          __HAL_DMA_DISABLE(huart->hdmatx);
  26.         UsartType1.dmaSend_flag = USART_DMA_SENDOVER;
  27. }

  28. //串口接收空闲中断
  29. void UsartReceive_IDLE(UART_HandleTypeDef *huart)
  30. {
  31.         uint32_t temp;

  32.         if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
  33.         {
  34.                 __HAL_UART_CLEAR_IDLEFLAG(&huart1);
  35.                 HAL_UART_DMAStop(&huart1);
  36.                 temp = huart1.hdmarx->Instance->NDTR;
  37.                 UsartType1.rx_len =  RECEIVELEN - temp;
  38.                 UsartType1.receive_flag=1;
  39.                 HAL_UART_Receive_DMA(&huart1,UsartType1.usartDMA_rxBuf,RECEIVELEN);
  40.         }
  41. }

  42. /* USER CODE END 1 */
 楼主| kzlzqi 发表于 2023-9-20 16:06 | 显示全部楼层
</pre><p></p><pre>
 楼主| kzlzqi 发表于 2023-9-20 16:06 | 显示全部楼层
8.在中断文件里添加(当然,上面的空闲中断处理函数需要声明)(stm32f4xxit.c)

  1. void USART1_IRQHandler(void)
  2. {
  3.   /* USER CODE BEGIN USART1_IRQn 0 */
  4.         UsartReceive_IDLE(&huart1);
  5.   /* USER CODE END USART1_IRQn 0 */
  6.   HAL_UART_IRQHandler(&huart1);
  7.   /* USER CODE BEGIN USART1_IRQn 1 */

  8.   /* USER CODE END USART1_IRQn 1 */
  9. }
 楼主| kzlzqi 发表于 2023-9-20 16:06 | 显示全部楼层
9.主函数里,打开空闲中断,初始化DMA接收
  1. /* USER CODE BEGIN 2 */
  2.         HAL_UART_Receive_DMA(&huart1, UsartType1.usartDMA_rxBuf, RECEIVELEN);
  3.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
  4.   /* USER CODE END 2 */
 楼主| kzlzqi 发表于 2023-9-20 16:06 | 显示全部楼层
10.然后就可以在while(1)里处理数据了
  1. /* Infinite loop */
  2.   /* USER CODE BEGIN WHILE */
  3.        
  4.   while (1)
  5.   {
  6.                 if(UsartType1.receive_flag)//如果产生了空闲中断
  7.                 {
  8.                         UsartType1.receive_flag=0;//清零标记
  9.                         Usart1SendData_DMA(UsartType1.usartDMA_rxBuf,UsartType1.rx_len);//串口打印收到的数据。
  10.                 }
  11.   /* USER CODE END WHILE */

  12.   /* USER CODE BEGIN 3 */
  13.                
  14.   }
  15.   /* USER CODE END 3 */
AloneKaven 发表于 2023-9-20 21:53 | 显示全部楼层
空闲中断是怎么用的啊
中国龙芯CDX 发表于 2024-4-28 18:11 | 显示全部楼层
初始化DMA有哪些注意事项呢?
童雨竹 发表于 2024-9-6 08:26 | 显示全部楼层

确保当开关管导通,
Wordsworth 发表于 2024-9-6 09:29 | 显示全部楼层

电阻元件的电阻值大小一般与温度,材料,长度,还有横截面积有关
Clyde011 发表于 2024-9-6 10:32 | 显示全部楼层

灌封之前需要使用抽空机进行天然脱泡和真空脱泡预处理
公羊子丹 发表于 2024-9-6 11:25 | 显示全部楼层

主要起到支承作用,板不会散掉。
Uriah 发表于 2024-9-6 13:31 | 显示全部楼层

在低成本控制器内部有时候会没有钳位二极管
帛灿灿 发表于 2024-9-6 15:27 | 显示全部楼层

会使二极管导通
Bblythe 发表于 2024-9-6 16:30 | 显示全部楼层

对于电力电路来说串联的电阻起阻尼作用
周半梅 发表于 2024-9-6 18:26 | 显示全部楼层

将ESD静电保护二极管并联于电路中
Pulitzer 发表于 2024-9-6 19:29 | 显示全部楼层

电阻阻值大小则需根据元器件可承受电流大小而决定
您需要登录后才可以回帖 登录 | 注册

本版积分规则

127

主题

996

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部