STM32F103 实例应用(11)——DMA接收不定长串口数据


一、DMA 简介

DMA(Direct Memory Access)—直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数据,但是不需要占用 CPU,即在传输数据的时候,CPU 可以干其他的事情,好像是多线程一样。

数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是 SRAM 或者是 FLASH

DMA 控制器包含了 DMA1DMA2,其中 DMA1 有 7 个通道,DMA2 有 5 个通道,这里的通道可以理解为传输数据的一种管道。要注意的是 DMA2 只存在于大容量的单片机中。

二、DMA 功能框图

DMA 控制器独立于内核,属于一个单独的外设,结构比较简单,从编程的角度来看,我们只需掌握功能框图中的三部分内容即可,具体见下图:
STM32F103 实例应用(11)——DMA接收不定长串口数据_第1张图片

  1. ①DMA 请求

如果外设要想通过 DMA 来传输数据,必须先给 DMA 控制器发送 DMA 请求,DMA收到请求信号之后,控制器会给外设一个应答信号,当外设应答后且 DMA 控制器收到应答信号之后,就会启动 DMA 的传输,直到传输完毕。
DMA 有 DMA1 和 DMA2 两个控制器,DMA1 有 7 个通道,DMA2 有 5 个通道,不同的 DMA 控制器的通道对应着不同的外设请求,这决定了我们在软件编程上该怎么设置,具体见 DMA 请求映像表。
STM32F103 实例应用(11)——DMA接收不定长串口数据_第2张图片

  1. ②通道
    DMA 具有 12 个独立可编程的通道,其中 DMA1 有 7 个通道,DMA2 有 5 个通道,每个通道对应不同的外设的 DMA 请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。

  2. ③仲裁器
    当发生多个 DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器也管理。仲裁器管理 DMA 通道请求分为两个阶段。第一阶段属于软件阶段,可以在DMA_CCRx 寄存器中设置,有 4 个等级:非常高、高、中和低四个优先级。第二阶段属于硬件阶段,如果两个或以上的 DMA 通道请求设置的优先级一样,则他们优先级取决于通 道编号,编号越低优先权越高,比如通道 0 高于通道 1。在大容量产品和互联型产品中,
    DMA1 控制器拥有高于 DMA2 控制器的优先级。

三、设计实例

本示例使用串口1打印并接收电脑端发来的指令,串口3作为与4G通信的渠道。
bsp_usart.h

/**===========================================================================
  @file     bsp_usart.h
  @brief    本文件是用于usart驱动
  @author   青梅煮久
  @version  r0.1
  @date     2021/02/20
----------------------------------------------------------------------------
  Remark: (备注描述)
	串口1、3的驱动。
	串口1:用于日志打印、指令配置
	串口3:用于4G模块通讯
----------------------------------------------------------------------------
                                History
----------------------------------------------------------------------------
       |  |        | 
-------------|-----------|----------------|---------------------------------
  2021/02/20 | r0.1      | 青梅煮久        | 创建
-------------|-----------|----------------|---------------------------------
             |           |                |
-------------|-----------|----------------|---------------------------------
             |           |                |
-------------|-----------|----------------|---------------------------------
             |           |                |
============================================================================*/
#ifndef __USART_H
#define	__USART_H

/*********************************************************************
 * INCLUDES
 */
#include "stm32f10x.h"
#include 

/*********************************************************************
 * DEFINITIONS
 */	
/** 
  * 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
	* 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线
	* 2-修改GPIO的宏
  */
	
// 串口1-USART1
#define  DEBUG_USARTx                   USART1
#define  DEBUG_USART_CLK                RCC_APB2Periph_USART1
#define  DEBUG_USART_APBxClkCmd         RCC_APB2PeriphClockCmd
#define  DEBUG_USART_BAUDRATE           115200

// USART GPIO 引脚宏定义
#define  DEBUG_USART_GPIO_CLK           (RCC_APB2Periph_GPIOA)
#define  DEBUG_USART_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
    
#define  DEBUG_USART_TX_GPIO_PORT       GPIOA   
#define  DEBUG_USART_TX_GPIO_PIN        GPIO_Pin_9
#define  DEBUG_USART_RX_GPIO_PORT       GPIOA
#define  DEBUG_USART_RX_GPIO_PIN        GPIO_Pin_10

#define  DEBUG_USART_IRQ                USART1_IRQn
#define  DEBUG_USART_IRQHandler         USART1_IRQHandler


// 串口2-USART2
//#define  DEBUG_USARTx                   USART2
//#define  DEBUG_USART_CLK                RCC_APB1Periph_USART2
//#define  DEBUG_USART_APBxClkCmd         RCC_APB1PeriphClockCmd
//#define  DEBUG_USART_BAUDRATE           115200

 USART GPIO 引脚宏定义
//#define  DEBUG_USART_GPIO_CLK           (RCC_APB2Periph_GPIOA)
//#define  DEBUG_USART_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
//    
//#define  DEBUG_USART_TX_GPIO_PORT       GPIOA   
//#define  DEBUG_USART_TX_GPIO_PIN        GPIO_Pin_2
//#define  DEBUG_USART_RX_GPIO_PORT       GPIOA
//#define  DEBUG_USART_RX_GPIO_PIN        GPIO_Pin_3

//#define  DEBUG_USART_IRQ                USART2_IRQn
//#define  DEBUG_USART_IRQHandler         USART2_IRQHandler

// 串口3-USART3
#define  LTE_USARTx                   USART3
#define  LTE_USART_CLK                RCC_APB1Periph_USART3
#define  LTE_USART_APBxClkCmd         RCC_APB1PeriphClockCmd
#define  LTE_USART_BAUDRATE           115200

// USART GPIO 引脚宏定义
#define  LTE_USART_GPIO_CLK           (RCC_APB2Periph_GPIOB)
#define  LTE_USART_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
    
#define  LTE_USART_TX_GPIO_PORT       GPIOB   
#define  LTE_USART_TX_GPIO_PIN        GPIO_Pin_10
#define  LTE_USART_RX_GPIO_PORT       GPIOB
#define  LTE_USART_RX_GPIO_PIN        GPIO_Pin_11

#define  LTE_USART_IRQ                USART3_IRQn
#define  LTE_USART_IRQHandler         USART3_IRQHandler

// 串口4-UART4
//#define  DEBUG_USARTx                   UART4
//#define  DEBUG_USART_CLK                RCC_APB1Periph_UART4
//#define  DEBUG_USART_APBxClkCmd         RCC_APB1PeriphClockCmd
//#define  DEBUG_USART_BAUDRATE           115200

 USART GPIO 引脚宏定义
//#define  DEBUG_USART_GPIO_CLK           (RCC_APB2Periph_GPIOC)
//#define  DEBUG_USART_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
//    
//#define  DEBUG_USART_TX_GPIO_PORT       GPIOC   
//#define  DEBUG_USART_TX_GPIO_PIN        GPIO_Pin_10
//#define  DEBUG_USART_RX_GPIO_PORT       GPIOC
//#define  DEBUG_USART_RX_GPIO_PIN        GPIO_Pin_11

//#define  DEBUG_USART_IRQ                UART4_IRQn
//#define  DEBUG_USART_IRQHandler         UART4_IRQHandler


// 串口5-UART5
//#define  DEBUG_USARTx                   UART5
//#define  DEBUG_USART_CLK                RCC_APB1Periph_UART5
//#define  DEBUG_USART_APBxClkCmd         RCC_APB1PeriphClockCmd
//#define  DEBUG_USART_BAUDRATE           115200

 USART GPIO 引脚宏定义
//#define  DEBUG_USART_GPIO_CLK           (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD)
//#define  DEBUG_USART_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd
//    
//#define  DEBUG_USART_TX_GPIO_PORT       GPIOC   
//#define  DEBUG_USART_TX_GPIO_PIN        GPIO_Pin_12
//#define  DEBUG_USART_RX_GPIO_PORT       GPIOD
//#define  DEBUG_USART_RX_GPIO_PIN        GPIO_Pin_2

//#define  DEBUG_USART_IRQ                UART5_IRQn
//#define  DEBUG_USART_IRQHandler         UART5_IRQHandler

/*********************************************************************
* API FUNCTIONS
*/
void USART_Config(void);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);

#endif /* __USART_H */

bsp_usart.c

/**===========================================================================
  @file     bsp_usart.c
  @brief    本文件是用于usart驱动
  @author   青梅煮久
  @version  r0.1
  @date     2021/02/20
----------------------------------------------------------------------------
  Remark: (备注描述)
	串口1、3的驱动。
	串口1:用于日志打印、指令配置
	串口3:用于4G模块通讯
----------------------------------------------------------------------------
                                History
----------------------------------------------------------------------------
       |  |        | 
-------------|-----------|----------------|---------------------------------
  2021/02/20 | r0.1      | 青梅煮久        | 创建
-------------|-----------|----------------|---------------------------------
             |           |                |
-------------|-----------|----------------|---------------------------------
             |           |                |
-------------|-----------|----------------|---------------------------------
             |           |                |
============================================================================*/

/*********************************************************************
 * INCLUDES
 */
#include "bsp_usart.h"
#include "bsp_dma.h"
#include "stm32f10x.h"

static void NVIC_Configuration(void);

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief  USART GPIO 配置,工作参数配置
 @param  无
 @retval 无
*/
void USART_Config(void)
{
     
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	// 打开串口GPIO的时钟
	DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
	LTE_USART_GPIO_APBxClkCmd(LTE_USART_GPIO_CLK, ENABLE);
	
	// 打开串口外设的时钟
	DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
	LTE_USART_APBxClkCmd(LTE_USART_CLK, ENABLE);

	/*
	*  配置串口
	*  USART1_TX -> PA9 , USART1_RX ->	PA10
	*/	
	// 将USART Tx的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

	// 将USART Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
	
	USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No ;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(DEBUG_USARTx, &USART_InitStructure);
	
	/*
	*  4G
	*  USART3_TX -> PB10 , USART3_RX ->	PB11
	*/				
	GPIO_InitStructure.GPIO_Pin = LTE_USART_TX_GPIO_PIN;	         
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
	GPIO_Init(LTE_USART_TX_GPIO_PORT, &GPIO_InitStructure);		   
	
	GPIO_InitStructure.GPIO_Pin = LTE_USART_RX_GPIO_PIN;	        
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
	GPIO_Init(LTE_USART_RX_GPIO_PORT, &GPIO_InitStructure);
	
	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无校验
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制失能
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //发送和接受使能
	USART_Init(LTE_USARTx, &USART_InitStructure); 
  
	
	// 串口中断优先级配置
	NVIC_Configuration();
	
	// 使能串口接收中断
	USART_ITConfig(DEBUG_USARTx, USART_IT_IDLE, ENABLE);	
	USART_ITConfig(LTE_USARTx, USART_IT_IDLE, ENABLE);
	
	// 使能串口
	USART_Cmd(DEBUG_USARTx, ENABLE);	   
	USART_Cmd(LTE_USARTx, ENABLE); 
	
	USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);  //使能串口1的DMA发送     
    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);  //使能串口1的DMA接收  
	
	USART_DMACmd(USART3,USART_DMAReq_Tx,ENABLE);  //使能串口1的DMA发送     
    USART_DMACmd(USART3,USART_DMAReq_Rx,ENABLE);  //使能串口1的DMA接收  

}

/**
 @brief 发送一个字节
 @param pUSARTx -[in] 串口
 @param ch -[in] 发送数据
 @retval 无
*/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
     
	/* 发送一个字节数据到USART */
	USART_SendData(pUSARTx,ch);
		
	/* 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

/**
 @brief 发送8位的数组
 @param pUSARTx -[in] 串口
 @param array -[in] 发送数据
 @param num -[in] 发送长度
 @retval 无
*/
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
     
  uint8_t i;
	
	for(i=0; i<num; i++)
  {
     
	    /* 发送一个字节数据到USART */
	    Usart_SendByte(pUSARTx,array[i]);	
  
  }
	/* 等待发送完成 */
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}

/**
 @brief 发送字符串
 @param pUSARTx -[in] 串口
 @param str -[in] 发送数据
 @retval 无
*/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
     
	unsigned int k=0;
  do 
  {
     
      Usart_SendByte( pUSARTx, *(str + k) );
      k++;
  } while(*(str + k)!='\0');
  
  /* 等待发送完成 */
  while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
  {
     }
}

/**
 @brief 发送一个16位数
 @param pUSARTx -[in] 串口
 @param ch -[in] 发送数据
 @retval 无
*/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
     
	uint8_t temp_h, temp_l;
	
	/* 取出高八位 */
	temp_h = (ch&0XFF00)>>8;
	/* 取出低八位 */
	temp_l = ch&0XFF;
	
	/* 发送高八位 */
	USART_SendData(pUSARTx,temp_h);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
	
	/* 发送低八位 */
	USART_SendData(pUSARTx,temp_l);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

/**
 @brief 重定向c库函数printf到串口,重定向后可使用printf函数
*/
int fputc(int ch, FILE *f)
{
     
		/* 发送一个字节数据到串口 */
		USART_SendData(DEBUG_USARTx, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

/**
 @brief 重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
*/
int fgetc(FILE *f)
{
     
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(DEBUG_USARTx);
}

/**
 @brief USART1中断
 @param 无
 @retval 无
*/
void USART1_IRQHandler(void)  
{
       
    uint16_t data;  
    if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)  
    {
       
        DMA_Cmd(DMA1_Channel5, DISABLE); //关闭DMA,防止处理其间有数据  
  
        data = USART1->SR;  
        data = USART1->DR;  
          
        g_uart1ReceiveSize =RECEIVE_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);  
        if(g_uart1ReceiveSize !=0)  
        {
       
           // OSSemPost(DMAReceiveSize_Sem);  
			printf("shoudao1:%s", g_uart1ReceiveBuff);
        }  
        DMA_ClearFlag(DMA1_FLAG_TC5 | DMA1_FLAG_TE5 | DMA1_FLAG_HT5);//清除DMA2_Steam7传输完成标志    
        DMA_SetCurrDataCounter(DMA1_Channel5, RECEIVE_BUF_SIZE);  
        DMA_Cmd(DMA1_Channel5, ENABLE);     //打开DMA,  
  
    }  
} 

/**
 @brief USART3中断
 @param 无
 @retval 无
*/ 
void USART3_IRQHandler(void)  
{
       
    uint16_t data;  
    if(USART_GetITStatus(USART3,USART_IT_IDLE) != RESET)  
    {
       
        DMA_Cmd(DMA1_Channel3, DISABLE); //关闭DMA,防止处理其间有数据  
  
        data = USART3->SR;  
        data = USART3->DR;  
          
        g_uart3ReceiveSize =RECEIVE_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel3);  
        if(g_uart3ReceiveSize !=0)  
        {
       
           // OSSemPost(DMAReceiveSize_Sem);  
			printf("shoudao3:%s", g_uart3ReceiveBuff);
        }  
        DMA_ClearFlag(DMA1_FLAG_TC3 | DMA1_FLAG_TE3 | DMA1_FLAG_HT3);//清除DMA2_Steam7传输完成标志    
        DMA_SetCurrDataCounter(DMA1_Channel3, RECEIVE_BUF_SIZE);  
        DMA_Cmd(DMA1_Channel3, ENABLE);     //打开DMA,  
  
    }  
}

/*********************************************************************
 * LOCAL FUNCTIONS
 */
/**
 @brief  配置嵌套向量中断控制器NVIC
 @param  无
 @retval 无
*/
static void NVIC_Configuration(void)
{
     
	NVIC_InitTypeDef NVIC_InitStructure;
  
	/* 嵌套向量中断控制器组选择 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
	/* 4G NVIC设置*/
	/* 配置USART为中断源 */
	NVIC_InitStructure.NVIC_IRQChannel = LTE_USART_IRQ;
	/* 抢断优先级*/
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	/* 子优先级 */
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	/* 使能中断 */
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	/* 初始化配置NVIC */
	NVIC_Init(&NVIC_InitStructure);
	
	/* 配置串口的 NVIC设置*/
	NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
}

bsp_dma.h

/**===========================================================================
  @file     bsp_dma.h
  @brief    本文件是用于DMA驱动
  @author   青梅煮久
  @version  r0.1
  @date     2021/02/19
----------------------------------------------------------------------------
  Remark: (备注描述)
	串口1、3的接收。
							DMA1各个通道请求映像
外设    通道1   通道2     通道3       通道4        通道5       通道6      通道7
USART   - 	 USART3_TX  USART3_RX  USART1_TX  USART1_RX  USART2_RX  USART2_TX
----------------------------------------------------------------------------
                                History
----------------------------------------------------------------------------
       |  |        | 
-------------|-----------|----------------|---------------------------------
  2021/02/19 | r0.1      | 青梅煮久        | 创建
-------------|-----------|----------------|---------------------------------
             |           |                |
-------------|-----------|----------------|---------------------------------
             |           |                |
-------------|-----------|----------------|---------------------------------
             |           |                |
============================================================================*/
#ifndef __DMA_H
#define	__DMA_H	

/*********************************************************************
 * INCLUDES
 */
#include "stm32f10x.h"

/*********************************************************************
 * DEFINITIONS
 */						    					    
#define  RECEIVE_BUF_SIZE           255
#define  SEND_BUF_SIZE    			255

/*********************************************************************
 * GLOBAL VARIABLES
 */
extern uint8_t g_uart1ReceiveBuff[RECEIVE_BUF_SIZE];   			//接收缓冲  
extern uint8_t g_uart1SendBuff[SEND_BUF_SIZE];    				//发送数据缓冲区  
extern uint16_t g_uart1ReceiveSize;  
  
extern uint8_t  g_uart3ReceiveBuff[RECEIVE_BUF_SIZE];   		//接收缓冲  
extern uint8_t  g_uart3SendBuff[SEND_BUF_SIZE];    				//发送数据缓冲区  
extern uint16_t g_uart3ReceiveSize; 
 
/*********************************************************************
* API FUNCTIONS
*/
void DMA_Config(void);
void DmaSendDataProc(DMA_Channel_TypeDef *DMA_Streamx,uint16_t ndtr);
void Uart1DmaSendByte(uint8_t nSendInfo);
void Uart1DmaSendString(uint8_t* pSendInfo, uint16_t nSendCount);
void Uart3DmaSendByte(uint8_t nSendInfo);
void Uart3DmaSendString(uint8_t* pSendInfo, uint16_t nSendCount);

#endif /* __DMA_H */

bsp_dma.c

/**===========================================================================
  @file     bsp_dma.c
  @brief    本文件是用于DMA驱动
  @author   青梅煮久
  @version  r0.1
  @date     2021/02/19
----------------------------------------------------------------------------
  Remark: (备注描述)
	串口1、3的接收。
							DMA1各个通道请求映像
外设    通道1   通道2     通道3       通道4        通道5       通道6      通道7
USART   - 	 USART3_TX  USART3_RX  USART1_TX  USART1_RX  USART2_RX  USART2_TX
----------------------------------------------------------------------------
                                History
----------------------------------------------------------------------------
       |  |        | 
-------------|-----------|----------------|---------------------------------
  2021/02/19 | r0.1      | 青梅煮久        | 创建
-------------|-----------|----------------|---------------------------------
             |           |                |
-------------|-----------|----------------|---------------------------------
             |           |                |
-------------|-----------|----------------|---------------------------------
             |           |                |
============================================================================*/

/*********************************************************************
 * INCLUDES
 */
#include "bsp_dma.h"
#include 

static void NVIC_Configuration(void);

/*********************************************************************
 * GLOBAL VARIABLES
 */
uint8_t  g_uart1ReceiveBuff[RECEIVE_BUF_SIZE];   //接收缓冲  
uint8_t  g_uart1SendBuff[SEND_BUF_SIZE];    //发送数据缓冲区  
uint16_t g_uart1ReceiveSize = 0;  
  
uint8_t  g_uart3ReceiveBuff[RECEIVE_BUF_SIZE];   //接收缓冲  
uint8_t  g_uart3SendBuff[SEND_BUF_SIZE];    //发送数据缓冲区  
uint16_t g_uart3ReceiveSize = 0;  

/*********************************************************************
 * LOCAL VARIABLES
 */

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief DMA配置
 @param 无
 @return 无
*/
void DMA_Config(void)
{
     
	DMA_InitTypeDef  DMA_InitStructure;
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//使能DMA传输
	
	/****************************配置UART1发送***********************/
    DMA_DeInit(DMA1_Channel4);  
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;//DMA外设地址  
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)g_uart1SendBuff;//DMA 存储器0地址  
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//存储器到外设模式  
    DMA_InitStructure.DMA_BufferSize = SEND_BUF_SIZE;//数据传输量   
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式  
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式  
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位  
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位  
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式   
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级  
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);//初始化DMA Stream
	DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
	
	/****************************配置UART1接收***********************/
    DMA_DeInit(DMA1_Channel5);  
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;//DMA外设地址  
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)g_uart1ReceiveBuff;//DMA 存储器0地址  
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC ;//外设到存储器模式  
    DMA_InitStructure.DMA_BufferSize = RECEIVE_BUF_SIZE;//数据传输量   
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式  
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式  
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位  
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位  
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式   
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级  
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
    DMA_Init(DMA1_Channel5, &DMA_InitStructure);//初始化DMA Stream  
	
	
	
	/****************************配置UART3发送***********************/
    DMA_DeInit(DMA1_Channel2);  
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART3->DR;//DMA外设地址  
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)g_uart3SendBuff;//DMA 存储器0地址  
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//存储器到外设模式  
    DMA_InitStructure.DMA_BufferSize = SEND_BUF_SIZE;//数据传输量   
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式  
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式  
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位  
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位  
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式   
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级  
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
    DMA_Init(DMA1_Channel2, &DMA_InitStructure);//初始化DMA Stream
	DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);
	
	/****************************配置UART3接收***********************/
    DMA_DeInit(DMA1_Channel3);  
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART3->DR;//DMA外设地址  
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)g_uart3ReceiveBuff;//DMA 存储器0地址  
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC ;//外设到存储器模式  
    DMA_InitStructure.DMA_BufferSize = RECEIVE_BUF_SIZE;//数据传输量   
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式  
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式  
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位  
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8位  
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式   
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级  
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
    DMA_Init(DMA1_Channel3, &DMA_InitStructure);//初始化DMA Stream  
	
	
	
	/****************************配置NVIC***********************/
	NVIC_Configuration();
	/**********************2个串口接收使能DMA*******************/
	DMA_Cmd(DMA1_Channel5, ENABLE);  //开启DMA传输
	DMA_Cmd(DMA1_Channel3, ENABLE);  //开启DMA传输
	
	DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);  
	DMA_ITConfig(DMA1_Channel3,DMA_IT_TC,ENABLE);  
}

/**
 @brief 开启一次DMA传输 
 @param DMA_Streamx -[in] DMA数据流,通道
 @param ndtr -[in] 数据传输量
 @return 无
*/  
void DmaSendDataProc(DMA_Channel_TypeDef *DMA_Streamx,uint16_t ndtr)  
{
       

    DMA_Cmd(DMA_Streamx, DISABLE);                      //关闭DMA传输   

    DMA_SetCurrDataCounter(DMA_Streamx,ndtr);          //数据传输量    

    DMA_Cmd(DMA_Streamx, ENABLE);                      //开启DMA传输   
}

/**
 @brief 串口1使用DMA发送单字节
 @param nSendInfo -[in] 发送数据
 @return 无
*/ 
void Uart1DmaSendByte(uint8_t nSendInfo)  
{
       
    uint8_t *pBuf = NULL;  
    //指向发送缓冲区
    pBuf = g_uart1SendBuff;  
    *pBuf++ = nSendInfo;  
  
    DmaSendDataProc(DMA1_Channel4, 1); //开始一次DMA传输!       
} 

/**
 @brief 串口1使用DMA发送多字节
 @param nSendInfo -[in] 发送数据
 @param nSendCount -[in] 发送长度
 @return 无
*/ 
void Uart1DmaSendString(uint8_t* pSendInfo, uint16_t nSendCount)  
{
       
    uint16_t i = 0;  
    uint8_t *pBuf = NULL;  
    //指向发送缓冲区  
    pBuf = g_uart1SendBuff;  
  
    for (i=0; i<nSendCount; i++)  
    {
       
        *pBuf++ = pSendInfo[i];  
    }  
    //DMA发送方式  
    DmaSendDataProc(DMA1_Channel4, nSendCount); //开始一次DMA传输!      
}  

/**
 @brief 串口3使用DMA发送单字节
 @param nSendInfo -[in] 发送数据
 @return 无
*/ 
void Uart3DmaSendByte(uint8_t nSendInfo)  
{
       
    uint8_t *pBuf = NULL;  
    //指向发送缓冲区
    pBuf = g_uart3SendBuff;  
    *pBuf++ = nSendInfo;  
  
    DmaSendDataProc(DMA1_Channel2, 1); //开始一次DMA传输!       
} 

/**
 @brief 串口3使用DMA发送多字节
 @param nSendInfo -[in] 发送数据
 @param nSendCount -[in] 发送长度
 @return 无
*/ 
void Uart3DmaSendString(uint8_t* pSendInfo, uint16_t nSendCount)  
{
       
    uint16_t i = 0;  
    uint8_t *pBuf = NULL;  
    //指向发送缓冲区  
    pBuf = g_uart3SendBuff;  
  
    for (i=0; i<nSendCount; i++)  
    {
       
        *pBuf++ = pSendInfo[i];  
    }  
    //DMA发送方式  
    DmaSendDataProc(DMA1_Channel2, nSendCount); //开始一次DMA传输!      
}

/**
 @brief 串口1使用DMA发送完成中断
 @param 无
 @return 无
*/
void DMA1_Channel4_IRQHandler(void)  
{
       
    //清除标志  
    if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=RESET)//等待传输完成  
    {
        
        DMA_ClearFlag(DMA1_FLAG_TC4);//清除传输完成标志  
    }  
} 

/**
 @brief 串口1使用DMA接完成中断
 @param 无
 @return 无
*/ 
void DMA1_Channel5_IRQHandler(void)  
{
       
    //清除标志  
    if(DMA_GetFlagStatus(DMA1_FLAG_TC5)!=RESET)//等待传输完成  
    {
        
        DMA_Cmd(DMA1_Channel5, DISABLE); //关闭DMA,防止处理其间有数据  
  
        g_uart1ReceiveSize =RECEIVE_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);  
        if(g_uart1ReceiveSize !=0)  
        {
       
            // 此处不处理数据,uart处理
        }  
          
        DMA_ClearFlag(DMA1_FLAG_TC5 | DMA1_FLAG_TE5 | DMA1_FLAG_HT5);//清除DMA2_Steam7传输完成标志  
        DMA_SetCurrDataCounter(DMA1_Channel5, RECEIVE_BUF_SIZE);  
        DMA_Cmd(DMA1_Channel5, ENABLE);     //打开DMA,  
    }  
}  

/**
 @brief 串口3使用DMA发送完成中断
 @param 无
 @return 无
*/
void DMA1_Channel2_IRQHandler(void)  
{
       
    //清除标志  
    if(DMA_GetFlagStatus(DMA1_FLAG_TC2)!=RESET)//等待传输完成  
    {
        
        DMA_ClearFlag(DMA1_FLAG_TC2);//清除传输完成标志  
    }  
} 

/**
 @brief 串口3使用DMA接完成中断
 @param 无
 @return 无
*/ 
void DMA1_Channel3_IRQHandler(void)  
{
       
    //清除标志  
    if(DMA_GetFlagStatus(DMA1_FLAG_TC3)!=RESET)//等待传输完成  
    {
        
        DMA_Cmd(DMA1_Channel3, DISABLE); //关闭DMA,防止处理其间有数据  
  
        g_uart3ReceiveSize =RECEIVE_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel3);  
        if(g_uart3ReceiveSize !=0)  
        {
       
            // 此处不处理数据,uart处理
        }  
          
        DMA_ClearFlag(DMA1_FLAG_TC3 | DMA1_FLAG_TE3 | DMA1_FLAG_HT3);//清除DMA2_Steam7传输完成标志  
        DMA_SetCurrDataCounter(DMA1_Channel3, RECEIVE_BUF_SIZE);  
        DMA_Cmd(DMA1_Channel3, ENABLE);     //打开DMA,  
    }  
} 

/*********************************************************************
 * LOCAL FUNCTIONS
 */
/**
 @brief 配置嵌套向量中断控制器NVIC
 @param 无
 @return 无
*/
static void NVIC_Configuration(void)
{
     
	NVIC_InitTypeDef NVIC_InitStructure;

	/* 嵌套向量中断控制器组选择 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	
	// 配置UART1发送  
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;    
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;    
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    
    NVIC_Init(&NVIC_InitStructure);    
	
	// 配置UART1接收 
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;    
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;    
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    
    NVIC_Init(&NVIC_InitStructure);    
	
	// 配置UART3发送  
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;    
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;    
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    
    NVIC_Init(&NVIC_InitStructure);    
	
	// 配置UART3接收 
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;    
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;    
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    
    NVIC_Init(&NVIC_InitStructure);    
}

main.c

int main()
{
     
	...
	USART_Config();
	DMA_Config();
	...
}


• 由 青梅煮久 写于 2021 年 02 月 20 日

你可能感兴趣的:(STM32,实例应用,嵌入式)