一、DMA 簡介
DMA(Direct Memory Access)—直接存盤器存取,是單片機的一個外設,它的主要功能是用來搬資料,但是不需要占用 CPU,即在傳輸資料的時候,CPU 可以干其他的事情,好像是多執行緒一樣,
資料傳輸支持從外設到存盤器或者存盤器到存盤器,這里的存盤器可以是 SRAM 或者是 FLASH,
DMA 控制器包含了 DMA1 和 DMA2,其中 DMA1 有 7 個通道,DMA2 有 5 個通道,這里的通道可以理解為傳輸資料的一種管道,要注意的是 DMA2 只存在于大容量的單片機中,
二、DMA 功能框圖
DMA 控制器獨立于內核,屬于一個單獨的外設,結構比較簡單,從編程的角度來看,我們只需掌握功能框圖中的三部分內容即可,具體見下圖:

- ①DMA 請求
如果外設要想通過 DMA 來傳輸資料,必須先給 DMA 控制器發送 DMA 請求,DMA收到請求信號之后,控制器會給外設一個應答信號,當外設應答后且 DMA 控制器收到應答信號之后,就會啟動 DMA 的傳輸,直到傳輸完畢,
DMA 有 DMA1 和 DMA2 兩個控制器,DMA1 有 7 個通道,DMA2 有 5 個通道,不同的 DMA 控制器的通道對應著不同的外設請求,這決定了我們在軟體編程上該怎么設定,具體見 DMA 請求映像表,

-
②通道
DMA 具有 12 個獨立可編程的通道,其中 DMA1 有 7 個通道,DMA2 有 5 個通道,每個通道對應不同的外設的 DMA 請求,雖然每個通道可以接收多個外設的請求,但是同一時間只能接收一個,不能同時接收多個, -
③仲裁器
當發生多個 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
----------------------------------------------------------------------------
<Date> | <Version> | <Author> | <Description>
-------------|-----------|----------------|---------------------------------
2021/02/20 | r0.1 | 青梅煮久 | 創建
-------------|-----------|----------------|---------------------------------
| | |
-------------|-----------|----------------|---------------------------------
| | |
-------------|-----------|----------------|---------------------------------
| | |
============================================================================*/
#ifndef __USART_H
#define __USART_H
/*********************************************************************
* INCLUDES
*/
#include "stm32f10x.h"
#include <stdio.h>
/*********************************************************************
* 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
----------------------------------------------------------------------------
<Date> | <Version> | <Author> | <Description>
-------------|-----------|----------------|---------------------------------
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
----------------------------------------------------------------------------
<Date> | <Version> | <Author> | <Description>
-------------|-----------|----------------|---------------------------------
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
----------------------------------------------------------------------------
<Date> | <Version> | <Author> | <Description>
-------------|-----------|----------------|---------------------------------
2021/02/19 | r0.1 | 青梅煮久 | 創建
-------------|-----------|----------------|---------------------------------
| | |
-------------|-----------|----------------|---------------------------------
| | |
-------------|-----------|----------------|---------------------------------
| | |
============================================================================*/
/*********************************************************************
* INCLUDES
*/
#include "bsp_dma.h"
#include <stdio.h>
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 日
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/261802.html
標籤:其他
