概述
直接存儲器訪問(DMA)用于在外設(shè)與存儲器之間以及存儲器與存儲器之間提供高速數(shù)據(jù)傳輸??梢栽跓o需任何CPU操作的情況下通過DMA快速傳輸傳輸。這樣節(jié)省的CPU資源可供其它操作使用。
DMA允許在后臺執(zhí)行數(shù)據(jù)傳輸,無需Cortex-MO處理器干預(yù)。在此操作過程中,主處理器可以執(zhí)行其它任務(wù),僅當(dāng)整個(gè)數(shù)據(jù)塊需要處理時(shí),才會中斷主處理器。這樣即使傳輸大量數(shù)據(jù)也不會對系統(tǒng)性能造成太大影響。
DMA主要用于為不同的外設(shè)模塊實(shí)現(xiàn)集中數(shù)據(jù)緩沖存儲(通常在系統(tǒng)SRAM中)。與分布式解決方案(其中每個(gè)外設(shè)都需要實(shí)現(xiàn)自己的本地?cái)?shù)據(jù)存儲)相比,DMA解決方案在硅片成本和功耗方面的成本較低。
根據(jù)使用的產(chǎn)品型號的不同,有一個(gè)或兩個(gè)DMA模塊。
STM32F0XX DMA控制器總共有5個(gè)通道用于DMA1,每個(gè)通道都專門管理來自一個(gè)或多個(gè)外設(shè)的存儲器訪問請求。它具有一個(gè)仲裁器,用于處理不同的DMA請求的優(yōu)先級。
本篇文章主要介紹如何使用STM32CubeMX實(shí)現(xiàn)串口DMA讀取,并且打印出去。
在這里插入圖片描述
硬件準(zhǔn)備
首先需要準(zhǔn)備一個(gè)開發(fā)板,這里我準(zhǔn)備的是NUCLEO-F030R8的開發(fā)板:
在這里插入圖片描述
選擇芯片型號
使用STM32CUBEMX選擇芯片stm32f030r8,如下所示:
在這里插入圖片描述
配置時(shí)鐘源
HSE與LSE分別為外部高速時(shí)鐘和低速時(shí)鐘,在本文中使用內(nèi)置的時(shí)鐘源,故都選擇Disable選項(xiàng),如下所示:
在這里插入圖片描述
配置時(shí)鐘樹
STM32F0的最高主頻到48M,所以配置48即可:
在這里插入圖片描述
串口配置
本次實(shí)驗(yàn)使用的串口1進(jìn)行串口通信,波特率配置為115200。
配置DMA
中斷
在這里插入圖片描述
生成工程設(shè)置
在這里插入圖片描述
代碼生成設(shè)置
最后設(shè)置生成獨(dú)立的初始化文件:
在這里插入圖片描述
生成代碼
在這里插入圖片描述
配置keil
在這里插入圖片描述
代碼
在main.c中,添加頭文件,若不添加會出現(xiàn) identifier "FILE" is undefined報(bào)錯(cuò)。
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
變量定義:
/* USER CODE BEGIN PV */
#define BUFFERSIZE 255 //可以接收的最大字符個(gè)數(shù)
uint8_t ReceiveBuff[BUFFERSIZE]; //接收緩沖區(qū)
uint8_t recv_end_flag = 0,Rx_len;//接收完成中斷標(biāo)志,接收到字符長度
/* USER CODE END PV */
函數(shù)聲明和串口重定向:
/* USER CODE BEGIN PFP */
void uart1_data(void); //接收函數(shù)
#ifdef __GNUC__ //串口重定向
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END PFP */
開啟串口IDLE中斷:
/* USER CODE BEGIN 2 */
printf("串口1DMA例程
");
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能串口1 IDLE中斷
/* USER CODE END 2 */
主循環(huán):
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
uart1_data();//串口數(shù)據(jù)處理
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
串口DMA獲?。?/p>
/* USER CODE BEGIN 4 */
void uart1_data(void)
{
if(recv_end_flag ==1)//接收完成標(biāo)志
{
printf("數(shù)據(jù)長度=%d
",Rx_len);//打印接收到的數(shù)據(jù)長度
printf("數(shù)據(jù)內(nèi)容:");
for(int i=0;iprintf("%c",ReceiveBuff[i]);//向串口打印接收到的數(shù)據(jù)
}
printf("
");
for(int i = 0; i < Rx_len ; i++) //清空接收緩存區(qū)
ReceiveBuff[i]=0;//置0
Rx_len=0;//接收數(shù)據(jù)長度清零
recv_end_flag=0;//接收標(biāo)志位清零
}
//開啟下一次接收
HAL_UART_Receive_DMA(&huart1,(uint8_t*)ReceiveBuff,BUFFERSIZE);
}
/* USER CODE END 4 */
#include "stm32f0xx_it.c"文件中斷外部變量引用:
/* USER CODE BEGIN 0 */
#define BUFFERSIZE 255 //可接收的最大數(shù)據(jù)量
extern uint8_t recv_end_flag,Rx_len,bootfirst;
/* USER CODE END 0 */
串口1中斷函數(shù):
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
uint32_t temp;
if(USART1 == huart1.Instance)//判斷是否為串口1中斷
{
if(RESET != __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))//如果為串口1
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除中斷標(biāo)志
HAL_UART_DMAStop(&huart1);//停止DMA接收
temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);//獲取DMA當(dāng)前還有多少未填充
Rx_len = BUFFERSIZE - temp; //計(jì)算串口接收到的數(shù)據(jù)個(gè)數(shù)
recv_end_flag = 1;
}
}
/* USER CODE END USART1_IRQn 1 */
}
演示效果
在這里插入圖片描述
審核編輯:湯梓紅
-
控制器
+關(guān)注
關(guān)注
112文章
16133瀏覽量
177143 -
dma
+關(guān)注
關(guān)注
3文章
558瀏覽量
100367 -
USART
+關(guān)注
關(guān)注
1文章
195瀏覽量
30768 -
stm32cubemx
+關(guān)注
關(guān)注
5文章
280瀏覽量
14721
發(fā)布評論請先 登錄
相關(guān)推薦
評論