stm32f407实现DMA+串口中断接收不定长数据实验

1.前言

学习大佬成为大佬

http://t.csdnimg.cn/P7JiC

如果能仔细看完这篇博客基本上DMA就能懂个大致了

因为刚开始学,很多东西还不懂,尤其很东西学了就忘所以写这篇博客,做个笔记。

由于是从串口一步步学到DMA,程序内容也是这个顺序,所以博客也按照这个顺序来写

2.串口

上一篇笔记已经写了关于串口的收发实验是如何实现的,这里就不过多赘述了

3.DMA

其实单从这个图来看,即使作为一个新人也感觉挺好理解的。诸多个外设在各自通道上对DMA发出传输数据的请求,这些请求经过仲裁器处理,判断各个请求处理的先后顺序,随后向外设做出应答,此时请求优先级的外设接收到“允许”的指令后,便开始准备好数据传输。

DMA便开始从外设中搬运数据至另一个外设(这里可以把内部ram也理解为外设)。与F1稍有不同的是F4好像在中间环节多出了4个字节的fifo,其实这里我感觉略显鸡肋(观众老爷们如果有高见,欢迎批评指正)。所以我不打算用F4自带的这个fifo

好在官方也是很有远见,并不锁死非得用它的fifo。只要一次性处理数据足够多,而且时间足够长这个容量的fifo是肯定不够用的。

看过上面那个图之后,再加上这个图,那么DMA传输数据的一个结构就大概能了解了。

至于为什么要用DMA,或者换个问法,用DMA搬运数据和正常CPU搬运数据有什么区别,其实网上很多博文都讲了,说实话看个大概是能看的,但是俗话说,绝知此事要躬行,没有真正去做一些实验啥的还是不好去体会。

这里附个链接:http://t.csdnimg.cn/cA4xh

但是上个实验代码(http://t.csdnimg.cn/u3t7g,用串口实现一个最起码不丢数据的收发实验)来看,在只用CPU来处理数据的情况下,如果为了不丢数据,就会丢失实时性。当然这两个要求很难真正完全意义上的同时保证(以我现在水平难以做到),但是运用DMA的话,我可以向着这个目标往前多走几步。

划重点:::其实将通俗点,DMA就是一个无情的搬运工,只要你设置好了它的参数,它不管你的CPU在进行什么进程,只要有请求传出,它就开始搬运。只要参数设置的足够好,用DMA能省心省力。

至于DMA的工作模式,寻址,指针递增等,这里就不介绍了,参考手册都有。

但是这里有个地方值得一看:

一开始看的博文<一个严谨的STM32... ...>这个博主就是用的双缓冲模式来进行数据的正常传输,真的好用。

后面我会先不用F4的双缓冲区模式来写,就假设没有这个模块。完事再用这个双缓冲区模式来写写试试。欢迎批评指正。

代码部分

1.串口部分代码

#include "bsp_usart.h"



static void Usart_Gpio_Config(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);

	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
	
	GPIO_InitTypeDef    GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;     //USART1的输出为gpioa_9
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure); 
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;     //USART1的输入为gpioa_10
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);  	

}

static void Usart_NVIC_Config(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
	NVIC_InitTypeDef  NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStructure);
}



void Usart_config(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    
	USART_InitTypeDef       USART_InitStructure;
	USART_InitStructure.USART_BaudRate=115200;
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
	USART_InitStructure.USART_Parity=USART_Parity_No;
	USART_InitStructure.USART_StopBits=USART_StopBits_1;
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;
    USART_Init(USART1, &USART_InitStructure);

    Usart_Gpio_Config();
	Usart_NVIC_Config();
	

	USART_ITConfig(USART1,USART_IT_IDLE, ENABLE);
	clear_IT_IDLE();
	
    USART_Cmd(USART1, ENABLE);
}

void clear_IT_IDLE(void)
{
	USART_GetFlagStatus(USART1, USART_FLAG_IDLE);
	USART_ReceiveData(USART1);
}

double power(double a, double b)
{
	double result = 1;
	for(int i=0;i<b;i++)
	{
		result *= a;
	}
	return result;
}

void Usart1_SendByte(uint8_t data)
{
	if(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==1)
	{
       USART_SendData(USART1, data);
	   while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==0);
	}
}

void Usart1_SendNumber(uint32_t data)
{
	uint8_t count = 0;
	uint8_t i = 0;
	uint8_t num;
	uint8_t sector;
	while(data % (int)(power(10, count) )!= data)
	{
		count++;
	}
	 num = count-1;
	for (i = 0; i < count; i++)
	{
		sector = (data / (int)power(10, num));
		Usart1_SendByte(sector);
		data = data - (int)power(10, num)*sector;
		num--;
	}
}

void Usart1_SendNumber_16(uint32_t data)
{
	uint8_t count = 0;
	uint8_t i = 0;
	uint8_t num;
	uint8_t sector;
	while(data % (int)(power(10, count) )!= data)
	{
		count++;
	}
	 num = count-1;
	for (i = 0; i < count; i++)
	{
		sector = (data / (int)power(10, num));
		Usart1_SendByte(30+sector);
		data = data - (int)power(10, num)*sector;
		num--;
	}
}

void Usart1_SendArray(uint8_t arr[],uint16_t ArrayLength)
{
	uint16_t i=0;
	for(i=0;i<ArrayLength;i++)
	{
	   Usart1_SendByte(arr[i]);
    }
}

这部分代码与之前笔记里的串口发送接收代码并没有太多差异,只是:1.这里是使用DMA进行发送,所以就不需要串口非空中断了,2.就是额外写了一些发送函数,毕竟之前写的串口发送函数是以一个字节为单位进行发送,也就是说最大能发送的数字也就是255,限制性太强,调试的时候想要查看中间量,或者查看地址都极其不方便。

2.DMA部分

像我这种初学者刚开始接触这些多文件的实验的时候,很容易懵逼,所以还是先捋捋思路。

这就是本套实验的处理数据的逻辑。

需注意:1.因为实验中接收和发送都使用了DMA,所以需要配置DMA发送和接收函数。

               2.实验中的fifo看似无用,我之前也曾尝试将Rxbuff中的数据直接复制进Txbuff,但最后实验失败,具体原因没弄清楚,但是无论从保护数据还是为了方便DMA正常传输的角度出发,都不应该将数据缓冲区设置与DMA通道相通。

               3.其中无论buff也好还是fifo也好,其实通俗来理解都只是定义在32中的一块连续内存,也就是一块数组,所以再进行数组间数据复制时,需要进行指针操作。例如将buff中的数据复制给fifo:(假设定义buff的写/读指针分别为buff_write_ptr/buff_read_ptr;定义fifo的写/读指针分别为fifo_write_ptr/fifo_read_ptr;)  *fifo_write_ptr=*buff_read_ptr (此时的复制操作相对于buff而言是读操作,而相对于fifo而言则是写操作) ;同时为了连续传输还应进行fifo_write_ptr++;buff_read_ptr++;  直到此次复制的数据全部传输完毕,复制操作才结束。

               4.就如大佬的博文所说,DMA的传输速度很快,为了留足给stm32 CPU进行完整复制操作的时间,需要两个接收buff,buff1接收数据完成后,cpu开始将buff1的数据copy给fifo,同时PC端的数据将传输给buff2.等buff2接收完成后,又轮换至buff1.这样就可以有条不紊的进行数据传输。所以fifo的大小要足够大。这种行为在F407中是非常方便的,F407内部就设计好了双缓冲模式,也其实就是这里说的双buff模式,F103则不行,F103不允许在传输过程中更换memory的地址。但是这也是有办法的可以模仿这种操作的:设置1个buff,但是启动DMA的接收半满和全满中断,这也就相当于人为的将buff一分为二,当进入半满中断时,CPU立刻开始处理前半buff中的数据,全满中断时,CPU则开始处理后半buff中的数据。

第一步 建立buff和fifo的结构体

typedef struct
{
    uint8_t*     fifo_read_ptr;
	uint8_t*     fifo_write_ptr;
	uint8_t*     fifo_start_ptr;
	uint16_t     fifo_occupied_size;
	uint16_t     fifo_free_size;
	uint16_t     fifo_total_size;
}Fifo_InitTypedef;

typedef struct
{
    uint8_t*     Buff_read_ptr;
	uint8_t*     Buff_write_ptr;
	uint8_t*     Buff_start_ptr;
	uint16_t     Buff_free_size;
	uint16_t     Buff_total_size;
	uint16_t     Buff_occupied_size;
}Buff_InitTypedef;

结构体中包含6个部分,分别有3个指针变量和3个普通变量。其中,因为需要对一个数组反复利用,所以当写指针或者读指针指向数组最后地址的后一个成员地址时,需要程序上将写指针或者读指针重新指向其实数组的起始地址,这也就需要用到start_ptr.

注意:这里可能有点绕,为什么是指向最后地址的后一个成员的地址,这里跟之前写代码逻辑有关,因为我是先执行复制操作,再执行指针+1操作,也就是说当数组的最后一个空间被填满时,指针应当指向的是数组最后地址的后一个成员的地址。举例:uint8_t   buff[8]={0}; uint8_t* buff_read_ptr=buff; 初始化结束后,当buff[7]的数据被复制给fifo后,便有buff_read_ptr=& buff[8];

但显然& buff[8]是一个非法地址,所以当此情况出现时,需要认为将地址初始化也即buff_read_ptr=buff_start_ptr;这也就形成了闭环,也就达到了环形缓冲区的用法。这当然只是一个简易的ring_buff用法,但是相对本实验而言已经够用,而且对我这种水平而言,网上搜到的那种严谨版的ring_buff用法太复杂,又是什么位域,又是什么镜像指示,太麻烦了。

第二步 初始化buff以及fifo

因为上一步只是定义了结构体,并没有实际意义上给buff或者fifo分配内存空间,因为buff和fifo在整个实验进程中是始终存在的,所以需要给其分配在堆区,也即定义全局变量

uint8_t     rxbuff[buff_size]={0};
uint8_t     txbuff[buff_size/2]={0};
Buff_InitTypedef   Rx_Buff_InitStructure={0};
Buff_InitTypedef   Tx_Buff_InitStructure={0};
extern Fifo_InitTypedef   Fifo_InitStructure;
/**************************************buff初始化函数**************************************************/
void Buff_Init(void)
{
	Rx_Buff_InitStructure.Buff_free_size=buff_size;
	Rx_Buff_InitStructure.Buff_occupied_size=Rx_Buff_InitStructure.Buff_total_size-Rx_Buff_InitStructure.Buff_free_size;
	Rx_Buff_InitStructure.Buff_total_size=buff_size;
	Rx_Buff_InitStructure.Buff_start_ptr=rxbuff;
	Rx_Buff_InitStructure.Buff_read_ptr=rxbuff;
	Rx_Buff_InitStructure.Buff_write_ptr=rxbuff;
	
	Tx_Buff_InitStructure.Buff_free_size=buff_size/2;
	Tx_Buff_InitStructure.Buff_occupied_size=Tx_Buff_InitStructure.Buff_total_size-Tx_Buff_InitStructure.Buff_free_size;
	Tx_Buff_InitStructure.Buff_total_size=buff_size/2;
	Tx_Buff_InitStructure.Buff_start_ptr=txbuff;
	Tx_Buff_InitStructure.Buff_read_ptr=txbuff;
	Tx_Buff_InitStructure.Buff_write_ptr=txbuff;
}
void Fifo_Init(void)
{
	Fifo_InitStructure.fifo_free_size=fifo_size;
	Fifo_InitStructure.fifo_occupied_size=Fifo_InitStructure.fifo_total_size-Fifo_InitStructure.fifo_free_size;
	Fifo_InitStructure.fifo_total_size=buff_size;
	Fifo_InitStructure.fifo_start_ptr=fifo;
	Fifo_InitStructure.fifo_read_ptr=fifo;
	Fifo_InitStructure.fifo_write_ptr=fifo;
}

第三步 配置DMA收发函数

/**************************************DMA配置函数**************************************************/

void Dma_Rx_Config(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
	
	DMA_DeInit(DMA2_Stream5);
	DMA_InitTypeDef       DMA_InitStructure;
	DMA_StructInit(&DMA_InitStructure);
	DMA_InitStructure.DMA_Channel=DMA_Channel_4;   //数据流5,通道4
	DMA_InitStructure.DMA_BufferSize=buff_size;    //总的缓冲区大小
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;
	DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;   //不使用fifo模式
//	DMA_InitStructure.DMA_FIFOThreshold=;  //阈值选择,当为直接模式时,该位无作用
	DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)rxbuff;
	DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;     //循环模式接收数据
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)(USART1_BASE+0x04);
	DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;   //不使用突发模式
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_Priority=DMA_Priority_High;      //DMA传输优先级高
    DMA_Init(DMA2_Stream5, &DMA_InitStructure);

    Dma_Rx_Nvic_Config();
	DMA_ITConfig(DMA2_Stream5, DMA_IT_TC|DMA_IT_HT, ENABLE);     //自定义一个类似双缓冲区,这时候需要开启半满和满中断
	DMA_ClearITPendingBit(DMA2_Stream5, DMA_IT_TCIF5|DMA_IT_HTIF5);

    Usart_config();
    USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
	DMA_Cmd(DMA2_Stream5, ENABLE);
}

void Dma_Tx_Config(uint8_t* buff,uint16_t size)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
	
	DMA_DeInit(DMA2_Stream7);
	DMA_InitTypeDef       DMA_InitStructure;
	DMA_StructInit(&DMA_InitStructure);
	DMA_InitStructure.DMA_Channel=DMA_Channel_4;
	DMA_InitStructure.DMA_BufferSize=size;
	DMA_InitStructure.DMA_DIR=DMA_DIR_MemoryToPeripheral;
	DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;
//	DMA_InitStructure.DMA_FIFOThreshold=;  //阈值选择,当为直接模式时,该位无作用
	DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)buff;
	DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)(USART1_BASE+0x04);
	DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_Priority=DMA_Priority_High;
    DMA_Init(DMA2_Stream7, &DMA_InitStructure); 
	
	Dma_Tx_Nvic_Config();
	DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE);     //发送函数中只需开启发送完成中断
	DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7);
	
	Usart_config();
    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
	DMA_Cmd(DMA2_Stream7, ENABLE);
}

F407的串口1接收和发送通道分别是DMA2的stream5 和stream7的通道4

此外,实验不使用stm32 内部的fifo模块,也不使用双缓冲区模式,同时它的突发模式也不使用

对应地,如下,当然当选择直接模式时,配置双缓冲区是无效的配置

DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable; 
DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;

官方手册中有对应的fifo 、突发模式、双buff、DMA暂停传输的讲解,这里没涉及到,就不哔哔。

第四步 配置中断处理函数

/**************************************中断处理函数**************************************************/

void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1,USART_IT_IDLE)==1)
	{
		clear_IT_IDLE();
		uint16_t R_size;
		R_size=get_rxbuff_IDLE_receive_size();
		R_size=Data_Transfer(&Rx_Buff_InitStructure,&Fifo_InitStructure,R_size,Trans_Dir_BufftoFifo);
		T_size=Data_Transfer(&Tx_Buff_InitStructure,&Fifo_InitStructure,R_size,Trans_Dir_FifotoBuff);
		Usart1_SendData_With_Dma(T_size);
		Tx_Begin=1;
	}
}

void DMA2_Stream7_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA2_Stream7,DMA_IT_TCIF7)!= RESET)	//DMA接收完成标志
	{
//		while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)==RESET);  
//        while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);    //DMA发送完毕但是也需要等待串口发送完毕,否则数据会在串口中被覆盖
		DMA_Cmd(DMA2_Stream7, DISABLE);   	//关闭USART1 TX DMA1 所指示的通道
		DMA_ClearITPendingBit(DMA2_Stream7,DMA_IT_TCIF7); 	//清除中断标志 
	}
}

void DMA2_Stream5_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA2_Stream5,DMA_IT_TCIF5)!= RESET)
	{
	    DMA_ClearITPendingBit(DMA2_Stream5,DMA_IT_TCIF5);
		uint16_t R_size;
		R_size=get_rxbuff_TC_receive_size();
		R_size=Data_Transfer(&Rx_Buff_InitStructure,&Fifo_InitStructure,R_size,Trans_Dir_BufftoFifo);
		T_size=Data_Transfer(&Tx_Buff_InitStructure,&Fifo_InitStructure,R_size,Trans_Dir_FifotoBuff);
		Usart1_SendData_With_Dma(R_size);
		Tx_Begin=1;
	}              
    if(DMA_GetITStatus(DMA2_Stream5,DMA_IT_HTIF5)!= RESET)
	{
	    DMA_ClearITPendingBit(DMA2_Stream5,DMA_IT_HTIF5);
		uint16_t R_size;
		R_size=get_rxbuff_HT_receive_size();
		R_size=Data_Transfer(&Rx_Buff_InitStructure,&Fifo_InitStructure,R_size,Trans_Dir_BufftoFifo);
		T_size=Data_Transfer(&Tx_Buff_InitStructure,&Fifo_InitStructure,R_size,Trans_Dir_FifotoBuff);
		Usart1_SendData_With_Dma(T_size);
//		Usart1_SendNumber(get_txbuff_free_size());      调试
		Tx_Begin=1;
	}
}

以上四个函数的分别是,串口一接收中断处理函数,串口1DMA发送完成中断处理函数,串口1DMA接收半满以及接收完成中断处理函数

DMA发送完成中断处理函数

发送完成中断仅需清除中断标志位,以及失能DMA的任务便可,之所以需要配置DMA发送完成中断是因为:每次DMA进行传输的数据起始地址和数据量都是不确定的,每次发送数据前都需重新配置这两个参数,而DMA使能之后,是无法更改之前的配置的,所以便需要每次发送完成都进入中断中,失能DMA发送通道。下次传送时再重新使能。

3个接收中断处理函数

因为实际实验时,我们通过PC端给stm32发送的数据量得由我们随心控制,在发送的数据量达不到进入DMA半满或全满中断处理函数中时,CPU也就无法正常处理数据,但是好在串口有自带的空闲中断函数,猜想设计师们可能正是出于这些考虑才设计了串口空闲中断处理函数。

其中,R_size 表示此次DMA接收到的数据量,T_size表示此次要发送的数据量

get_rxbuff_XX_receive_size();函数用于得到数据量的值,Data_Transfer();函数用于数据从rxbuff到fifo和从fifo到txbuff的数据复制Usart1_SendData_With_Dma();为使用DMA发送数据函数

数据量计算部分
uint16_t get_rxbuff_IDLE_receive_size(void)
{
	uint16_t available_size;
	available_size=buff_size-DMA_GetCurrDataCounter(DMA2_Stream5)
	-(Rx_Buff_InitStructure.Buff_read_ptr-Rx_Buff_InitStructure.Buff_start_ptr);
	Rx_Buff_InitStructure.Buff_write_ptr+=available_size;
    return available_size;
}
//	     |   |   |   |   |\\\|\\\|\\\|\\\|    |    |    |  假设这就是整个数据  \\\部分为此次DMA从外设接收到的数据
//         0   1   2   3   4   5   6   7    8    9   10
//	     0 1 2 3号房间是之前的数据,此时read_ptr应该指向第4号房间 DMA_current_data指向的是8 9 10号空房间 
//  总共的房间数为buff_size-11,无效房间数分为两个部分,第一个部分用read_ptr-start_ptr可以计算
//  第二个部分可以用函数接收current_data
//  之所以用这种方法,是因为上一次数据接收后,read_ptr的位置不是用户指定的
//  理解了IDLE中断接收的情况后,其他两种中断情况就更简单了

uint16_t get_rxbuff_TC_receive_size(void)
{
	uint16_t available_size;
	available_size=buff_size-(Rx_Buff_InitStructure.Buff_read_ptr-Rx_Buff_InitStructure.Buff_start_ptr);
	Rx_Buff_InitStructure.Buff_write_ptr+=available_size;
    return available_size;
}

uint16_t get_rxbuff_HT_receive_size(void)
{
	uint16_t available_size;
	available_size=buff_size/2-(Rx_Buff_InitStructure.Buff_read_ptr-Rx_Buff_InitStructure.Buff_start_ptr);
	Rx_Buff_InitStructure.Buff_write_ptr+=available_size;
    return available_size;
}

代码讲解

available_size=buff_size-(Rx_Buff_InitStructure.Buff_read_ptr-Rx_Buff_InitStructure.Buff_start_ptr);

以接收全满时为例,如何得到此次接收到的数据量

DMA发送函数

void Usart1_SendData_With_Dma(uint16_t T_size)
{


    Dma_Tx_Config(Tx_Buff_InitStructure.Buff_read_ptr,T_size);	
	Tx_Buff_InitStructure.Buff_read_ptr+=T_size;
	if(Tx_Buff_InitStructure.Buff_read_ptr==&Tx_Buff_InitStructure.Buff_start_ptr[buff_size/2])
	{
	    Tx_Buff_InitStructure.Buff_read_ptr=Tx_Buff_InitStructure.Buff_start_ptr;
	}
}

 3.fifo部分

/**************************************fifo处理函数*******************************************************/
/**
*  @brief 定义一个cpu复制函数,用于将数据在DMA接收/发送 buff和fifo之间互传
*         用一个Trans_Direction变量来区分数据传输的方向
*         Trans_size是要传输的数据量,而实际传输了的数据量为available_size,该值也会回传
*
*
*/

uint16_t Data_Transfer(Buff_InitTypedef*  Buff_InitStructure,
      Fifo_InitTypedef* Fifo_InitStructure,uint16_t Trans_size,uint8_t Trans_Direction)
{
	uint16_t  available_size=0;
//	uint16_t& fifo_free_size    =Fifo_InitStructure->fifo_free_size;
//	uint16_t& fifo_occupied_size=Fifo_InitStructure->fifo_occupied_size;
//	uint16_t& Buff_free_size    =Buff_InitStructure->Buff_free_size;
//	uint16_t& Buff_occupied_size=Buff_InitStructure->Buff_occupied_size;
	//结构体写法太长,创建临时变量,便于检查
	//利用指针方式改变实参
	uint16_t  count=0;
	
//	uint8_t* &fifo_start_ptr=Fifo_InitStructure->fifo_start_ptr;
//	uint8_t* &fifo_write_ptr=Fifo_InitStructure->fifo_write_ptr;
//	uint8_t* &fifo_read_ptr =Fifo_InitStructure->fifo_read_ptr;
//	uint8_t* &buff_start_ptr=Buff_InitStructure->Buff_start_ptr;
//	uint8_t* &buff_write_ptr=Buff_InitStructure->Buff_write_ptr;
//	uint8_t* &buff_read_ptr =Buff_InitStructure->Buff_read_ptr;
    //C语言好像不能用引用的这种用法
	
	if(Trans_Direction==Trans_Dir_BufftoFifo)
	{
    if(Fifo_InitStructure->fifo_free_size==0||Trans_size==0)
		return 0;//如果判断是无效传输,则不往后执行
	
	if(Buff_InitStructure->Buff_occupied_size<Trans_size)
	{
	    available_size=Buff_InitStructure->Buff_occupied_size;//处理逻辑是如果buff中实际有效的数据量小于用户指定的传输量,则有效传输量取实际量
	}
	else
	{
	    available_size=Trans_size;  //处理逻辑是如果要传输的数据大于缓冲区的剩余容量,则大于的那部分将会被丢弃
	}
	count=available_size;
	fifo_lock();
	    while(count-->0)
	    {
	        *Fifo_InitStructure->fifo_write_ptr=*Buff_InitStructure->Buff_read_ptr;
			Fifo_InitStructure->fifo_write_ptr++; Buff_InitStructure->Buff_read_ptr++;
			Fifo_InitStructure->fifo_free_size--; Fifo_InitStructure->fifo_occupied_size++;
			Buff_InitStructure->Buff_free_size++; Buff_InitStructure->Buff_occupied_size--;
			if(Fifo_InitStructure->fifo_write_ptr==&Fifo_InitStructure->fifo_start_ptr[fifo_size])
			{
			   Fifo_InitStructure->fifo_write_ptr=Fifo_InitStructure->fifo_start_ptr;
			}
			if(Buff_InitStructure->Buff_read_ptr==&Buff_InitStructure->Buff_start_ptr[buff_size])
			{
			   Buff_InitStructure->Buff_read_ptr=Buff_InitStructure->Buff_start_ptr;
			}
	    }
	}
	if(Trans_Direction==Trans_Dir_FifotoBuff)
	{
	if(Trans_size==0)
		return 0;//如果判断是无效传输,则不往后执行
	
	if(Fifo_InitStructure->fifo_occupied_size<Trans_size)
	{
	    available_size=Fifo_InitStructure->fifo_occupied_size;
	}
	else
	{
	    available_size=Trans_size;  //处理逻辑是如果要传输的数据大于缓冲区的剩余容量,则大于的那部分将会被丢弃
	}
	count=available_size;
		fifo_lock();
	    while(count-->0)
	    {
	        *Buff_InitStructure->Buff_write_ptr=*Fifo_InitStructure->fifo_read_ptr;
			Buff_InitStructure->Buff_write_ptr++; Fifo_InitStructure->fifo_read_ptr++;
//			Buff_InitStructure->Buff_free_size--; Buff_InitStructure->Buff_occupied_size++;
			Fifo_InitStructure->fifo_free_size++; Fifo_InitStructure->fifo_occupied_size--;
			if(Buff_InitStructure->Buff_write_ptr==&Buff_InitStructure->Buff_start_ptr[buff_size/2])
			{
			   Buff_InitStructure->Buff_write_ptr=Buff_InitStructure->Buff_start_ptr;
			}
			if(Fifo_InitStructure->fifo_read_ptr==&Fifo_InitStructure->fifo_start_ptr[fifo_size])
			{
			   Fifo_InitStructure->fifo_read_ptr=Fifo_InitStructure->fifo_start_ptr;
			}
	    }
	}
    fifo_unlock();
    return available_size;
}

该函数没什么技术含量,纯是苦力活。根据Trans_Direction判断数据是从buff传进fifo还是从fifo传进buff中。

到此就全部结束了,测试了一下

20ms,每次自动传送256个字节,收发是没问题的

问题------bug 

每次当从PC端发送给stm32的数据量达到61440个字节后,stm32便停止向PC端发送数据了,至今没弄明白

 下面是完整代码

bsp_usart1.c/h

#include "bsp_usart.h"



static void Usart_Gpio_Config(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);

	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
	
	GPIO_InitTypeDef    GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;     //USART1的输出为gpioa_9
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure); 
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;     //USART1的输入为gpioa_10
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);  	

}

static void Usart_NVIC_Config(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
	NVIC_InitTypeDef  NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStructure);
}



void Usart_config(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    
	USART_InitTypeDef       USART_InitStructure;
	USART_InitStructure.USART_BaudRate=115200;
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
	USART_InitStructure.USART_Parity=USART_Parity_No;
	USART_InitStructure.USART_StopBits=USART_StopBits_1;
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;
    USART_Init(USART1, &USART_InitStructure);

    Usart_Gpio_Config();
	Usart_NVIC_Config();
	

	USART_ITConfig(USART1,USART_IT_IDLE, ENABLE);
	clear_IT_IDLE();
	
    USART_Cmd(USART1, ENABLE);
}

void clear_IT_IDLE(void)
{
	USART_GetFlagStatus(USART1, USART_FLAG_IDLE);
	USART_ReceiveData(USART1);
}

double power(double a, double b)
{
	double result = 1;
	for(int i=0;i<b;i++)
	{
		result *= a;
	}
	return result;
}

void Usart1_SendByte(uint8_t data)
{
	if(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==1)
	{
       USART_SendData(USART1, data);
	   while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==0);
	}
}

void Usart1_SendNumber(uint32_t data)
{
	uint8_t count = 0;
	uint8_t i = 0;
	uint8_t num;
	uint8_t sector;
	while(data % (int)(power(10, count) )!= data)
	{
		count++;
	}
	 num = count-1;
	for (i = 0; i < count; i++)
	{
		sector = (data / (int)power(10, num));
		Usart1_SendByte(sector);
		data = data - (int)power(10, num)*sector;
		num--;
	}
}

void Usart1_SendNumber_16(uint32_t data)
{
	uint8_t count = 0;
	uint8_t i = 0;
	uint8_t num;
	uint8_t sector;
	while(data % (int)(power(10, count) )!= data)
	{
		count++;
	}
	 num = count-1;
	for (i = 0; i < count; i++)
	{
		sector = (data / (int)power(10, num));
		Usart1_SendByte(30+sector);
		data = data - (int)power(10, num)*sector;
		num--;
	}
}

void Usart1_SendArray(uint8_t arr[],uint16_t ArrayLength)
{
	uint16_t i=0;
	for(i=0;i<ArrayLength;i++)
	{
	   Usart1_SendByte(arr[i]);
    }
}

#ifndef  _BSP_USART_H
#define  _BSP_USART_H

#include "stm32f4xx.h"



#ifdef __cplusplus
extern "C" {
#endif

#include "stm32f4xx_gpio.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx_rcc.h"


	
	
void clear_IT_IDLE(void);	
void Usart_config(void);	
void Usart1_SendByte(uint8_t data);
void Usart1_SendNumber(uint32_t data);
void Usart1_SendNumber_16(uint32_t data);
void Usart1_SendArray(uint8_t arr[],uint16_t ArrayLength);

	
#ifdef __cplusplus
}
#endif

#endif  /*_BSP_USART_H*/

 bsp_dma.c/h

#include "bsp_dma.h"

/**************************************变量声明*******************************************************/
uint8_t     rxbuff[buff_size]={0};
uint8_t     txbuff[buff_size/2]={0};
Buff_InitTypedef   Rx_Buff_InitStructure={0};
Buff_InitTypedef   Tx_Buff_InitStructure={0};
extern Fifo_InitTypedef   Fifo_InitStructure;
uint8_t Tx_Begin=0;
uint16_t 		T_size=0;
/**************************************中断优先级配置函数**********************************************/
static void Dma_Rx_Nvic_Config(void)  //接收
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
	NVIC_InitTypeDef  NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=DMA2_Stream5_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStructure);
}
   
static void Dma_Tx_Nvic_Config(void)  //发送
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
	NVIC_InitTypeDef  NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=DMA2_Stream7_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStructure);
}


/**************************************DMA配置函数**************************************************/

void Dma_Rx_Config(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
	
	DMA_DeInit(DMA2_Stream5);
	DMA_InitTypeDef       DMA_InitStructure;
	DMA_StructInit(&DMA_InitStructure);
	DMA_InitStructure.DMA_Channel=DMA_Channel_4;   //数据流5,通道4
	DMA_InitStructure.DMA_BufferSize=buff_size;    //总的缓冲区大小
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;
	DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;   //不使用fifo模式
//	DMA_InitStructure.DMA_FIFOThreshold=;  //阈值选择,当为直接模式时,该位无作用
	DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)rxbuff;
	DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;     //循环模式接收数据
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)(USART1_BASE+0x04);
	DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;   //不使用突发模式
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_Priority=DMA_Priority_High;      //DMA传输优先级高
    DMA_Init(DMA2_Stream5, &DMA_InitStructure);

    Dma_Rx_Nvic_Config();
	DMA_ITConfig(DMA2_Stream5, DMA_IT_TC|DMA_IT_HT, ENABLE);     //自定义一个类似双缓冲区,这时候需要开启半满和满中断
	DMA_ClearITPendingBit(DMA2_Stream5, DMA_IT_TCIF5|DMA_IT_HTIF5);

    Usart_config();
    USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
	DMA_Cmd(DMA2_Stream5, ENABLE);
}

void Dma_Tx_Config(uint8_t* buff,uint16_t size)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
	
	DMA_DeInit(DMA2_Stream7);
	DMA_InitTypeDef       DMA_InitStructure;
	DMA_StructInit(&DMA_InitStructure);
	DMA_InitStructure.DMA_Channel=DMA_Channel_4;
	DMA_InitStructure.DMA_BufferSize=size;
	DMA_InitStructure.DMA_DIR=DMA_DIR_MemoryToPeripheral;
	DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;
//	DMA_InitStructure.DMA_FIFOThreshold=;  //阈值选择,当为直接模式时,该位无作用
	DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)buff;
	DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)(USART1_BASE+0x04);
	DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_Priority=DMA_Priority_High;
    DMA_Init(DMA2_Stream7, &DMA_InitStructure); 
	
	Dma_Tx_Nvic_Config();
	DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE);     //发送函数中只需开启发送完成中断
	DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7);
	
	Usart_config();
    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
	DMA_Cmd(DMA2_Stream7, ENABLE);
}

/**************************************buff初始化函数**************************************************/
void Buff_Init(void)
{
	Rx_Buff_InitStructure.Buff_free_size=buff_size;
	Rx_Buff_InitStructure.Buff_occupied_size=Rx_Buff_InitStructure.Buff_total_size-Rx_Buff_InitStructure.Buff_free_size;
	Rx_Buff_InitStructure.Buff_total_size=buff_size;
	Rx_Buff_InitStructure.Buff_start_ptr=rxbuff;
	Rx_Buff_InitStructure.Buff_read_ptr=rxbuff;
	Rx_Buff_InitStructure.Buff_write_ptr=rxbuff;
	
	Tx_Buff_InitStructure.Buff_free_size=buff_size/2;
	Tx_Buff_InitStructure.Buff_occupied_size=Tx_Buff_InitStructure.Buff_total_size-Tx_Buff_InitStructure.Buff_free_size;
	Tx_Buff_InitStructure.Buff_total_size=buff_size/2;
	Tx_Buff_InitStructure.Buff_start_ptr=txbuff;
	Tx_Buff_InitStructure.Buff_read_ptr=txbuff;
	Tx_Buff_InitStructure.Buff_write_ptr=txbuff;
}

/**************************************buff数据处理函数**************************************************/

uint16_t get_rxbuff_occupied_size(void)
{
    return Rx_Buff_InitStructure.Buff_occupied_size;
}

uint16_t get_rxbuff_free_size(void)
{
    return Rx_Buff_InitStructure.Buff_free_size;
}

uint16_t get_txbuff_occupied_size(void)
{
    return Tx_Buff_InitStructure.Buff_occupied_size;
}

uint16_t get_txbuff_free_size(void)
{
    return Tx_Buff_InitStructure.Buff_free_size;
}

uint16_t get_rxbuff_IDLE_receive_size(void)
{
	uint16_t available_size;
	available_size=buff_size-DMA_GetCurrDataCounter(DMA2_Stream5)
	-(Rx_Buff_InitStructure.Buff_read_ptr-Rx_Buff_InitStructure.Buff_start_ptr);
	Rx_Buff_InitStructure.Buff_write_ptr+=available_size;
    return available_size;
}
//	     |   |   |   |   |\\\|\\\|\\\|\\\|    |    |    |  假设这就是整个数据  \\\部分为此次DMA从外设接收到的数据
//         0   1   2   3   4   5   6   7    8    9   10
//	     0 1 2 3号房间是之前的数据,此时read_ptr应该指向第4号房间 DMA_current_data指向的是8 9 10号空房间 
//  总共的房间数为buff_size-11,无效房间数分为两个部分,第一个部分用read_ptr-start_ptr可以计算
//  第二个部分可以用函数接收current_data
//  之所以用这种方法,是因为上一次数据接收后,read_ptr的位置不是用户指定的
//  理解了IDLE中断接收的情况后,其他两种中断情况就更简单了

uint16_t get_rxbuff_TC_receive_size(void)
{
	uint16_t available_size;
	available_size=buff_size-(Rx_Buff_InitStructure.Buff_read_ptr-Rx_Buff_InitStructure.Buff_start_ptr);
	Rx_Buff_InitStructure.Buff_write_ptr+=available_size;
    return available_size;
}

uint16_t get_rxbuff_HT_receive_size(void)
{
	uint16_t available_size;
	available_size=buff_size/2-(Rx_Buff_InitStructure.Buff_read_ptr-Rx_Buff_InitStructure.Buff_start_ptr);
	Rx_Buff_InitStructure.Buff_write_ptr+=available_size;
    return available_size;
}

void Usart1_SendData_With_Dma(uint16_t T_size)
{
//				Usart1_SendNumber(T_size);

    Dma_Tx_Config(Tx_Buff_InitStructure.Buff_read_ptr,T_size);	
	Tx_Buff_InitStructure.Buff_read_ptr+=T_size;
	if(Tx_Buff_InitStructure.Buff_read_ptr==&Tx_Buff_InitStructure.Buff_start_ptr[buff_size/2])
	{
	    Tx_Buff_InitStructure.Buff_read_ptr=Tx_Buff_InitStructure.Buff_start_ptr;
	}
}

uint8_t Get_Tx_Flag(void)
{
    return Tx_Begin;
}

uint16_t Get_Tx_Size(void)
{
    return T_size;
}

void clear_Tx_Flag(void)
{
    Tx_Begin=0;
}
/**************************************中断处理函数**************************************************/

void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1,USART_IT_IDLE)==1)
	{
		clear_IT_IDLE();
		uint16_t R_size;
		R_size=get_rxbuff_IDLE_receive_size();
		R_size=Data_Transfer(&Rx_Buff_InitStructure,&Fifo_InitStructure,R_size,Trans_Dir_BufftoFifo);
		T_size=Data_Transfer(&Tx_Buff_InitStructure,&Fifo_InitStructure,R_size,Trans_Dir_FifotoBuff);
		Usart1_SendData_With_Dma(T_size);
		Tx_Begin=1;
	}
}

void DMA2_Stream7_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA2_Stream7,DMA_IT_TCIF7)!= RESET)	//DMA接收完成标志
	{
//		while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)==RESET);  
//        while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);    //DMA发送完毕但是也需要等待串口发送完毕,否则数据会在串口中被覆盖
		DMA_Cmd(DMA2_Stream7, DISABLE);   	//关闭USART1 TX DMA1 所指示的通道
		DMA_ClearITPendingBit(DMA2_Stream7,DMA_IT_TCIF7); 	//清除中断标志 
	}
}

void DMA2_Stream5_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA2_Stream5,DMA_IT_TCIF5)!= RESET)
	{
	    DMA_ClearITPendingBit(DMA2_Stream5,DMA_IT_TCIF5);
		uint16_t R_size;
		R_size=get_rxbuff_TC_receive_size();
		R_size=Data_Transfer(&Rx_Buff_InitStructure,&Fifo_InitStructure,R_size,Trans_Dir_BufftoFifo);
		T_size=Data_Transfer(&Tx_Buff_InitStructure,&Fifo_InitStructure,R_size,Trans_Dir_FifotoBuff);
		Usart1_SendData_With_Dma(R_size);
		Tx_Begin=1;
	}              
    if(DMA_GetITStatus(DMA2_Stream5,DMA_IT_HTIF5)!= RESET)
	{
	    DMA_ClearITPendingBit(DMA2_Stream5,DMA_IT_HTIF5);
		uint16_t R_size;
		R_size=get_rxbuff_HT_receive_size();
		R_size=Data_Transfer(&Rx_Buff_InitStructure,&Fifo_InitStructure,R_size,Trans_Dir_BufftoFifo);
		T_size=Data_Transfer(&Tx_Buff_InitStructure,&Fifo_InitStructure,R_size,Trans_Dir_FifotoBuff);
		Usart1_SendData_With_Dma(T_size);
//		Usart1_SendNumber(get_txbuff_free_size());      调试
		Tx_Begin=1;
	}
}





#ifndef  _BSP_DMA_H
#define  _BSP_DMA_H

#include "stm32f4xx.h"


#ifdef __cplusplus
extern "C" {
#endif



#include "bsp_usart.h"
#include "fifo.h"
#include "stm32f4xx_dma.h"

	

	
	
	

	
	
	
	

void Dma_Tx_Config(uint8_t* buff,uint16_t size);
void Dma_Rx_Config(void);	
void Buff_Init(void);
uint16_t get_rxbuff_occupied_size(void);
uint16_t get_rxbuff_free_size(void);
uint16_t get_txbuff_occupied_size(void);
uint16_t get_txbuff_free_size(void);
uint16_t get_rxbuff_IDLE_receive_size(void);
uint16_t get_rxbuff_TC_receive_size(void);
uint16_t get_rxbuff_HT_receive_size(void);
void Usart1_SendData_With_Dma(uint16_t T_size);
uint8_t Get_Tx_Flag(void);
uint16_t Get_Tx_Size(void);
void clear_Tx_Flag(void);

#ifdef __cplusplus
}
#endif

#endif  /*__BSP_DMA_H*/

fifo.c/fifo.h

#include "fifo.h"

/**************************************变量声明*******************************************************/

uint8_t            fifo[fifo_size]={0};
Fifo_InitTypedef   Fifo_InitStructure={0};

/**************************************fifo初始化函数*******************************************************/

void Fifo_Init(void)
{
	Fifo_InitStructure.fifo_free_size=fifo_size;
	Fifo_InitStructure.fifo_occupied_size=Fifo_InitStructure.fifo_total_size-Fifo_InitStructure.fifo_free_size;
	Fifo_InitStructure.fifo_total_size=buff_size;
	Fifo_InitStructure.fifo_start_ptr=fifo;
	Fifo_InitStructure.fifo_read_ptr=fifo;
	Fifo_InitStructure.fifo_write_ptr=fifo;
}

static void fifo_lock(void)
{
    __disable_irq();             //cpu不响应中断
}


static void fifo_unlock(void)
{
    __enable_irq();
}

/**************************************fifo处理函数*******************************************************/
/**
*  @brief 定义一个cpu复制函数,用于将数据在DMA接收/发送 buff和fifo之间互传
*         用一个Trans_Direction变量来区分数据传输的方向
*         Trans_size是要传输的数据量,而实际传输了的数据量为available_size,该值也会回传
*
*
*/

uint16_t Data_Transfer(Buff_InitTypedef*  Buff_InitStructure,
      Fifo_InitTypedef* Fifo_InitStructure,uint16_t Trans_size,uint8_t Trans_Direction)
{
	uint16_t  available_size=0;
//	uint16_t& fifo_free_size    =Fifo_InitStructure->fifo_free_size;
//	uint16_t& fifo_occupied_size=Fifo_InitStructure->fifo_occupied_size;
//	uint16_t& Buff_free_size    =Buff_InitStructure->Buff_free_size;
//	uint16_t& Buff_occupied_size=Buff_InitStructure->Buff_occupied_size;
	//结构体写法太长,创建临时变量,便于检查
	//利用指针方式改变实参
	uint16_t  count=0;
	
//	uint8_t* &fifo_start_ptr=Fifo_InitStructure->fifo_start_ptr;
//	uint8_t* &fifo_write_ptr=Fifo_InitStructure->fifo_write_ptr;
//	uint8_t* &fifo_read_ptr =Fifo_InitStructure->fifo_read_ptr;
//	uint8_t* &buff_start_ptr=Buff_InitStructure->Buff_start_ptr;
//	uint8_t* &buff_write_ptr=Buff_InitStructure->Buff_write_ptr;
//	uint8_t* &buff_read_ptr =Buff_InitStructure->Buff_read_ptr;
    //C语言好像不能用引用的这种用法
	
	if(Trans_Direction==Trans_Dir_BufftoFifo)
	{
    if(Fifo_InitStructure->fifo_free_size==0||Trans_size==0)
		return 0;//如果判断是无效传输,则不往后执行
	
	if(Buff_InitStructure->Buff_occupied_size<Trans_size)
	{
	    available_size=Buff_InitStructure->Buff_occupied_size;//处理逻辑是如果buff中实际有效的数据量小于用户指定的传输量,则有效传输量取实际量
	}
	else
	{
	    available_size=Trans_size;  //处理逻辑是如果要传输的数据大于缓冲区的剩余容量,则大于的那部分将会被丢弃
	}
	count=available_size;
	fifo_lock();
	    while(count-->0)
	    {
	        *Fifo_InitStructure->fifo_write_ptr=*Buff_InitStructure->Buff_read_ptr;
			Fifo_InitStructure->fifo_write_ptr++; Buff_InitStructure->Buff_read_ptr++;
			Fifo_InitStructure->fifo_free_size--; Fifo_InitStructure->fifo_occupied_size++;
			Buff_InitStructure->Buff_free_size++; Buff_InitStructure->Buff_occupied_size--;
			if(Fifo_InitStructure->fifo_write_ptr==&Fifo_InitStructure->fifo_start_ptr[fifo_size])
			{
			   Fifo_InitStructure->fifo_write_ptr=Fifo_InitStructure->fifo_start_ptr;
			}
			if(Buff_InitStructure->Buff_read_ptr==&Buff_InitStructure->Buff_start_ptr[buff_size])
			{
			   Buff_InitStructure->Buff_read_ptr=Buff_InitStructure->Buff_start_ptr;
			}
	    }
	}
	if(Trans_Direction==Trans_Dir_FifotoBuff)
	{
	if(Trans_size==0)
		return 0;//如果判断是无效传输,则不往后执行
	
	if(Fifo_InitStructure->fifo_occupied_size<Trans_size)
	{
	    available_size=Fifo_InitStructure->fifo_occupied_size;
	}
	else
	{
	    available_size=Trans_size;  //处理逻辑是如果要传输的数据大于缓冲区的剩余容量,则大于的那部分将会被丢弃
	}
	count=available_size;
		fifo_lock();
	    while(count-->0)
	    {
	        *Buff_InitStructure->Buff_write_ptr=*Fifo_InitStructure->fifo_read_ptr;
			Buff_InitStructure->Buff_write_ptr++; Fifo_InitStructure->fifo_read_ptr++;
//			Buff_InitStructure->Buff_free_size--; Buff_InitStructure->Buff_occupied_size++;
			Fifo_InitStructure->fifo_free_size++; Fifo_InitStructure->fifo_occupied_size--;
			if(Buff_InitStructure->Buff_write_ptr==&Buff_InitStructure->Buff_start_ptr[buff_size/2])
			{
			   Buff_InitStructure->Buff_write_ptr=Buff_InitStructure->Buff_start_ptr;
			}
			if(Fifo_InitStructure->fifo_read_ptr==&Fifo_InitStructure->fifo_start_ptr[fifo_size])
			{
			   Fifo_InitStructure->fifo_read_ptr=Fifo_InitStructure->fifo_start_ptr;
			}
	    }
	}
    fifo_unlock();
    return available_size;
}

uint16_t get_fifo_occupied_size(void)
{
    return Fifo_InitStructure.fifo_occupied_size;
}

uint16_t get_fifo_free_size(void)
{
    return Fifo_InitStructure.fifo_free_size;
}
#ifndef  _FIFO_H
#define  _FIFO_H

#include "stm32f4xx.h"


#ifdef __cplusplus
extern "C" {
#endif


#include "bsp_dma.h"	

#define         fifo_size                         4096
#define         buff_size                         4096
#define         Trans_Dir_BufftoFifo	          1
#define         Trans_Dir_FifotoBuff	          0

	
typedef struct
{
    uint8_t*     fifo_read_ptr;
	uint8_t*     fifo_write_ptr;
	uint8_t*     fifo_start_ptr;
	uint16_t     fifo_occupied_size;
	uint16_t     fifo_free_size;
	uint16_t     fifo_total_size;
}Fifo_InitTypedef;

typedef struct
{
    uint8_t*     Buff_read_ptr;
	uint8_t*     Buff_write_ptr;
	uint8_t*     Buff_start_ptr;
	uint16_t     Buff_free_size;
	uint16_t     Buff_total_size;
	uint16_t     Buff_occupied_size;
}Buff_InitTypedef;

void Fifo_Init(void);
uint16_t Data_Transfer(Buff_InitTypedef*  Buff_InitStructure,Fifo_InitTypedef* Fifo_InitStructure,
                       uint16_t Trans_size,uint8_t Trans_Direction);
uint16_t get_fifo_occupied_size(void);
uint16_t get_fifo_free_size(void);

#ifdef __cplusplus
}
#endif

#endif  /*_FIFO_H*/

main.c

#include "bsp_usart.h"
#include "bsp_led.h"
#include "bsp_dma.h"
#include "fifo.h"

extern Fifo_InitTypedef   Fifo_InitStructure;

int main(void)
{
	
//	LED_GPIO_Config();
	Usart_config();
	Dma_Rx_Config();
    Buff_Init();
	Fifo_Init();
	

	while(1)
	{
//		if(Get_Tx_Flag()==SET)
//		{
//		    Usart1_SendData_With_Dma(Get_Tx_Size());
				Usart1_SendNumber((uint32_t)Fifo_InitStructure.fifo_read_ptr);
//			clear_Tx_Flag();			
//		}
//		LED_PURPLE
	}
   
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值