你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】stm32f0串口 DMA 空闲中断接收——基于HAL库(代码篇)

[复制链接]
STMCU小助手 发布时间:2021-11-25 15:00
一、STM32CubeMX开发
1.1 新建工程
file -> new project

选择芯片-> stm32 core内核         

                   stm32 series 系列

                   stm32  line

                   stm32  package

选择芯片根据自身需求去选择,目前该项目是stm32f0系列

                    stm32 core内核         M0

                   stm32 series 系列      F0

                   stm32  line                 F0X1

                   stm32  package         TSSOP 20

1.2 配置 USART1
配置 USART1 的模式为 Asynchronous,即异步串口模式

20210827163252369.png


1.3 配置串口参数
根据需要设置波特率和数据宽度等参数,在此使用 9600,8,N,1

20210827163448427.png


1.4 设置DMA

20210827164240955.png


1.5 添加串口中断

20210827164323729.png


1.6 生成源代码。
在界面中输入工程名,保存路径,工程 IDE 类型,点 GENERATE CODE 即可。

20210827164544427.png


生成代码完成后可选择打开工程。

20210827164829635.png


二、代码部分
2.1  接收中断处理
2.1.1 接收固定长度:(舍弃)
只有接收缓存到固定长度才会触发中断
串口接收回调函数

  1. uint8_t aRxBuffer[RXBUFFERSIZE];
  2. /* Size of Reception buffer */
  3. #define RXBUFFERSIZE                    10


  4. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
  5. {
  6.   /* Set transmission flag: trasfer complete*/
  7.   UartrxReady = SET;
  8.         HAL_UART_Transmit(&huart1, aRxBuffer, 10, 0x200);
  9.         HAL_UART_Receive_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
  10.   HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer,1);

  11. }

  12. void USART1_IRQHandler(void)
  13. {
  14.   HAL_UART_IRQHandler(&huart1);
  15. }


  16. static void MX_USART1_UART_Init(void)
  17. {

  18.   huart1.Instance = USART1;
  19.   huart1.Init.BaudRate = 9600;
  20.   huart1.Init.WordLength = UART_WORDLENGTH_8B;
  21.   huart1.Init.StopBits = UART_STOPBITS_1;
  22.   huart1.Init.Parity = UART_PARITY_NONE;
  23.   huart1.Init.Mode = UART_MODE_TX_RX;
  24.   huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  25.   huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  26.   huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  27.   huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  28.   if(HAL_UART_DeInit(&huart1) != HAL_OK)
  29.   {
  30.     Error_Handler();
  31.   }  
  32.         
  33.         if (HAL_UART_Init(&huart1) != HAL_OK)
  34.   {
  35.     Error_Handler();
  36.   }
  37.         
  38.         UartrxReady=RESET;
  39.   /* USER CODE BEGIN USART1_Init 2 */
  40.         if(HAL_UART_Receive_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
  41.   {
  42.     Error_Handler();
  43.   }
  44.         
  45.   /* USER CODE END USART1_Init 2 */
  46. }
复制代码

从串口调试助手可以看只有接收的长度 RXBUFFERSIZE为10时,才触发接收回调函数。

20210902164819116.png


2.1.2 编写空闲中断函数接收不定长
USART1初始化:
  1. static void MX_USART1_UART_Init(void)
  2. {
  3.   huart1.Instance = USART1;
  4.   huart1.Init.BaudRate = 9600;
  5.   huart1.Init.WordLength = UART_WORDLENGTH_8B;
  6.   huart1.Init.StopBits = UART_STOPBITS_1;
  7.   huart1.Init.Parity = UART_PARITY_NONE;
  8.   huart1.Init.Mode = UART_MODE_TX_RX;
  9.   huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  10.   huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  11.   huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  12.   huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  13.   if(HAL_UART_DeInit(&huart1) != HAL_OK)
  14.   {
  15.     Error_Handler();
  16.   }  
  17.         
  18.         if (HAL_UART_Init(&huart1) != HAL_OK)
  19.   {
  20.     Error_Handler();
  21.   }

  22.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
  23.   /* USER CODE BEGIN USART1_Init 2 */
  24.         if(HAL_UART_Receive_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
  25.   {
  26.     Error_Handler();
  27.   }
  28.         
  29. }
复制代码

空闲中断函数:
  1. #define TXBUFFERSIZE                    30
  2. /* Size of Reception buffer */
  3. #define RXBUFFERSIZE                    30

  4. void USAR_UART_IDLECallback(UART_HandleTypeDef *huart)
  5. {
  6.     HAL_UART_DMAStop(&huart1);

  7.     uint8_t data_length  = RXBUFFERSIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);


  8.     HAL_UART_Transmit(&huart1,aRxBuffer,data_length,0x200);

  9.     memset(aRxBuffer,0x00,data_length);
  10.     data_length = 0;
  11.     HAL_UART_Receive_DMA(&huart1, (uint8_t*)aRxBuffer, RXBUFFERSIZE);
  12. }

  13. void USER_UART_IRQHandler(UART_HandleTypeDef *huart)
  14. {
  15.     if(USART1 == huart1.Instance)
  16.     {
  17.         if(RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
  18.         {
  19.             __HAL_UART_CLEAR_IDLEFLAG(&huart1);
  20.             USAR_UART_IDLECallback(huart);
  21.         }
  22.     }
  23. }

  24. /**
  25.   * @brief This function handles USART1 global interrupt / USART1 wake-up interrupt through EXTI line 25.
  26.   */
  27. void USART1_IRQHandler(void)
  28. {
  29.     HAL_UART_IRQHandler(&huart1);
  30.     USER_UART_IRQHandler(&huart1);
  31. }
复制代码

可实现不定长的接收!

20210902171851390.png


注意:
在中断中,尽量处理简单,不要做过多的处理,如发射,可以在函数外执行。

三、使用ringbuffer实现任意数据类型的FIFO处理接收数据
使用原因:

        虽然将数据保存在DMA接收缓存中,但在处理接收数据时,可能存在接收新的数据在调用数据完覆盖了接收缓存,导致调用数据时候会出现与原计划的处理不同的问题。

        因此,使用ringbuffer将DMA接收缓存,以防数据的被覆盖

① fifo头文件:
  1. #ifndef        __FIFO_H_
  2. #define        __FIFO_H_

  3. #pragma pack(4)
  4. typedef struct FIFO_Type_STRU
  5. {
  6.         unsigned int                        Depth;                        // Fifo深度
  7.         volatile unsigned int        Head;                        // Head为起始元素
  8.         volatile unsigned int        Tail;                        // Tail-1为最后一个元素
  9.         volatile unsigned int        Counter;                // 元素个数
  10.         unsigned int                        ElementBytes;        // 每个元素的字节数element
  11.         void                                        *Buff;                        // 缓存区
  12. }FIFO_Type;
  13. #pragma pack()

  14. /********************************************************************//**
  15. * @brief       FIFO初始化
  16. * @param[in]   pFIFO: FIFO指针
  17. * @param[in]        pBuff: FIFO中缓存
  18. * @param[in]        elementBytes:FIFO每个元素的字节数
  19. * @param[in]        depth: FIFO深度
  20. * @return      None
  21. *********************************************************************/
  22. void FIFO_Init(FIFO_Type *pFIFO, void *pBuff, unsigned int elementBytes, unsigned int depth);

  23. /********************************************************************//**
  24. * @brief       向FIFO添加一个元素
  25. * @param[in]   pFIFO: FIFO指针
  26. * @param[in]        pValue: 要添加的元素
  27. * @return      1-TRUE or 0-FALSE
  28. *********************************************************************/
  29. unsigned char FIFO_AddOne(FIFO_Type *pFIFO, void *pValue);

  30. /********************************************************************//**
  31. * @brief       向FIFO添加多个元素
  32. * @param[in]   pFIFO: FIFO指针
  33. * @param[in]        pValues: 要添加的元素指针
  34. * @param[in]        bytesToAdd: 要添加元素的长度
  35. * @return      实际添加的元素个数
  36. *********************************************************************/
  37. unsigned int FIFO_Add(FIFO_Type *pFIFO, void *pValues, unsigned int bytesToAdd);

  38. /********************************************************************//**
  39. * @brief       从FIFO读取一个元素
  40. * @param[in]   pFIFO: FIFO指针
  41. * @param[in]        pValue: 存放要读取的元素指针
  42. * @return      1-TRUE or 0-FALSE
  43. *********************************************************************/
  44. unsigned char FIFO_GetOne(FIFO_Type *pFIFO, void *pValue);

  45. /********************************************************************//**
  46. * @brief       从FIFO读取多个元素
  47. * @param[in]   pFIFO: FIFO指针
  48. * @param[out]        pValues: 存放要读取的元素指针
  49. * @param[in]        bytesToRead: 要读取的元素长度
  50. * @return      实际读取的元素个数
  51. *********************************************************************/
  52. unsigned int FIFO_Get(FIFO_Type *pFIFO, void *pValues, unsigned int bytesToRead);


  53. /********************************************************************//**
  54. * @brief       清空FIFO
  55. * @param[in]   pFIFO: FIFO指针
  56. * @return      None
  57. *********************************************************************/
  58. void FIFO_Clear(FIFO_Type *pFIFO);


  59. unsigned char FIFO_IsEmpty(FIFO_Type *pFIFO);

  60. #endif
复制代码

② fifo.c程序主体

  1. #include <string.h>
  2. #include "fifo.h"


  3. /********************************************************************//**
  4. * @brief       FIFO初始化
  5. * @param[in]   pFIFO: FIFO指针
  6. * @param[in]        pBuff: FIFO中缓存
  7. * @param[in]        elementBytes:FIFO每个元素的字节数
  8. * @param[in]        depth: FIFO深度
  9. * @return      None
  10. *********************************************************************/
  11. void FIFO_Init(FIFO_Type *pFIFO, void *pBuff, unsigned int elementBytes, unsigned int depth)
  12. {
  13.         pFIFO->Buff = pBuff;
  14.         pFIFO->ElementBytes = elementBytes;
  15.         pFIFO->Depth = depth;
  16.         pFIFO->Head = 0;
  17.         pFIFO->Tail = 0;
  18.         pFIFO->Counter = 0;
  19. }

  20. /********************************************************************//**
  21. * @brief       判断FIFO是否为空
  22. * @param[in]   pFIFO: FIFO指针
  23. * @return      1-TRUE or 0-FALSE
  24. *********************************************************************/
  25. unsigned char FIFO_IsEmpty(FIFO_Type *pFIFO)
  26. {
  27.         return (pFIFO->Counter == 0);
  28. }

  29. /********************************************************************//**
  30. * @brief       判断FIFO是否已满
  31. * @param[in]   pFIFO: FIFO指针
  32. * @return      TRUE or FALSE
  33. *********************************************************************/
  34. unsigned char FIFO_IsFull(FIFO_Type *pFIFO)
  35. {
  36.         return (pFIFO->Counter == pFIFO->Depth);
  37. }

  38. /********************************************************************//**
  39. * @brief       向FIFO添加一个元素
  40. * @param[in]   pFIFO: FIFO指针
  41. * @param[in]        pValue: 要添加的元素
  42. * @return      1-TRUE or 0-FALSE
  43. *********************************************************************/
  44. unsigned char FIFO_AddOne(FIFO_Type *pFIFO, void *pValue)
  45. {
  46.         unsigned char *p;

  47.         if (FIFO_IsFull(pFIFO))
  48.         {
  49.                 return 0;
  50.         }

  51.         p = (unsigned char *)pFIFO->Buff;
  52.         memcpy(p + pFIFO->Tail * pFIFO->ElementBytes, (unsigned char *)pValue, pFIFO->ElementBytes);
  53.         
  54.         pFIFO->Tail ++;
  55.         if (pFIFO->Tail >= pFIFO->Depth)
  56.         {
  57.                 pFIFO->Tail = 0;
  58.         }
  59.         pFIFO->Counter ++;
  60.         return 1;
  61. }

  62. /********************************************************************//**
  63. * @brief       向FIFO添加多个元素
  64. * @param[in]   pFIFO: FIFO指针
  65. * @param[in]        pValues: 要添加的元素指针
  66. * @param[in]        bytesToAdd: 要添加元素的长度
  67. * @return      实际添加的元素个数
  68. *********************************************************************/
  69. unsigned int FIFO_Add(FIFO_Type *pFIFO, void *pValues, unsigned int bytesToAdd)
  70. {
  71.         unsigned char *p;
  72.         unsigned int cnt = 0;

  73.         p = (unsigned char *)pValues;
  74.         while(bytesToAdd --)
  75.         {
  76.                 if (FIFO_AddOne(pFIFO, p))
  77.                 {
  78.                         p += pFIFO->ElementBytes;
  79.                         cnt++;
  80.                 }
  81.                 else
  82.                 {
  83.                         break;
  84.                 }
  85.         }

  86.         return cnt;
  87. }

  88. /********************************************************************//**
  89. * @brief       从FIFO读取一个元素
  90. * @param[in]   pFIFO: FIFO指针
  91. * @param[in]        pValue: 存放要读取的元素指针
  92. * @return      1-TRUE or 0-FALSE
  93. *********************************************************************/
  94. unsigned char FIFO_GetOne(FIFO_Type *pFIFO, void *pValue)
  95. {
  96.         unsigned char *p;
  97.         if (FIFO_IsEmpty(pFIFO))
  98.         {
  99.                 return 0;
  100.         }

  101.         p = (unsigned char *)pFIFO->Buff;
  102.         memcpy(pValue, p + pFIFO->Head * pFIFO->ElementBytes, pFIFO->ElementBytes);

  103.         pFIFO->Head ++;
  104.         if (pFIFO->Head >= pFIFO->Depth)
  105.         {
  106.                 pFIFO->Head = 0;
  107.         }
  108.         pFIFO->Counter --;

  109.         return 1;
  110. }

  111. /********************************************************************//**
  112. * @brief       从FIFO读取多个元素
  113. * @param[in]   pFIFO: FIFO指针
  114. * @param[out]        pValues: 存放要读取的元素指针
  115. * @param[in]        bytesToRead: 要读取的元素长度
  116. * @return      实际读取的元素个数
  117. *********************************************************************/
  118. unsigned int FIFO_Get(FIFO_Type *pFIFO, void *pValues, unsigned int bytesToRead)
  119. {
  120.         unsigned int cnt = 0;
  121.         unsigned char *p;

  122.         p = pValues;
  123.         while(bytesToRead--)
  124.         {
  125.                 if (FIFO_GetOne(pFIFO, p))
  126.                 {
  127.                         p += pFIFO->ElementBytes;
  128.                         cnt++;
  129.                 }
  130.                 else
  131.                 {
  132.                         break;
  133.                 }
  134.         }

  135.         return cnt;
  136. }

  137. /********************************************************************//**
  138. * @brief       清空FIFO
  139. * @param[in]   pFIFO: FIFO指针
  140. * @return      None
  141. *********************************************************************/
  142. void FIFO_Clear(FIFO_Type *pFIFO)
  143. {
  144.         pFIFO->Counter = 0;
  145.         pFIFO->Head = 0;
  146.         pFIFO->Tail = 0;
  147. }
复制代码

③ 串口初始化
  1. static void MX_USART1_UART_Init(void)
  2. {
  3.   huart1.Instance = USART1;
  4.   huart1.Init.BaudRate = 9600;
  5.   huart1.Init.WordLength = UART_WORDLENGTH_8B;
  6.   huart1.Init.StopBits = UART_STOPBITS_1;
  7.   huart1.Init.Parity = UART_PARITY_NONE;
  8.   huart1.Init.Mode = UART_MODE_TX_RX;
  9.   huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  10.   huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  11.   huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  12.   huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  13.   if(HAL_UART_DeInit(&huart1) != HAL_OK)
  14.   {
  15.     Error_Handler();
  16.   }  
  17.         
  18.         if (HAL_UART_Init(&huart1) != HAL_OK)
  19.   {
  20.     Error_Handler();
  21.   }
  22.         
  23.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
  24.   /* USER CODE BEGIN USART1_Init 2 */
  25.         if(HAL_UART_Receive_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
  26.   {
  27.     Error_Handler();
  28.   }
  29.         
  30. }
复制代码

④ 接收空闲中断
  1. void USAR_UART_IDLECallback(UART_HandleTypeDef *huart)
  2. {
  3.     HAL_UART_DMAStop(&huart1);

  4.     uint8_t data_length  = RXBUFFERSIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
  5.         
  6.         FIFO_Add(pfifo, aRxBuffer, data_length);
  7.     data_length = 0;
  8.     HAL_UART_Receive_DMA(&huart1, (uint8_t*)aRxBuffer, RXBUFFERSIZE);
  9. }

  10. void USER_UART_IRQHandler(UART_HandleTypeDef *huart)
  11. {
  12.     if(USART1 == huart1.Instance)
  13.     {
  14.         if(RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
  15.         {
  16.             __HAL_UART_CLEAR_IDLEFLAG(&huart1);
  17.             USAR_UART_IDLECallback(huart);
  18.         }
  19.     }
  20. }

  21. /**
  22.   * @brief This function handles USART1 global interrupt / USART1 wake-up interrupt through EXTI line 25.
  23.   */
  24. void USART1_IRQHandler(void)
  25. {
  26.   HAL_UART_IRQHandler(&huart1);
  27.   USER_UART_IRQHandler(&huart1);
  28. }
复制代码

⑤ 主函数调用:
  1. #define TXBUFFERSIZE                    30
  2. /* Size of Reception buffer */
  3. #define RXBUFFERSIZE                    TXBUFFERSIZE
  4. #define RXFIFOBUFFERSIZE                TXBUFFERSIZE * 5


  5. uint8_t aTxBuffer[] = " ****UART_TwoBoards communication based on DMA****";

  6. /* Buffer used for reception */
  7. uint8_t aRxBuffer[RXBUFFERSIZE];

  8. uint8_t aRxFIFOBuffer[RXFIFOBUFFERSIZE];
  9. FIFO_Type        fifo;
  10. FIFO_Type        *pfifo;

  11. int main(void)
  12. {
  13.   /*此处省略硬件初始化*/
  14.   if(HAL_UART_Transmit(&huart1, (uint8_t*)aTxBuffer, TXBUFFERSIZE, 200)!= HAL_OK)
  15.   {
  16.     Error_Handler();
  17.   }
  18.         
  19.   pfifo = &fifo;

  20.   FIFO_Init(pfifo, aRxFIFOBuffer, sizeof(uint8_t), RXFIFOBUFFERSIZE);

  21.   while (1)
  22.   {
  23.         /*一次接收的缓存,重新发送*/
  24.                 if(!FIFO_IsEmpty(pfifo))
  25.                 {
  26.                         uint8_t a[100]; //存放读取fifobuffer的数据
  27.                         int i = pfifo->Counter;//先保存接收缓存的数据个数
  28.                         FIFO_Get(pfifo, &a, pfifo->Counter);
  29.                         HAL_UART_Transmit(&huart1, a, i, 200); //将接收的缓存数据再次发送,判断有无误码率
  30.                 }
  31.   }
  32. }
复制代码

测试成功!可以在主函数对数据进行处理,不用担心缓存的覆盖!

202109031459585.png


问:关于 stm32 HardFault_Handler问题处理?

ANS:

        在代码调试是,发现在执行fifo_init初始化,会进入HardFault_Handler,

20210903150306628.png


20210903150316369.png


最后,发现是在fifo_init 调用的指针,未赋地址。添加之后,解决了!
  1. pfifo = &fifo;
复制代码




收藏 评论0 发布时间:2021-11-25 15:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版