DMA,全稱Direct Memory Access,即直接存儲器訪問, DMA 傳輸方式無需 CPU 干預,通過硬件爲 RAM 和 I/O 設備開闢一條直接傳送數據的通路,能大大提高CPU的運行效率。
下面介紹stm32單片機的USART和DMA的配置過程:
step1:STM32串口配置
使用串口初始化函數來配置:
void usart_init(void)
{
//第一步:GPIO複用端口設置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA時鐘
//PA9複用爲串口1發送引腳
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //複用推輓輸出
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PA2複用爲串口1接收引腳
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//第二步:串口參數設置
USART_InitStructure.USART_BaudRate = 115200; //串口波特率,也可以設爲其他規定數
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長爲8位數據格式
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(USART1, &USART_InitStructure); //初始化串口1
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能串口1的DMA接收,這一點注意
USART_Cmd(USART1, ENABLE); //串口1使能
}
需要說明一下:程序中用的GPIO端口,不同的芯片,端口編號可能會不同,我們要根據實際情況進行調整。
step2:申請串口接收數據的存儲區域
存儲接收數據的內存必須在DMA配置前定義好。
#define USART_RBUFF_SIZE 100
char Usart_Rx_Buff[USART_RBUFF_SIZE]; //串口接收緩衝
step3:DMA配置
void USARTx_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
// 開啓DMA時鐘
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// 設置DMA源地址:串口數據寄存器地址*/
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)USART_DR_ADDRESS; //這個地址是串口數據寄存器的絕對地址,用戶可進行宏定義
// 內存地址(要傳輸的變量的指針)
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Usart_Rx_Buff;
// 方向:從內存到外設
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
// 傳輸大小
DMA_InitStructure.DMA_BufferSize = USART_RBUFF_SIZE;
// 外設地址不增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// 內存地址自增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// 外設數據單位
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Byte;
// 內存數據單位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
// DMA模式,一次或者循環模式
//DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// 優先級:中
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
// 禁止內存到內存的傳輸
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
// 配置DMA通道
DMA_Init(USART_RX_DMA_CHANNEL, &DMA_InitStructure);
// 清除DMA所有標誌
DMA_ClearFlag(DMA1_FLAG_GL5);
DMA_ITConfig(USART_RX_DMA_CHANNEL, DMA_IT_TE, ENABLE);
// 使能DMA
DMA_Cmd (USART_RX_DMA_CHANNEL,ENABLE);
}
step4:經過DMA接收數據並讀取數據的程序
DMA使能後,就能在定義的數組Usart_Rx_Buff[USART_RBUFF_SIZE]中讀到接收的數據了。
如果想在讀取完畢後,清空DMA,則可以使用如下代碼:
void DMA_Retrive_Rx_Data(void)
{
// 關閉DMA ,防止干擾
DMA_Cmd(USART_RX_DMA_CHANNEL, DISABLE);
// 清DMA標誌位
DMA_ClearFlag( DMA1_FLAG_GL5 );
// 重新賦值計數值,必須大於等於最大可能接收到的數據幀數目
USART_RX_DMA_CHANNEL->CNDTR = USART_RBUFF_SIZE;
//如果必要,清空數組
memset(Usart_Rx_Buff,0,USART_RBUFF_SIZE);
//重新使能DMA,接收數據
DMA_Cmd(USART_RX_DMA_CHANNEL, ENABLE);
}