目录
三、使用ringbuffer实现任意数据类型的FIFO处理接收数据
一、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 即可。
生成代码完成后可选择打开工程。
二、代码部分
对于芯片的 外设,最好的办法就是去官方查看官方发布的参考例子:
官方关于STM32CubeF0的例子:https://github.com/STMicroelectronics/STM32CubeF0
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接收缓存,以防数据的被覆盖
参考:https://blog.youkuaiyun.com/xmxqiyan/article/details/43408291?utm_source=itdadao&utm_medium=referral
① 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 调用的指针,未赋地址。添加之后,解决了!
pfifo = &fifo;
代码获取:https://download.youkuaiyun.com/download/qq_41070511/21889482
或私聊
本人小白!望指导!(o゚v゚)ノ
参考链接:https://blog.youkuaiyun.com/a154299/article/details/86652801?spm=1001.2014.3001.5501
https://blog.youkuaiyun.com/sea1216/article/details/104426075
https://blog.youkuaiyun.com/xmxqiyan/article/details/43408291?utm_source=itdadao&utm_medium=referral