OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4664|回复: 15

Stm32f030串口dma接收数据,偶发性触发不了中断

[复制链接]

25

主题

115

帖子

0

精华

高级会员

Rank: 4

积分
940
金钱
940
注册时间
2018-11-9
在线时间
146 小时
发表于 2021-12-7 14:11:39 | 显示全部楼层 |阅读模式
1金钱
用stm32f030芯片的串口dma接收数据,然后发现偶尔不触发接收中断,485总线上用示波器量是有数据的,就是不触发接收,偶然发生,很奇怪

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

668

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1926
金钱
1926
注册时间
2021-8-13
在线时间
262 小时
发表于 2021-12-7 14:19:54 | 显示全部楼层
回复

使用道具 举报

12

主题

3399

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8679
金钱
8679
注册时间
2020-5-11
在线时间
4162 小时
发表于 2021-12-7 14:32:32 | 显示全部楼层
即然有示波器,为啥不测RXD脚,485有数据不代表RXD脚有数据。
专治疑难杂症
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2021-12-7 16:57:26 | 显示全部楼层
应该是你的中断配置出了问题。
     我的单片机STM32F103和STM32F407使用DMA运行了5年都没有出现你说的问题。
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2021-12-7 17:03:37 | 显示全部楼层
1.DMA.H
  1. #include "stm32f10x.h"

  2. void USART1_DMA_Tx_Configuration(void);
  3. void USART1_DMA_Rx_Configuration(void);
  4. void USART2_DMA_Tx_Configuration(void);
  5. void USART2_DMA_Rx_Configuration(void);
  6. void USART3_DMA_Tx_Configuration(void);
  7. void USART3_DMA_Rx_Configuration(void);
  8. void UART4_DMA_Tx_Configuration(void);
  9. void UART4_DMA_Rx_Configuration(void);
  10. void UART5_DMA_Tx_Configuration(void);
  11. void UART5_DMA_Rx_Configuration(void);
  12. void USART6_DMA_Tx_Configuration(void);
  13. void USART6_DMA_Rx_Configuration(void);
  14. void USART1_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount);
  15. void USART2_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount);
  16. void UART4_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount);
  17. void UART5_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount);
  18. void USART6_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount);
复制代码
2、DMA.C
  1. uint8_t USART1_DMA_RX_Buffer[USART1_DMA_RX_BUFFER_MAX_LENGTH];
  2. uint8_t USART1_DMA_TX_Buffer[USART1_DMA_TX_BUFFER_MAX_LENGTH];



  3. void USART1_DMA_Tx_Configuration(void)
  4. {
  5.         DMA_InitTypeDef  DMA_InitStructure;
  6.        
  7.        
  8.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);                                                //DMA1时钟使能
  9.         DMA_DeInit(DMA1_Channel4);
  10.         DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;                //DMA外设地址
  11.     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_DMA_TX_Buffer;        //发送缓存指针
  12.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                                                //传输方向
  13.     DMA_InitStructure.DMA_BufferSize = USART1_DMA_TX_BUFFER_MAX_LENGTH;                //传输长度
  14.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                //外设递增
  15.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                 //内存递增
  16.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;        //外设数据宽度:BYTE
  17.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;                        //内存数据宽度:BYTE
  18.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                                        //循环模式:否//(注:DMA_Mode_Normal为正常模式,DMA_Mode_Circular为循环模式)
  19.     DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;                                 //优先级:高
  20.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                                         //内存:内存(都)
  21.         DMA_Init(DMA1_Channel4 , &DMA_InitStructure);                                                        //初始化DMA1_Channel4
  22.         DMA_ClearFlag(DMA1_FLAG_GL4);
  23.         DMA_Cmd(DMA1_Channel4 , DISABLE);                                                                                 //开启DMA传输
  24. }





  25. void USART1_DMA_Rx_Configuration(void)
  26. {
  27.         DMA_InitTypeDef  DMA_InitStructure;

  28.        
  29.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);                                        //DMA1时钟使能
  30.     DMA_DeInit(DMA1_Channel5);                 
  31.         DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);
  32.     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_DMA_RX_Buffer;        //接收缓存指针   
  33.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                    
  34.     DMA_InitStructure.DMA_BufferSize = USART1_DMA_RX_BUFFER_MAX_LENGTH;                //缓冲大小
  35.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;      
  36.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;               
  37.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  38.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;        
  39.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//(注:DMA_Mode_Normal为正常模式,DMA_Mode_Circular为循环模式)                           
  40.     DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;               
  41.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                           
  42.     DMA_Init(DMA1_Channel5, &DMA_InitStructure);            
  43.     DMA_ClearFlag(DMA1_FLAG_GL5);                              
  44.     DMA_Cmd(DMA1_Channel5 , ENABLE);  
  45. }
复制代码
3、USART1.C
  1. //DMA方式
  2. void USART1_Configuration(void)
  3. {
  4.         GPIO_InitTypeDef GPIO_InitStructure;
  5.         USART_InitTypeDef USART_InitStructure;
  6.                
  7.        
  8.         // config USART1 clock
  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

  10.         // USART1 GPIO config
  11.         // Configure USART1 Tx (PA.09) as alternate function push-pull
  12.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  13.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  14.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  15.         GPIO_Init(GPIOA, &GPIO_InitStructure);                                    //        PA.9
  16.        
  17.         // Configure USART1 Rx (PA.10) as input floating
  18.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  19.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  20.         GPIO_Init(GPIOA, &GPIO_InitStructure);                                        //        PA.10
  21.        
  22.         // USART1 mode config
  23.         USART_InitStructure.USART_BaudRate = 115200;
  24.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  25.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  26.         USART_InitStructure.USART_Parity = USART_Parity_No ;
  27.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  28.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  29.         USART_Init(USART1, &USART_InitStructure);
  30.        
  31. //CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去如下语句解决第1个字节无法正确发送出去的问题
  32. //        USART_ClearFlag(USART1, USART_FLAG_TC);                                     //清发送完成标志,Transmission Complete flag         
  33. //        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  34. //        USART_Cmd(USART1, ENABLE);


  35.         USART_Cmd(USART1, ENABLE);
  36.         USART_ClearFlag(USART1, USART_FLAG_TC); //清除发送完成标志       
  37.         while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);//等待空闲帧发送完成后再清零发送完成标志(警告:如果不使能USART_Mode_Tx,会导致单片机在这里死机)
  38.         USART_ClearFlag(USART1, USART_FLAG_TC);        //清除发送完成标志

  39.     USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
  40.         USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
  41.         USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
  42.         USART_ITConfig(USART1, USART_IT_TC, ENABLE);
  43.         USART_DMACmd(USART1 ,   USART_DMAReq_Tx,ENABLE);
  44.         USART_DMACmd(USART1 ,   USART_DMAReq_Rx,ENABLE);


  45. //错误:
  46. //1、以下情况初始化STM32F013VC单片机串口1,则单片机会死机
  47. //        USART_ClearFlag(USART1, USART_FLAG_TC); //清除发送完成标志       
  48. //        while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);        //等待空闲帧发送完成后再清零发送完成标志(警告:如果不使能USART_Mode_Tx,会导致单片机在这里死机)
  49. //        USART_ClearFlag(USART1, USART_FLAG_TC);        //清除发送完成标志
  50. //        USART_Cmd(USART1, ENABLE);
  51. //正确:
  52. //2、以下情况初始化STM32F013VC单片机串口1,则正常运行
  53. //        USART_Cmd(USART1, ENABLE);
  54. //        USART_ClearFlag(USART1, USART_FLAG_TC); //清除发送完成标志       
  55. //        while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);        //等待空闲帧发送完成后再清零发送完成标志(警告:如果不使能USART_Mode_Tx,会导致单片机在这里死机)
  56. //        USART_ClearFlag(USART1, USART_FLAG_TC);        //清除发送完成标志
  57. //
  58. //3、因此USART_Cmd(USART1, ENABLE);必须放在while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);前面执行
  59. }


  60. //DMA方式
  61. void USART1_IRQHandler(void)
  62. {
  63.         uint16_t ch;

  64.        
  65.         if (USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
  66.         {               
  67.                 USART_ClearITPendingBit(USART1 , USART_IT_IDLE);        //必须先清除总线空闲中断标识,然后读一下数据寄存器,DMA接收才会正确(先读SR,然后读DR才能清除空闲中断标识)注意:这句必须要,否则不能够清除中断标志位。
  68.                 ch =  USART_ReceiveData(USART1);                                        //必须先清除总线空闲中断标识,然后读一下数据寄存器,DMA接收才会正确(先读SR,然后读DR才能清除空闲中断标识)注意:这句必须要,否则不能够清除中断标志位。                               

  69.                 DMA_Cmd(DMA1_Channel5 , DISABLE);                                         //关闭DMA,防止处理其间有数据
  70.                 DMA_ClearFlag(DMA1_FLAG_GL5 | DMA1_FLAG_TC5 | DMA1_FLAG_HT5 | DMA1_FLAG_TE5);
  71.                 ch = USART1_DMA_RX_BUFFER_MAX_LENGTH - DMA_GetCurrDataCounter(DMA1_Channel5);
  72.                 if (ch > 0)
  73.                 {
  74.                         MB_USART1.Outtime_mark = TRUE;
  75.                         MB_USART1.receCount = ch;
  76.                         memcpy(MB_USART1.mscomm_buffer , USART1_DMA_RX_Buffer , MB_USART1.receCount);
  77.                 }
  78.                 DMA_SetCurrDataCounter(DMA1_Channel5 , USART1_DMA_RX_BUFFER_MAX_LENGTH);
  79.                 DMA_Cmd(DMA1_Channel5, ENABLE);
  80.         }
  81.        
  82.         else if (USART_GetITStatus(USART1,USART_IT_TC)!= RESET)
  83.         {
  84.                 USART_ClearITPendingBit(USART1, USART_IT_TC);
  85.                                
  86.                 //DMA_Cmd(DMA2_Stream7 , DISABLE);//这条语句必须屏蔽,否则485通信时会出现异常情况,2018.10.18
  87.                 DMA_ClearFlag(DMA1_FLAG_GL4 | DMA1_FLAG_TC4 | DMA1_FLAG_HT4 | DMA1_FLAG_TE4);
  88.                 DMA_SetCurrDataCounter(DMA1_Channel4 , 0);
  89.                 //GPIO_USART1_RS485_RECIVE_enable();
  90.         }       
  91. }
复制代码


回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2021-12-7 17:08:28 | 显示全部楼层
5、主程序中启动DMA发送中断
    发送前先将发送数据和发送字节数填充到DMA发送缓冲区,然后开启DMA传输中断即可自动完成发送。

  1. void USART1_DMA_Begin_Send(uint8_t *send_buffer , uint16_t nSendCount)
  2. {               
  3.         if (nSendCount < USART1_DMA_TX_BUFFER_MAX_LENGTH)
  4.         {
  5.                 memcpy(USART1_DMA_TX_Buffer , send_buffer , nSendCount);
  6.                 DMA_Cmd(DMA1_Channel4 , DISABLE);                    //关闭DMA传输
  7.                 //while (DMA_GetCmdStatus(DMA1_Channel4) != DISABLE);//确保DMA可以被设置
  8.                 DMA_SetCurrDataCounter(DMA1_Channel4 , nSendCount);  //数据传输量
  9.                 DMA_Cmd(DMA1_Channel4 , ENABLE);                                //开启DMA传输
  10.         }
  11. }
复制代码


回复

使用道具 举报

25

主题

115

帖子

0

精华

高级会员

Rank: 4

积分
940
金钱
940
注册时间
2018-11-9
在线时间
146 小时
 楼主| 发表于 2021-12-7 18:36:27 来自手机 | 显示全部楼层
霸王猫 发表于 2021-12-7 17:08
5、主程序中启动DMA发送中断
    发送前先将发送数据和发送字节数填充到DMA发送缓冲区,然后开启DMA传输中 ...

难呦,偶发性的,不知道咋回事
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2021-12-7 18:41:20 | 显示全部楼层
本帖最后由 霸王猫 于 2021-12-7 18:46 编辑
dingning 发表于 2021-12-7 18:36
难呦,偶发性的,不知道咋回事

既然是偶发性的,应该是软件配置方面的问题。

    (1)、检查初始化
    (2)、检查串口中断里是否清除了相应的中断标志位。

  我上面提供的程序,采用的是USART1+DMA方式接收和发送数据,只开启了USART1中断,没有开启DMA中断,连续运行5年都没有问题。
      记住:1、我只开启了USART1中断,没有开启DMA中断。
               2、在USART1初始化中启用了DMA接收方式和DMA发送方式。
               3、在USART1的接收中断里清除了DMA中断标识。--->按照我的方式配置肯定没有问题
               4、USART1的发送中断里清除了DMA中断标识。--->按照我的方式配置肯定没有问题

回复

使用道具 举报

2

主题

685

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3448
金钱
3448
注册时间
2017-7-4
在线时间
869 小时
发表于 2021-12-7 23:33:41 | 显示全部楼层
DMA收发参考这个,里面有f030例子:https://acuity.blog.csdn.net/article/details/108367512
回复

使用道具 举报

5

主题

179

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
8195
金钱
8195
注册时间
2016-9-7
在线时间
1113 小时
发表于 2021-12-8 08:53:56 | 显示全部楼层
可以先排除硬件问题,换过板子吗,或者不适用dma的情况如何?
回复

使用道具 举报

25

主题

115

帖子

0

精华

高级会员

Rank: 4

积分
940
金钱
940
注册时间
2018-11-9
在线时间
146 小时
 楼主| 发表于 2021-12-13 10:29:57 | 显示全部楼层
lrzxc 发表于 2021-12-8 08:53
可以先排除硬件问题,换过板子吗,或者不适用dma的情况如何?

是偶发性的,要是硬件有问题应该一直发生才对
回复

使用道具 举报

25

主题

115

帖子

0

精华

高级会员

Rank: 4

积分
940
金钱
940
注册时间
2018-11-9
在线时间
146 小时
 楼主| 发表于 2021-12-13 10:30:21 | 显示全部楼层
Acuity 发表于 2021-12-7 23:33
DMA收发参考这个,里面有f030例子:https://acuity.blog.csdn.net/article/details/108367512

好的,谢谢呦
回复

使用道具 举报

25

主题

115

帖子

0

精华

高级会员

Rank: 4

积分
940
金钱
940
注册时间
2018-11-9
在线时间
146 小时
 楼主| 发表于 2021-12-13 10:31:20 | 显示全部楼层
霸王猫 发表于 2021-12-7 18:41
既然是偶发性的,应该是软件配置方面的问题。

    (1)、检查初始化

好的,我开启DMA中断了
回复

使用道具 举报

25

主题

115

帖子

0

精华

高级会员

Rank: 4

积分
940
金钱
940
注册时间
2018-11-9
在线时间
146 小时
 楼主| 发表于 2021-12-13 10:35:36 | 显示全部楼层
霸王猫 发表于 2021-12-7 18:41
既然是偶发性的,应该是软件配置方面的问题。

    (1)、检查初始化

因为我记得F429HAL库中的HAL_UART_Receive_DMA会自动需要DMA中断
  1. HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
  2. {
  3.   uint32_t *tmp;

  4.   /* Check that a Rx process is not already ongoing */
  5.   if (huart->RxState == HAL_UART_STATE_READY)
  6.   {
  7.     if ((pData == NULL) || (Size == 0U))
  8.     {
  9.       return HAL_ERROR;
  10.     }

  11.     /* Process Locked */
  12.     __HAL_LOCK(huart);

  13.     huart->pRxBuffPtr = pData;
  14.     huart->RxXferSize = Size;

  15.     huart->ErrorCode = HAL_UART_ERROR_NONE;
  16.     huart->RxState = HAL_UART_STATE_BUSY_RX;

  17.     /* Set the UART DMA transfer complete callback */
  18.     huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt;

  19.     /* Set the UART DMA Half transfer complete callback */
  20.     huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;

  21.     /* Set the DMA error callback */
  22.     huart->hdmarx->XferErrorCallback = UART_DMAError;

  23.     /* Set the DMA abort callback */
  24.     huart->hdmarx->XferAbortCallback = NULL;

  25.     /* Enable the DMA stream */
  26.     tmp = (uint32_t *)&pData;
  27.     HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t *)tmp, Size);
复制代码
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2021-12-13 11:20:52 | 显示全部楼层
dingning 发表于 2021-12-13 10:31
好的,我开启DMA中断了



1、可以使用USART中断+DMA中断
2、也可以单独使用USART中断(空中断+发送完成中断),此时不需要DMA中断


    我使用的是第二种方案,单独使用USART中断空中断+发送完成中断),没有开启DMA中断。
回复

使用道具 举报

25

主题

115

帖子

0

精华

高级会员

Rank: 4

积分
940
金钱
940
注册时间
2018-11-9
在线时间
146 小时
 楼主| 发表于 2021-12-13 11:36:04 | 显示全部楼层
霸王猫 发表于 2021-12-13 11:20
1、可以使用USART中断+DMA中断
2、也可以单独使用USART中断(空中断+发送完成中断),此时不需要DMA ...

嗯嗯,我现在是用串口空闲中断,然后发送是阻塞发送
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-18 04:02

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表