目录
一、参考文档
二、源代码
三、结构说明
四、原理讲解
五、代码讲解
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(使用前将#替换为@)