一、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,即异步串口模式 
 
 
 
1.3 配置串口参数 
 根据需要设置波特率和数据宽度等参数,在此使用 9600,8,N,1 
 
 
 
 1.4 设置DMA 
 
 
 
 1.5 添加串口中断 
 
 
 
 1.6 生成源代码。 
在界面中输入工程名,保存路径,工程 IDE 类型,点 GENERATE CODE 即可。 
 
 
 
生成代码完成后可选择打开工程。  
 
 
 
二、代码部分 
2.1  接收中断处理 
2.1.1 接收固定长度:(舍弃) 
只有接收缓存到固定长度才会触发中断 
串口接收回调函数 
 
- uint8_t aRxBuffer[RXBUFFERSIZE];
 
 - /* Size of Reception buffer */
 
 - #define RXBUFFERSIZE                    10
 
  
 
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
 
 - {
 
 -   /* Set transmission flag: trasfer complete*/
 
 -   UartrxReady = SET;
 
 -         HAL_UART_Transmit(&huart1, aRxBuffer, 10, 0x200);
 
 -         HAL_UART_Receive_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
 
 -   HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer,1);
 
  
- }
 
  
- void USART1_IRQHandler(void)
 
 - {
 
 -   HAL_UART_IRQHandler(&huart1);
 
 - }
 
  
 
- static void MX_USART1_UART_Init(void)
 
 - {
 
  
-   huart1.Instance = USART1;
 
 -   huart1.Init.BaudRate = 9600;
 
 -   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;
 
 -   huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
 
 -   huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
 
 -   if(HAL_UART_DeInit(&huart1) != HAL_OK)
 
 -   {
 
 -     Error_Handler();
 
 -   }  
 
 -         
 
 -         if (HAL_UART_Init(&huart1) != HAL_OK)
 
 -   {
 
 -     Error_Handler();
 
 -   }
 
 -         
 
 -         UartrxReady=RESET;
 
 -   /* USER CODE BEGIN USART1_Init 2 */
 
 -         if(HAL_UART_Receive_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
 
 -   {
 
 -     Error_Handler();
 
 -   }
 
 -         
 
 -   /* USER CODE END USART1_Init 2 */
 
 - }
 
  复制代码 
从串口调试助手可以看只有接收的长度 RXBUFFERSIZE为10时,才触发接收回调函数。 
 
 
  
 
2.1.2 编写空闲中断函数接收不定长 
USART1初始化: 
- static void MX_USART1_UART_Init(void)
 
 - {
 
 -   huart1.Instance = USART1;
 
 -   huart1.Init.BaudRate = 9600;
 
 -   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;
 
 -   huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
 
 -   huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
 
 -   if(HAL_UART_DeInit(&huart1) != HAL_OK)
 
 -   {
 
 -     Error_Handler();
 
 -   }  
 
 -         
 
 -         if (HAL_UART_Init(&huart1) != HAL_OK)
 
 -   {
 
 -     Error_Handler();
 
 -   }
 
  
-         __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); 
 
 -   /* USER CODE BEGIN USART1_Init 2 */
 
 -         if(HAL_UART_Receive_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
 
 -   {
 
 -     Error_Handler();
 
 -   }
 
 -         
 
 - }
 
  复制代码 
空闲中断函数:  
- #define TXBUFFERSIZE                    30
 
 - /* Size of Reception buffer */
 
 - #define RXBUFFERSIZE                    30
 
  
- void USAR_UART_IDLECallback(UART_HandleTypeDef *huart)
 
 - {
 
 -     HAL_UART_DMAStop(&huart1);
 
  
-     uint8_t data_length  = RXBUFFERSIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
 
  
 
-     HAL_UART_Transmit(&huart1,aRxBuffer,data_length,0x200);
 
  
-     memset(aRxBuffer,0x00,data_length);
 
 -     data_length = 0;
 
 -     HAL_UART_Receive_DMA(&huart1, (uint8_t*)aRxBuffer, RXBUFFERSIZE);
 
 - }
 
  
- void USER_UART_IRQHandler(UART_HandleTypeDef *huart)
 
 - {
 
 -     if(USART1 == huart1.Instance)
 
 -     {
 
 -         if(RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
 
 -         {
 
 -             __HAL_UART_CLEAR_IDLEFLAG(&huart1);
 
 -             USAR_UART_IDLECallback(huart);
 
 -         }
 
 -     }
 
 - }
 
  
- /**
 
 -   * @brief This function handles USART1 global interrupt / USART1 wake-up interrupt through EXTI line 25.
 
 -   */
 
 - void USART1_IRQHandler(void)
 
 - {
 
 -     HAL_UART_IRQHandler(&huart1);
 
 -     USER_UART_IRQHandler(&huart1);
 
 - }
 
  复制代码 
可实现不定长的接收!  
 
 
 
 注意: 
在中断中,尽量处理简单,不要做过多的处理,如发射,可以在函数外执行。 
 
 三、使用ringbuffer实现任意数据类型的FIFO处理接收数据 
使用原因: 
 
        虽然将数据保存在DMA接收缓存中,但在处理接收数据时,可能存在接收新的数据在调用数据完覆盖了接收缓存,导致调用数据时候会出现与原计划的处理不同的问题。 
 
        因此,使用ringbuffer将DMA接收缓存,以防数据的被覆盖 
 
① fifo头文件: 
- #ifndef        __FIFO_H_
 
 - #define        __FIFO_H_
 
  
- #pragma pack(4)
 
 - typedef struct FIFO_Type_STRU
 
 - {
 
 -         unsigned int                        Depth;                        // Fifo深度
 
 -         volatile unsigned int        Head;                        // Head为起始元素
 
 -         volatile unsigned int        Tail;                        // Tail-1为最后一个元素
 
 -         volatile unsigned int        Counter;                // 元素个数
 
 -         unsigned int                        ElementBytes;        // 每个元素的字节数element
 
 -         void                                        *Buff;                        // 缓存区
 
 - }FIFO_Type;
 
 - #pragma pack()
 
  
- /********************************************************************//**
 
 -  * @brief       FIFO初始化
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @param[in]        pBuff: FIFO中缓存
 
 -  * @param[in]        elementBytes:FIFO每个元素的字节数
 
 -  * @param[in]        depth: FIFO深度
 
 -  * @return      None
 
 -  *********************************************************************/
 
 - void FIFO_Init(FIFO_Type *pFIFO, void *pBuff, unsigned int elementBytes, unsigned int depth);
 
  
- /********************************************************************//**
 
 -  * @brief       向FIFO添加一个元素
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @param[in]        pValue: 要添加的元素
 
 -  * @return      1-TRUE or 0-FALSE
 
 -  *********************************************************************/
 
 - unsigned char FIFO_AddOne(FIFO_Type *pFIFO, void *pValue);
 
  
- /********************************************************************//**
 
 -  * @brief       向FIFO添加多个元素
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @param[in]        pValues: 要添加的元素指针
 
 -  * @param[in]        bytesToAdd: 要添加元素的长度
 
 -  * @return      实际添加的元素个数
 
 -  *********************************************************************/
 
 - unsigned int FIFO_Add(FIFO_Type *pFIFO, void *pValues, unsigned int bytesToAdd);
 
  
- /********************************************************************//**
 
 -  * @brief       从FIFO读取一个元素
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @param[in]        pValue: 存放要读取的元素指针
 
 -  * @return      1-TRUE or 0-FALSE
 
 -  *********************************************************************/
 
 - unsigned char FIFO_GetOne(FIFO_Type *pFIFO, void *pValue);
 
  
- /********************************************************************//**
 
 -  * @brief       从FIFO读取多个元素
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @param[out]        pValues: 存放要读取的元素指针
 
 -  * @param[in]        bytesToRead: 要读取的元素长度
 
 -  * @return      实际读取的元素个数
 
 -  *********************************************************************/
 
 - unsigned int FIFO_Get(FIFO_Type *pFIFO, void *pValues, unsigned int bytesToRead);
 
  
 
- /********************************************************************//**
 
 -  * @brief       清空FIFO
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @return      None
 
 -  *********************************************************************/
 
 - void FIFO_Clear(FIFO_Type *pFIFO);
 
  
 
- unsigned char FIFO_IsEmpty(FIFO_Type *pFIFO);
 
  
- #endif
 
  复制代码 
② fifo.c程序主体 
 
- #include <string.h>
 
 - #include "fifo.h"
 
  
 
- /********************************************************************//**
 
 -  * @brief       FIFO初始化
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @param[in]        pBuff: FIFO中缓存
 
 -  * @param[in]        elementBytes:FIFO每个元素的字节数
 
 -  * @param[in]        depth: FIFO深度
 
 -  * @return      None
 
 -  *********************************************************************/
 
 - void FIFO_Init(FIFO_Type *pFIFO, void *pBuff, unsigned int elementBytes, unsigned int depth)
 
 - {
 
 -         pFIFO->Buff = pBuff;
 
 -         pFIFO->ElementBytes = elementBytes;
 
 -         pFIFO->Depth = depth;
 
 -         pFIFO->Head = 0;
 
 -         pFIFO->Tail = 0;
 
 -         pFIFO->Counter = 0;
 
 - }
 
  
- /********************************************************************//**
 
 -  * @brief       判断FIFO是否为空
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @return      1-TRUE or 0-FALSE
 
 -  *********************************************************************/
 
 - unsigned char FIFO_IsEmpty(FIFO_Type *pFIFO)
 
 - {
 
 -         return (pFIFO->Counter == 0);
 
 - }
 
  
- /********************************************************************//**
 
 -  * @brief       判断FIFO是否已满
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @return      TRUE or FALSE
 
 -  *********************************************************************/
 
 - unsigned char FIFO_IsFull(FIFO_Type *pFIFO)
 
 - {
 
 -         return (pFIFO->Counter == pFIFO->Depth);
 
 - }
 
  
- /********************************************************************//**
 
 -  * @brief       向FIFO添加一个元素
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @param[in]        pValue: 要添加的元素
 
 -  * @return      1-TRUE or 0-FALSE
 
 -  *********************************************************************/
 
 - unsigned char FIFO_AddOne(FIFO_Type *pFIFO, void *pValue)
 
 - {
 
 -         unsigned char *p;
 
  
-         if (FIFO_IsFull(pFIFO))
 
 -         {
 
 -                 return 0;
 
 -         }
 
  
-         p = (unsigned char *)pFIFO->Buff;
 
 -         memcpy(p + pFIFO->Tail * pFIFO->ElementBytes, (unsigned char *)pValue, pFIFO->ElementBytes);
 
 -         
 
 -         pFIFO->Tail ++;
 
 -         if (pFIFO->Tail >= pFIFO->Depth)
 
 -         {
 
 -                 pFIFO->Tail = 0;
 
 -         }
 
 -         pFIFO->Counter ++;
 
 -         return 1;
 
 - }
 
  
- /********************************************************************//**
 
 -  * @brief       向FIFO添加多个元素
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @param[in]        pValues: 要添加的元素指针
 
 -  * @param[in]        bytesToAdd: 要添加元素的长度
 
 -  * @return      实际添加的元素个数
 
 -  *********************************************************************/
 
 - unsigned int FIFO_Add(FIFO_Type *pFIFO, void *pValues, unsigned int bytesToAdd)
 
 - {
 
 -         unsigned char *p;
 
 -         unsigned int cnt = 0;
 
  
-         p = (unsigned char *)pValues;
 
 -         while(bytesToAdd --)
 
 -         {
 
 -                 if (FIFO_AddOne(pFIFO, p))
 
 -                 {
 
 -                         p += pFIFO->ElementBytes;
 
 -                         cnt++;
 
 -                 }
 
 -                 else
 
 -                 {
 
 -                         break;
 
 -                 }
 
 -         }
 
  
-         return cnt;
 
 - }
 
  
- /********************************************************************//**
 
 -  * @brief       从FIFO读取一个元素
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @param[in]        pValue: 存放要读取的元素指针
 
 -  * @return      1-TRUE or 0-FALSE
 
 -  *********************************************************************/
 
 - unsigned char FIFO_GetOne(FIFO_Type *pFIFO, void *pValue)
 
 - {
 
 -         unsigned char *p;
 
 -         if (FIFO_IsEmpty(pFIFO))
 
 -         {
 
 -                 return 0;
 
 -         }
 
  
-         p = (unsigned char *)pFIFO->Buff;
 
 -         memcpy(pValue, p + pFIFO->Head * pFIFO->ElementBytes, pFIFO->ElementBytes);
 
  
-         pFIFO->Head ++;
 
 -         if (pFIFO->Head >= pFIFO->Depth)
 
 -         {
 
 -                 pFIFO->Head = 0;
 
 -         }
 
 -         pFIFO->Counter --;
 
  
-         return 1;
 
 - }
 
  
- /********************************************************************//**
 
 -  * @brief       从FIFO读取多个元素
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @param[out]        pValues: 存放要读取的元素指针
 
 -  * @param[in]        bytesToRead: 要读取的元素长度
 
 -  * @return      实际读取的元素个数
 
 -  *********************************************************************/
 
 - unsigned int FIFO_Get(FIFO_Type *pFIFO, void *pValues, unsigned int bytesToRead)
 
 - {
 
 -         unsigned int cnt = 0;
 
 -         unsigned char *p;
 
  
-         p = pValues;
 
 -         while(bytesToRead--)
 
 -         {
 
 -                 if (FIFO_GetOne(pFIFO, p))
 
 -                 {
 
 -                         p += pFIFO->ElementBytes;
 
 -                         cnt++;
 
 -                 }
 
 -                 else
 
 -                 {
 
 -                         break;
 
 -                 }
 
 -         }
 
  
-         return cnt;
 
 - }
 
  
- /********************************************************************//**
 
 -  * @brief       清空FIFO
 
 -  * @param[in]   pFIFO: FIFO指针
 
 -  * @return      None
 
 -  *********************************************************************/
 
 - void FIFO_Clear(FIFO_Type *pFIFO)
 
 - {
 
 -         pFIFO->Counter = 0;
 
 -         pFIFO->Head = 0;
 
 -         pFIFO->Tail = 0;
 
 - }
 
  复制代码 
 ③ 串口初始化 
- static void MX_USART1_UART_Init(void)
 
 - {
 
 -   huart1.Instance = USART1;
 
 -   huart1.Init.BaudRate = 9600;
 
 -   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;
 
 -   huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
 
 -   huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
 
 -   if(HAL_UART_DeInit(&huart1) != HAL_OK)
 
 -   {
 
 -     Error_Handler();
 
 -   }  
 
 -         
 
 -         if (HAL_UART_Init(&huart1) != HAL_OK)
 
 -   {
 
 -     Error_Handler();
 
 -   }
 
 -         
 
 -         __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); 
 
 -   /* USER CODE BEGIN USART1_Init 2 */
 
 -         if(HAL_UART_Receive_DMA(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
 
 -   {
 
 -     Error_Handler();
 
 -   }
 
 -         
 
 - }
 
  复制代码 
 ④ 接收空闲中断 
- void USAR_UART_IDLECallback(UART_HandleTypeDef *huart)
 
 - {
 
 -     HAL_UART_DMAStop(&huart1);
 
  
-     uint8_t data_length  = RXBUFFERSIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
 
 -         
 
 -         FIFO_Add(pfifo, aRxBuffer, data_length);
 
 -     data_length = 0;
 
 -     HAL_UART_Receive_DMA(&huart1, (uint8_t*)aRxBuffer, RXBUFFERSIZE);
 
 - }
 
  
- void USER_UART_IRQHandler(UART_HandleTypeDef *huart)
 
 - {
 
 -     if(USART1 == huart1.Instance)
 
 -     {
 
 -         if(RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
 
 -         {
 
 -             __HAL_UART_CLEAR_IDLEFLAG(&huart1);
 
 -             USAR_UART_IDLECallback(huart);
 
 -         }
 
 -     }
 
 - }
 
  
- /**
 
 -   * @brief This function handles USART1 global interrupt / USART1 wake-up interrupt through EXTI line 25.
 
 -   */
 
 - void USART1_IRQHandler(void)
 
 - {
 
 -   HAL_UART_IRQHandler(&huart1);
 
 -   USER_UART_IRQHandler(&huart1);
 
 - }
 
  复制代码 
⑤ 主函数调用: 
- #define TXBUFFERSIZE                    30
 
 - /* Size of Reception buffer */
 
 - #define RXBUFFERSIZE                    TXBUFFERSIZE
 
 - #define RXFIFOBUFFERSIZE                TXBUFFERSIZE * 5
 
  
 
- uint8_t aTxBuffer[] = " ****UART_TwoBoards communication based on DMA****";
 
  
- /* Buffer used for reception */
 
 - uint8_t aRxBuffer[RXBUFFERSIZE];
 
  
- uint8_t aRxFIFOBuffer[RXFIFOBUFFERSIZE];
 
 - FIFO_Type        fifo;
 
 - FIFO_Type        *pfifo;
 
  
- int main(void)
 
 - {
 
 -   /*此处省略硬件初始化*/
 
 -   if(HAL_UART_Transmit(&huart1, (uint8_t*)aTxBuffer, TXBUFFERSIZE, 200)!= HAL_OK)
 
 -   {
 
 -     Error_Handler();
 
 -   }
 
 -         
 
 -   pfifo = &fifo;
 
  
-   FIFO_Init(pfifo, aRxFIFOBuffer, sizeof(uint8_t), RXFIFOBUFFERSIZE);
 
  
-   while (1)
 
 -   {
 
 -         /*一次接收的缓存,重新发送*/
 
 -                 if(!FIFO_IsEmpty(pfifo))
 
 -                 {
 
 -                         uint8_t a[100]; //存放读取fifobuffer的数据
 
 -                         int i = pfifo->Counter;//先保存接收缓存的数据个数
 
 -                         FIFO_Get(pfifo, &a, pfifo->Counter);
 
 -                         HAL_UART_Transmit(&huart1, a, i, 200); //将接收的缓存数据再次发送,判断有无误码率
 
 -                 }
 
 -   }
 
 - }
 
  复制代码 
测试成功!可以在主函数对数据进行处理,不用担心缓存的覆盖!  
 
 
 
问:关于 stm32 HardFault_Handler问题处理? 
 
ANS: 
 
        在代码调试是,发现在执行fifo_init初始化,会进入HardFault_Handler, 
 
 
 
 
 
 最后,发现是在fifo_init 调用的指针,未赋地址。添加之后,解决了! 
 
 
 
 
 |