HAL库+环形队列(CFIFO)+Usart1+DMA数据缓存收发

2023-05-16

目录

一、参考文档

二、源代码

三、结构说明

四、原理讲解

五、代码讲解

4.1循环队列(CFIFO)代码

4.1.1:cifio.h

4.1.1:cifio.c

4.2循环队列(CFIFO)+DMA实现USART1数据收发

4.2.1:cfifo_usart_dma.h

4.2.1:cfifo_usart_dma.c


一、参考文档


1、HAL库版DMA循环模式串口数据收发

2、STM32进阶之串口环形缓冲区实现

配合上述参考文档,能更好理解本文章!!!


二、源代码

源代码工程:CFIFO_DMA_USART_HAL


三、结构说明

暂无

 

四、原理讲解

暂无

 

五、代码讲解

4.1循环队列(CFIFO)代码

4.1.1:cifio.h

#ifndef _CFIFO_H_
#define _CFIFO_H_

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
/* USER CODE END Includes */

/* USER CODE BEGIN Private defines */

#define CFIFO_SIZE 1024           //环形队列CFIFO大小


/*环形CFIFO结构体*/
typedef struct
{
	uint16_t Head;       //环形CFIFO队列头
	uint16_t Tail;	     //环形CFIFO队列尾
    uint16_t Lenght;     //环形CFIFO数据长度
	uint8_t  BUFF[CFIFO_SIZE];     //环形CFIFO缓存区
}CfifoBuff;


/* USER CODE END Private defines */


/* USER CODE BEGIN Prototypes */
void CfifoBuff_Init(CfifoBuff * Cfifo_pointer);  //CFIFO初始化
void CfifoBuff_Clear(CfifoBuff * Cfifo_pointer); //CFIFO数据清除
int16_t CfifoBuff_Write(CfifoBuff * Cfifo_pointer,char * User_buff,uint16_t num); //CFIFO数据写人
int16_t CfifoBuff_Read(CfifoBuff * Cfifo_pointer,char * User_buff,uint16_t num); //CFIFO数据读出
/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* _CFIFO_H_ */


4.1.1:cifio.c

#include "cfifo.h"


/*环形CFIFO初始化*/
void CfifoBuff_Init(CfifoBuff * Cfifo_pointer)
{
   //初始化相关信息
   Cfifo_pointer->Head = 0;
   Cfifo_pointer->Tail = 0;
   Cfifo_pointer->Lenght = 0;
   memset(Cfifo_pointer->BUFF,'\0',CFIFO_SIZE);  //环形CFIFO缓存区初始化
}

/*环形CFIFO数据清除*/
void CfifoBuff_Clear(CfifoBuff * Cfifo_pointer)
{
   //清除相关信息
   Cfifo_pointer->Head = 0;
   Cfifo_pointer->Tail = 0;
   Cfifo_pointer->Lenght = 0;
   memset(Cfifo_pointer->BUFF,'\0',CFIFO_SIZE); //环形CFIFO缓存区清除
}



/*环形CFIFO数据写入*/
/*
*参数说明:
*         Cfifo_pointer————环形CFIFO结构体
*         User_buff————待写入数据
*         num————写入数据长度
*
*返回值说明:正确写入到FIFO缓存区中的数据长度
*
*功能说明:将User_buff中的数据写入到环形CFIFO缓存区
*
*/
int16_t CfifoBuff_Write(CfifoBuff * Cfifo_pointer,char * User_buff,uint16_t num)
{
	int16_t i , wrint_num;
	
    if(Cfifo_pointer->Lenght >= CFIFO_SIZE) //判断缓存区是否已满
    {
		 wrint_num=-1;
		 
         return wrint_num;       //数据溢出
    }
		
    if(Cfifo_pointer->Lenght+num<CFIFO_SIZE)  //判断写入的数据长度是否超出当前可写入的最大值
	{
		wrint_num=num;
	}
	else
	{
		wrint_num=CFIFO_SIZE-Cfifo_pointer->Lenght;	  
	}
		
	for(i=0;i<wrint_num;i++)
	{
	    Cfifo_pointer->BUFF[Cfifo_pointer->Tail]=*(User_buff+i);
			
		Cfifo_pointer->Tail = (Cfifo_pointer->Tail+1)%CFIFO_SIZE;//防止越界非法访问
	}	
		
    Cfifo_pointer->Lenght+=wrint_num;
		
    return wrint_num;  //返回正确写入的数据长度
}


/*环形CFIFO读取*/
/*
*参数说明:
*         Cfifo_pointer————环形CFIFO结构体
*         User_buff————读取数据存放地
*         num————读取数据长度
*
*返回值说明:正确读取到User_buff的数据长度
*
*功能说明:将环形CFIFO缓存区的数据读取到User_buff
*
*/
int16_t CfifoBuff_Read(CfifoBuff * Cfifo_pointer,char * User_buff,uint16_t num)
{
	int16_t i , read_num;
	
    if(Cfifo_pointer->Lenght == 0) //判断非空
    {
        read_num=-1;
		 
        return read_num;       //没有数据
    }	
	
   if(Cfifo_pointer->Lenght-num>=0)       //判断读取的数据长度是否超出当前可读取的最大值
   {
		read_num=num;
   }
   else
   {
    	read_num=Cfifo_pointer->Lenght;	  
   }
		
   for(i=0;i<read_num;i++)
   {
	    *(User_buff+i)=Cfifo_pointer->BUFF[Cfifo_pointer->Head];
			
		Cfifo_pointer->Head = (Cfifo_pointer->Head+1)%CFIFO_SIZE;//防止越界非法访问
   }	
		
    Cfifo_pointer->Lenght-=read_num;
		
    return read_num;  //返回正确写入的数据长度
		
}



4.2循环队列(CFIFO)+DMA实现USART1数据收发

4.2.1:cfifo_usart_dma.h

#ifndef _CFIFO_USART_DMA_H_
#define _CFIFO_USART_DMA_H_

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
#include "cfifo.h"
/* USER CODE END Includes */

/* USER CODE BEGIN Private defines */


/* USER CODE END Private defines */
typedef struct 
{ 
	 UART_HandleTypeDef  *handle;    /*HAL库提供的串口句柄*/
	 int16_t TransFlag;              /*数据发送标志位*/      
	 int32_t DmaSize;                /*DMA缓冲区的大小*/
	 int32_t DamOffset;              /*获取数据在DMA缓冲区的偏移量*/
	 uint8_t *pReadDma;              /*指向接收DMA缓冲区的首地址*/
	 uint8_t *pWriteDma;             /*指向发送DMA缓冲区的首地址*/
	 CfifoBuff AcceptCFifo;          /*接受数据的循环缓冲区*/
	 CfifoBuff SendCFifo;            /*发送数据的循环缓冲区*/
}MW_UART_ATTR;	


/* USER CODE BEGIN Prototypes */
int8_t MW_UART_Init(UART_HandleTypeDef *handle);        //初始化
void MW_UART_IRQHandler(UART_HandleTypeDef *huart);     //串口中断中调用
int32_t MW_UART_Transmit(uint8_t* buffer,int32_t len);  //CFIFO+DMA+Usart数据发送
/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif
#endif /* _CFIFO_USART_DMA_H_ */

4.2.1:cfifo_usart_dma.c

#include "cfifo_usart_dma.h"

#define MW_FAIL              0
#define MW_SUCCESS           1

#define MW_TRANS_IDLE        0
#define MW_TRANS_BUSY        1

#define MW_UART_DMA_LEN      256


static uint8_t Uart1TxDma[MW_UART_DMA_LEN] = {0};	//DMA发送缓存区
static uint8_t Uart1RxDma[MW_UART_DMA_LEN] = {0}; //DMA接受缓存区

static MW_UART_ATTR sUartAttr;

int8_t MW_UART_Init(UART_HandleTypeDef *handle)
{ 
  /*为属性的参数附初值*/
	MW_UART_ATTR *pUartAttr = &sUartAttr;	
	pUartAttr->handle = handle;
	pUartAttr->DamOffset = 0;
	pUartAttr->TransFlag = MW_TRANS_IDLE;
	pUartAttr->DmaSize = MW_UART_DMA_LEN;
	pUartAttr->pReadDma = Uart1RxDma;
	pUartAttr->pWriteDma = Uart1TxDma;
	CfifoBuff_Init(&pUartAttr->AcceptCFifo);  //用于数据接受
	CfifoBuff_Init(&pUartAttr->SendCFifo);    //用于数据发送
		
	/*配置DMA参数并使能中断*/
	if(HAL_OK != HAL_UART_Receive_DMA(pUartAttr->handle, pUartAttr->pReadDma, MW_UART_DMA_LEN))
	{
		return MW_FAIL;
	}
  
	/*使能串口空闲中断*/
	__HAL_UART_ENABLE_IT(handle, UART_IT_IDLE);
	
	return MW_SUCCESS;
}

//串口空闲中断函数处理
void MW_UART_IRQHandler(UART_HandleTypeDef *huart)
{
	int32_t RecvNum = 0;
	int32_t WriteNum = 0;
	int32_t DmaIdleNum = 0;
	
	MW_UART_ATTR *pUartAttr = &sUartAttr;

	if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
	{
    /*清除空闲中断标识位,重新接受串口空闲中断*/ 
		__HAL_UART_CLEAR_IDLEFLAG(huart);

		/*计算在DMA缓冲区需要获取的数据长度*/
		DmaIdleNum = __HAL_DMA_GET_COUNTER(huart->hdmarx);
		RecvNum = pUartAttr->DmaSize - DmaIdleNum - pUartAttr->DamOffset;
		/*将获取到的数据放到数据接收缓冲区中*/                                           
		WriteNum = CfifoBuff_Write(&pUartAttr->AcceptCFifo,(char *)(pUartAttr->pReadDma + pUartAttr->DamOffset),RecvNum);
		
		if(WriteNum != RecvNum)
		{
			printf("Uart ReadFifo is not enough\r\n");
		}
                /*计算获取数据位置的偏移量*/
		pUartAttr->DamOffset += RecvNum;
		
		printf("%s",sUartAttr.AcceptCFifo.BUFF);
		
		CfifoBuff_Clear(&sUartAttr.AcceptCFifo);
	}
	
}	

//DMA接受完成中断调用
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{			
	int32_t DmaLen = 0;
	int32_t WriteNum = 0;
	MW_UART_ATTR *pUartAttr = &sUartAttr;

	/*计算需要获取数据的长度*/
	DmaLen = pUartAttr->DmaSize - pUartAttr->DamOffset;
	/*将获取的数据存放到数据缓冲区中*/
	WriteNum = CfifoBuff_Write(&pUartAttr->AcceptCFifo,(char *)(pUartAttr->pReadDma + pUartAttr->DamOffset),DmaLen);

	if(WriteNum != DmaLen)
	{
		printf("Uart ReadFifo is not enough\r\n");
	}
        /*复位DMA偏移量*/
	pUartAttr->DamOffset = 0;
	
}


//CFIFO_DMA_USART数据发送
int32_t MW_UART_Transmit(uint8_t* buffer,int32_t len)
{
	int32_t TransNum = 0;
	int32_t TransLen = 0;
	MW_UART_ATTR *pUartAttr = &sUartAttr;
	/*将要发送的数据先写入循环缓冲区*/
	TransNum = CfifoBuff_Write(&pUartAttr->SendCFifo, (char *) buffer, len);

	/*如果发送DMA未在发送中,则使能发送*/
	if(pUartAttr->TransFlag == MW_TRANS_IDLE)
	{
		TransLen = CfifoBuff_Read(&pUartAttr->SendCFifo,(char *)(pUartAttr->pWriteDma),pUartAttr->DmaSize);
		if(TransLen > 0)
		{
			pUartAttr->TransFlag = MW_TRANS_BUSY;
			if(HAL_OK != HAL_UART_Transmit_DMA(pUartAttr->handle,pUartAttr->pWriteDma,TransLen))
			{
				printf("Uart Trans_DMA failed\r\n");
			}
		}					
	}

	return TransNum;
}


//DMA发送完成中断调用
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	int32_t TransNum = 0;
	MW_UART_ATTR *pUartAttr = &sUartAttr;

	/*从发送循环缓冲区中获取数据*/
	TransNum = CfifoBuff_Read(&pUartAttr->SendCFifo,(char *)(pUartAttr->pWriteDma),pUartAttr->DmaSize);
	if(TransNum > 0)
	{		
		if(HAL_OK != HAL_UART_Transmit_DMA(pUartAttr->handle,pUartAttr->pWriteDma,TransNum))
		{
			printf("Uart Trans_DMA failed\r\n");
		}
	}
	else
	{
		pUartAttr->TransFlag = MW_TRANS_IDLE;
	}
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HAL库+环形队列(CFIFO)+Usart1+DMA数据缓存收发 的相关文章

  • 继承,static关键字,abstract,单例模式

    1 为什么要有类的继承性 类的继承性可以减少代码冗余度 xff0c 提高代码复用性 xff0c 提高代码操作效率 2 继承的格式 xff08 语法 xff09 子类 extends 父类 3 子类继承父类后有哪些不同 子类范围大于父类 xf
  • KVM详解(一)——KVM基础知识

    今天继续给大家介绍Linux运维相关知识 xff0c 本文主要内容是KVM的基础知识 一 虚拟化简介 xff08 一 xff09 虚拟化概述 在计算机中 xff0c 虚拟化技术是一种资源管理技术 xff0c 可以将计算机的各硬件资源 xff
  • Linux桌面图形化安装详解

    今天继续给大家介绍Linux相关知识 xff0c 本文主要内容是Linux xff08 CentOS7 xff09 图形化GUI页面安装详解 一 Linux GUI图形化页面简介 尽管在运维工作中 xff0c 我们很少在Linux上安装图形
  • 【MediaSoup c#】 worker的创建

    js rust 不太熟 c 似乎还好懂一些 学习media soup 的各个组件及大体使用方式 学习其设计理念 MediasoupServer 管理worker列表 worker的表达是通过 IWorker 抽象类 拥有一个observer
  • KVM详解(三)——KVM创建虚拟机

    今天继续给大家介绍Linux运维相关知识 xff0c 本文主要内容是在KVM上创建虚拟机 一 安装准备 在前文KVM详解 xff08 二 xff09 KVM安装部署中 xff0c 我们安装了KVM 今天 xff0c 我们就来创建一个KVM的
  • KVM详解(九)——CentOS6虚拟机关机失败问题解决

    今天继续给大家介绍Linux运维相关知识 xff0c 本文主要内容是CentOS6虚拟机关机失败问题解决 一 问题描述 当我们使用KVM安装CentOS6系统后 xff0c 会发现一个问题 xff0c 即无法通过virsh shutdown
  • Python循环结构详解

    今天继续给大家介绍Python相关知识 xff0c 本文主要内容是Python循环结构 循环是一种编程语言的重要结构 xff0c 在Python中 xff0c 存在着两种循环 xff0c 一种是遍历循环 xff0c 一种是while循环 一
  • Ubuntu配置sudo命令不需要输入密码

    执行以下命令 xff1a span class token function sudo span visudo span class token comment sudo visudo默认使用的编辑器是nano xff0c 使用上下键移动
  • 智慧社区信息管理系统的设计与实现(论文打包下载)

    摘 要 近几年来 xff0c 随着网上支付方式的普及 xff0c 越来越多的人选择使用网上支付 xff0c 但由于网上支付的方式还未普及到生活的各方面 xff0c 因此本系统的完成将为物业小区提供合理的线上管理模式 xff0c 代替传统的线
  • vsftp配置详解篇

    在配置安装vsftpd过程中 xff0c 我遇到了很多坑 xff1f 查了上百篇博客 xff0c 才把这些坑一一填满 这里记录是为了方便后来者查阅 xff0c 我也是个小白 有问题请不要客气 xff0c 直接喷就是了 xff01 vsftp
  • RNN构建语言模型(用前一个单词预测下一个单词)

    训练RNN的时候 xff0c 根据反向传播 xff0c 梯度会不断相乘 xff0c 很容易出现梯度消失和梯度爆炸 通常的解决方法 xff1a 对于梯度爆炸 xff1a Gradient Clipping xff1a 如果梯度太大就把它往下卡
  • pytorch中使用tensorboard绘制Accuracy/Loss曲线(train和test显示在同一幅图中)

    因为tensorboard可以在同一幅图中显示不同文件夹下的曲线 xff0c 所以将train和test分别存到不同的文件夹里就可以在同一副图中展示 xff0c 简要记录代码 from torch utils tensorboard imp
  • Android Studio 查看当前显示的 activity

    在修复bug时 xff0c 首先需要定位到是哪个activity出现的问题 xff0c 这时可以使用adb工具 abd工具在SDK目录下的platform tools文件夹下 1 打开Android Studio的Terminal xff0
  • MyBatis:使用MyBatis Generator快速完成Springboot项目数据层开发

    使用场景 当我们使用Springboot整合Mybatis时 xff0c 我们就需要为数据库中的每一个表分别写出 xff1a 实体类Mapper xml文件Mapper接口 如果数据库中有很多表 xff0c 这个过程就会非常的繁琐 而MyB
  • 【MediaSoup】mediasoup-sfu-cpp : demo 和MediaSoup实例

    MediaSoup mediasoup sfu cpp vs2022 构建 完成了构建 下面分析其线程模型 main 进程 创建一个独立server线程支持ws 作为一个oatpp的组件存在 D span class token punct
  • “jar中没有主清单属性”问题的解决方法

    今天想要把springboot项目打成jar包部署在服务器上 xff0c 但是在使用 java jar XXX 指令时遇到了 jar中没有主清单属性 的问题 在官网上看到这样一段话 xff0c 发现是因为pom文件里没有加上repackag
  • 《Java高并发程序设计》阅读笔记

    第一章 1 同步和异步 2 并发和并行 3 临界区 xff1a 表示一种公共资源 xff0c 可以被多个线程使用 xff0c 但是每一次只能有一个线程使用它 xff0c 一旦临界区资源被占用 xff0c 其他线程想要使用这个资源就必须等待
  • Android生物认证Biometric 四十行代码轻松实现面部识别、指纹认证

    Biometric Biometric是谷歌官方提供的生物识别验证类库 xff0c 能调用包括目前Android设备上搭载的指纹 人脸 虹膜等系统级的生物认证 xff08 目前大多数的国内定制ROM可能因为安全问题 xff0c 仅支持指纹
  • Excel 文件导出,兼容IE(web前后台导出方法)

    Excel 文件导出 前台导出 前台导出是指使用前台页面的数据导出到本地文件 XML文件和Excel文件之间可以相互转换 xff0c 因此可将 XML 数据从 Web 服务中导入到 Excel 工作表中 使用隐藏的Table存放需要导出的数
  • ftp——java上传总是返回false

    由于目录权限的问题 权限改为777 xff0c 则上传成功

随机推荐