IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> stm32f0串口 DMA 空闲中断接收——基于HAL库(代码篇) -> 正文阅读

[嵌入式]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.csdn.net/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.csdn.net/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.csdn.net/download/qq_41070511/21889482

或私聊?

本人小白!望指导!(o゚v゚)ノ

参考链接:https://blog.csdn.net/a154299/article/details/86652801?spm=1001.2014.3001.5501

??????????????????https://blog.csdn.net/sea1216/article/details/104426075

? ? ? ? ? ? ? ? ?https://blog.csdn.net/xmxqiyan/article/details/43408291?utm_source=itdadao&utm_medium=referral

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-04 17:42:22  更:2021-09-04 17:42:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:57:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码