stm32f0串口 DMA 空闲中断接收——基于HAL库(代码篇)

目录

一、STM32CubeMX开发

1.1 新建工程

1.2 配置 USART1

1.3 配置串口参数

1.4 设置DMA

1.5 添加串口中断

1.6 生成源代码。

二、代码部分

2.1  接收中断处理

2.1.1 接收固定长度:(舍弃)

2.1.2 编写空闲中断函数接收不定长

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

① fifo头文件:

② fifo.c程序主体

③ 串口初始化

④ 接收空闲中断

⑤ 主函数调用:


一、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://blog.youkuaiyun.com/u013184273/article/details/84440177?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1.essearch_pc_relevant&spm=1001.2101.3001.4242

代码获取: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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值