單片機STM32F103:DMA的原理以及應用

STM32F103系列微控制器(基于ARM Cortex-M3內核)集成了**DMA(Direct Memory Access,直接內存訪問)**控制器,用于在存儲器與外設、存儲器與存儲器之間高效傳輸數據,減少CPU的干預,從而提升系統性能。本文將詳細介紹STM32F103的DMA原理、架構、功能特性及使用方法,結合實際代碼示例說明如何在開發中應用DMA,特別以STM32CubeMX和HAL庫為工具。


1. DMA原理

DMA是一種硬件機制,允許數據在存儲器(Flash、SRAM)或外設(UART、SPI、ADC等)之間直接傳輸,而無需CPU逐字節處理。其核心思想是將數據搬運任務交給DMA控制器,CPU只需配置DMA通道并啟動傳輸,傳輸完成后通過中斷或查詢方式獲取結果。

1.1 工作原理
  • DMA控制器:STM32F103的DMA控制器管理多個通道,每個通道負責特定的數據傳輸任務。
  • 數據流
    • 存儲器到存儲器:如SRAM到SRAM。
    • 外設到存儲器:如ADC數據到SRAM。
    • 存儲器到外設:如SRAM數據到UART發送緩沖區。
  • 觸發機制
    • DMA傳輸可由軟件觸發(手動啟動)或硬件觸發(外設請求,如UART發送完成)。
  • 中斷支持
    • 傳輸完成(TC)、半傳輸(HT)或傳輸錯誤(TE)時可觸發中斷。
  • 優勢
    • 降低CPU負載,適合高吞吐量任務(如ADC采樣、音頻流)。
    • 提高實時性,適合多任務系統。
1.2 STM32F103的DMA架構

STM32F103的DMA控制器分為DMA1DMA2(部分高密度型號支持DMA2),具體特性如下:

  • DMA1
    • 7個通道(Channel 1-7)。
    • 連接到APB1/APB2外設(如UART、SPI、ADC)及存儲器。
  • DMA2(僅高密度型號,如STM32F103ZET6):
    • 5個通道(Channel 1-5)。
    • 通常用于高級外設或額外存儲器訪問。
  • 通道優先級
    • 每個通道可配置高、中、低優先級,解決多通道沖突。
  • 數據寬度
    • 支持8位、16位、32位數據傳輸。
  • 傳輸模式
    • 單次傳輸:傳輸固定長度數據后停止。
    • 循環模式:傳輸完成后自動重新開始,適合連續數據流。
    • 增量模式:支持源/目標地址自動遞增或固定。
  • FIFO:STM32F103的DMA無獨立FIFO,依賴外設緩沖區或直接傳輸。
1.3 DMA工作流程
  1. 配置DMA通道
    • 設置源地址、目標地址、數據長度。
    • 配置傳輸方向(存儲器到外設、外設到存儲器、存儲器到存儲器)。
    • 設置數據寬度、優先級、增量模式等。
  2. 啟動傳輸
    • 軟件觸發(設置ENABLE位)或硬件觸發(外設信號)。
  3. 數據傳輸
    • DMA控制器從源地址讀取數據,寫入目標地址。
  4. 完成處理
    • 傳輸完成后,觸發中斷或置位標志,通知CPU處理結果。

2. STM32F103 DMA功能特性

  • 通道數量
    • DMA1:7通道,支持ADC1/2、SPI1/2、UART1-3、I2C1/2、TIM1-4等。
    • DMA2(若有):5通道,支持高級外設或額外存儲器。
  • 傳輸方向
    • 存儲器到存儲器(僅DMA1支持)。
    • 外設到存儲器(如ADC采樣到SRAM)。
    • 存儲器到外設(如SRAM數據到UART)。
  • 中斷支持
    • 傳輸完成中斷(TCIF)。
    • 半傳輸中斷(HTIF)。
    • 傳輸錯誤中斷(TEIF)。
  • 數據對齊
    • 支持字節(8位)、半字(16位)、字(32位)傳輸。
    • 源和目標數據寬度可不同(如8位外設到16位SRAM)。
  • 循環模式
    • 啟用后,傳輸完成后自動重新加載計數器,適合連續數據流。
  • 優先級管理
    • 軟件配置通道優先級(Very High, High, Medium, Low)。
    • 硬件仲裁確保高優先級通道優先訪問總線。

3. DMA使用方法

以下以STM32F103C8T6為例,結合STM32CubeMX和HAL庫,介紹如何實現DMA傳輸,重點以ADC DMA(外設到存儲器)和UART DMA(存儲器到外設)為例。

3.1 開發環境準備
  • 硬件
    • STM32F103C8T6開發板(如“藍板”)。
    • ST-Link V2調試器。
    • USB-TTL模塊(如CH340)用于串口調試。
  • 軟件
    • STM32CubeMX:配置外設和DMA。
    • STM32CubeIDE:編寫和調試代碼。
    • STM32CubeProgrammer:燒錄程序。
    • 串口終端(如PuTTY):查看輸出。
3.2 示例1:ADC DMA(外設到存儲器)

目標:使用ADC1連續采樣多個通道的數據,通過DMA傳輸到SRAM緩沖區。

3.2.1 STM32CubeMX配置
  1. 創建項目
    • 打開STM32CubeMX,選擇STM32F103C8T6。
  2. 配置ADC
    • 在“Analog”中啟用ADC1。
    • 配置通道(如IN0、IN1,連接到PA0、PA1)。
    • 設置為“Continuous Conversion Mode”(連續轉換)。
    • 啟用“DMA Continuous Requests”。
  3. 配置DMA
    • 在ADC1的“DMA Settings”中,添加DMA請求:
      • 選擇DMA1 Channel 1(ADC1默認通道)。
      • 設置:
        • Mode:Circular(循環模式)。
        • Data Width:Half Word(16位,ADC為12位數據)。
        • Increment Address:Memory(目標地址遞增)。
        • Priority:Medium。
  4. 配置時鐘
    • 設置HSE(8MHz晶振),PLL倍頻到72MHz,APB2為72MHz,ADC時鐘分頻到12MHz(最大14MHz)。
  5. 生成代碼
    • 在“Project Manager”中設置項目名稱、路徑,選擇“STM32CubeIDE”。
    • 生成代碼。
3.2.2 代碼實現

在STM32CubeIDE中,修改main.c實現ADC DMA采樣:

#include "main.h"
#include "adc.h"
#include "dma.h"
#include "usart.h"
#include "stdio.h"#define ADC_CHANNEL_COUNT 2
uint16_t adcData[ADC_CHANNEL_COUNT]; // 存儲ADC采樣數據void SystemClock_Config(void);int main(void) {HAL_Init();SystemClock_Config();MX_DMA_Init();MX_ADC1_Init();MX_USART1_UART_Init(); // 串口用于調試// 啟動ADC DMAHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcData, ADC_CHANNEL_COUNT);while (1) {// 在循環模式下,DMA自動更新adcDatachar msg[50];sprintf(msg, "ADC1: %u, ADC2: %u\r\n", adcData[0], adcData[1]);HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 100);HAL_Delay(1000); // 每秒打印一次}
}// DMA傳輸完成回調(可選)
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {// 可在此處理傳輸完成后的邏輯
}

說明

  • HAL_ADC_Start_DMA啟動ADC和DMA,數據自動傳輸到adcData數組。
  • 循環模式下,DMA自動更新緩沖區,CPU無需干預。
  • 串口(UART1)打印ADC采樣值,用于調試。
3.2.3 測試
  • 燒錄程序到STM32F103。
  • 連接PA0/PA1到模擬信號(如電位器)。
  • 在串口終端(如PuTTY,115200波特率)查看ADC采樣值。
3.3 示例2:UART DMA(存儲器到外設)

目標:通過DMA將SRAM中的數據發送到UART1。

3.3.1 STM32CubeMX配置
  1. 配置UART
    • 啟用USART1(PA9-TX,PA10-RX)。
    • 設置波特率(如115200),模式為異步。
    • 在“DMA Settings”中,添加DMA請求:
      • 選擇DMA1 Channel 4(USART1_TX默認通道)。
      • 設置:
        • Mode:Normal(單次傳輸)。
        • Data Width:Byte(8位,UART數據)。
        • Increment Address:Memory。
        • Priority:Medium。
  2. 生成代碼
    • 同ADC示例,生成STM32CubeIDE項目。
3.3.2 kazhuCode實現

修改main.c實現UART DMA發送:

#include "main.h"
#include "dma.h"
#include "usart.h"
#include "string.h"uint8_t txData[] = "Hello, STM32 DMA!\r\n";void SystemClock_Config(void);void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {// 傳輸完成回調HAL_UART_Transmit(&huart1, (uint8_t*)"TX Complete\r\n", 13, 100);
}int main(void) {HAL_Init();SystemClock_Config();MX_DMA_Init();MX_USART1_UART_Init();// 啟動UART DMA發送HAL_UART_Transmit_DMA(&huart1, txData, strlen((char*)txData));while (1) {HAL_Delay(1000); // 每秒發送一次HAL_UART_Transmit_DMA(&huart1, txData, strlen((char*)txData));}
}

說明

  • HAL_UART_Transmit_DMA啟動DMA傳輸,將txData發送到UART1。
  • 傳輸完成后,觸發HAL_UART_TxCpltCallback中斷。
  • 單次模式下,需手動重新啟動傳輸。
3.3.3 測試
  • 燒錄程序。
  • 連接USB-TTL模塊(PA9->RX,PA10->TX)。
  • 在串口終端查看輸出“Hello, STM32 DMA!”。

4. 關鍵配置注意事項

  • DMA初始化順序
    • main.c中,MX_DMA_Init必須在其他外設初始化(如MX_ADC1_InitMX_USART1_Init)之前調用,確保DMA時鐘啟用。
  • 通道選擇
    • 每個外設有固定DMA通道(如ADC1->DMA1 Channel 1,USART1_TX->DMA1 Channel 4)。參考STM32F103參考手冊。
  • 數據對齊
    • 源和目標數據寬度需匹配(如ADC為16位,緩沖區應為uint16_t)。
  • 中斷管理
    • 啟用DMA中斷(如HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn))。
    • 在中斷回調中處理傳輸完成或錯誤。
  • 循環模式 vs 單次模式
    • 循環模式適合連續數據流(如ADC采樣)。
    • 單次模式適合一次性傳輸(如UART發送固定字符串)。
  • 優先級沖突
    • 多通道同時傳輸時,設置高優先級給關鍵任務(如ADC優于UART)。

5. 常見問題及解決

  • DMA不工作
    • 檢查DMA通道是否與外設匹配。
    • 確保MX_DMA_Init在其他外設初始化前調用。
    • 驗證源/目標地址正確,數據長度非零。
  • 數據錯誤
    • 檢查數據寬度(Byte/Half Word/Word)是否與外設匹配。
    • 確保目標緩沖區有足夠空間。
  • 中斷未觸發
    • 確認中斷使能(HAL_DMA_Start_IT或外設API)。
    • 檢查NVIC配置(優先級、使能)。
  • 總線沖突
    • 避免多個DMA通道同時訪問同一存儲器區域。
    • 調整通道優先級或降低傳輸速率。

6. 擴展應用

  • 多通道ADC:使用DMA采集多個ADC通道數據,存儲到數組,適合信號處理。
  • SPI DMA:實現高速SPI數據傳輸(如與LCD或Flash通信)。
  • FreeRTOS集成:結合DMA中斷和信號量,優化實時任務調度。
  • 雙緩沖技術:在循環模式下使用兩個緩沖區交替存儲數據,避免數據覆蓋。

7. 學習資源

  • 官方文檔
    • STM32F103參考手冊(DMA章節)。
    • STM32CubeMX用戶手冊。
  • 教程
    • 正點原子/野火的STM32 DMA教程。
    • ST社區論壇的DMA應用筆記(如AN2548)。
  • 工具
    • STM32CubeMonitor:監控DMA傳輸數據。
    • 邏輯分析儀:調試外設信號。

8. 總結

STM32F103的DMA控制器通過高效的數據傳輸,顯著降低CPU負載,適合高吞吐量場景。DMA1支持7通道,DMA2(部分型號)支持5通道,覆蓋ADC、UART、SPI等外設。使用STM32CubeMX配置DMA參數,結合HAL庫(如HAL_ADC_Start_DMAHAL_UART_Transmit_DMA)可快速實現傳輸。關鍵注意初始化順序、通道選擇和數據對齊,通過中斷和循環模式優化性能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/88598.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88598.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88598.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Webview 中可用的 VS Code 方法

在 VS Code Webview 的 HTML 中,不能直接調用 VS Code 的 API(如 vscode.window.showInformationMessage),但可以通過 acquireVsCodeApi() 獲取一個受限的 vscode 對象,用于與插件主程序通信。以下是詳細說明和示例&am…

Qt:布局管理器Layout

目錄 布局管理器 QVBoxLayout QHBoxLayout QGirdLayout QFormLayout Spacer 布局管理器 在以往的界面操作上,都是程序員手動拖動控件來布局,這種方式有一些不足之處,比如不能很好的把握控件之間的距離,以及控件的大小&…

【Java編程動手學】深入剖析Java網絡編程:原理、協議與應用

文章目錄一、引言二、計算機網絡基礎1、計算機網絡的概念2、網絡地址的重要性三、套接字編程:網絡通信的基石1、套接字的概念2、TCP通信編程示例四、TCP通信編程:可靠的數據傳輸1、TCP協議的特點2、實際應用中的TCP通信五、UDP通信編程:高效的…

vue3.2 前端動態分頁算法

文章目錄背景思路頁面情況核心代碼小結效果背景 1. 后臺接口只是動態返回一個數組的數據,前端需要根據數據量的大小判斷是否需要分頁,頁面高度固定2. 頁面根據頁數大小有不同的展示a. 只有一頁 頭部 內容 統計 尾部b. 多頁i. 第一頁 頭部 內容 尾…

UC瀏覽器PC版自2016年后未再更新不支持vue3

win uc瀏覽器,點擊頁面觸發異常。UC瀏覽器PC版自2016年后未再更新(最新版本停留在Chromium 50內核)。其內置內核版本較低(如Trident/Blink舊版),無法支持Vue 3等現代前端框架的語法特性(如ES6、…

亞古數據:澳大利亞公司的ABN和ACN號碼是什么?

在跨國商業的迷宮中,了解目標市場的公司注冊細節是一項不可或缺的技能。對于與中國企業有業務往來的朋友們來說,澳大利亞這片充滿機遇的土地上,兩個縮寫——ABN與ACN,如同解鎖合作之門的密鑰,顯得尤為重要。今天&#…

LangChain框架 Prompts、Agents 應用

目錄 (Prompts)提示作用 Prompts 常見操作 基礎 PromptTemplate 使用 Few-shot 提示模板 ChatPromptTemplate (對話提示模板) (Agents)代理作用 Agents 常見操作 基礎 Agent 使用 自定義工具 Agent 高級應用示例 帶記憶的對話代理 使用本地模型的代理 結構化輸出代…

模擬實現unordered_map

1.定義unordered_map 是 C 標準庫中的哈希表容器,特點是無序存儲、平均 O (1) 時間復雜度的插入 / 查找 / 刪除操作。其核心原理是通過哈希函數將關鍵字映射到哈希桶(bucket),再通過鏈表或紅黑樹處理哈希沖突。2.實現原理1. 哈希表…

史上最詳細Java并發多線程(面試必備,一篇足矣)

第一章:線程基礎 1.1 線程與進程 進程:系統資源分配的基本單位,擁有獨立的內存空間 線程:CPU調度的基本單位,共享進程內存空間 關系:一個進程可包含多個線程,線程切換成本遠低于進程 1.2 線程的…

【DataFlow】數據合成流水線工具

1.整體解讀 核心思想:以數據為中心的AI(Data-Centric AI) DataFlow 的核心目標是通過一系列自動化“流水線”(Pipelines)來處理和生成高質量的數據,從而提升大語言模型(LLM)在特定領…

Hangfire 調用報錯解決方案總結

System.ArgumentNullException: 值不能為 null 錯誤在使用 Hangfire 時確實是一個常見問題,特別是在配置 Hangfire 服務器時。問題分析這個錯誤通常發生在以下情況:沒有正確配置 Hangfire 服務器隊列配置缺失或不正確連接字符串配置問題解決方案要點正確…

MySQL的使用

MySQL的使用一、mysql中的周邊命令1. 檢查版本2. 查看字符集3. 查看客戶端連接4. 查看最后一條警告消息二、數據庫、數據表的管理1. 語法規則2. 數據庫2.1 查看數據庫2.2 創建數據庫2.3 選擇數據庫2.4 查看創建數據庫命令2.5 創建庫時添加字符集2.6 修改數據庫字符集2.7 刪除數…

2025Nginx最新版講解/面試

維護系統多服務器部署,將我們請求代理到各個服務器。代理正向代理,代理對象是我們的客戶端,目標對象不知道我們用戶。VPN就是典型的正向代理。反向代理,代理對象是服務端,用戶不知道服務端具體信息。而這正是Nginx所做…

JAVASCRIPT 前端數據庫-V8--仙盟數據庫架構-—-—仙盟創夢IDE

老版本 在v1 版本中我們講述了 基礎版的應用 JAVASCRIPT 前端數據庫-V1--仙盟數據庫架構-—-—仙盟創夢IDE-CSDN博客 接下載我們做一個更復雜的的其他場景 由于,V1查詢字段必須 id 接下來我們修改了了代碼 JAVASCRIPT 前端數據庫-V2--仙盟數據庫架構-—-—仙盟創…

UNIX 域套接字實現本地進程間通信

🚀 使用 UNIX 域套接字 (AF_UNIX) 實現高效進程通信 在 Linux 和其他類 UNIX 系統中,進程間通信 (IPC) 的方法有很多種,例如管道、消息隊列、共享內存等。然而,當你的應用程序需要在 同一臺機器上的不同進程間進行高效、低延遲的數…

【Axure教程】中繼器間圖片的傳遞

中繼器在Axure中可以作為圖片保存的數據庫,在實際系統中,我們經常需要將選擇數據庫的圖片添加到其他圖片列表中,所以今天就教大家,怎么在Axure中實現中繼器之間的圖片傳遞,包含將一個中繼器中的圖片列表傳遞到另一個中…

專題:2025云計算與AI技術研究趨勢報告|附200+份報告PDF、原數據表匯總下載

原文鏈接:https://tecdat.cn/?p42935 關鍵詞:2025, 云計算,AI 技術,市場趨勢,深度學習,公有云,研究報告 云計算和 AI 技術正以肉眼可見的速度重塑商業世界。過去十年,全球云服務收…

從代碼學習深度強化學習 - PPO PyTorch版

文章目錄 前言PPO 算法簡介從 TRPO 到 PPOPPO 的兩種形式:懲罰與截斷代碼實踐:PPO 解決離散動作空間問題 (CartPole)環境與工具函數定義策略與價值網絡PPO 智能體核心實現訓練與結果代碼實踐:PPO 解決連續動作空間問題 (Pendulum)環境準備適用于連續動作的網絡PPO 智能體 (連…

PortsWiggerLab: Blind OS command injection with output redirection

實驗目的This lab contains a blind OS command injection vulnerability in the feedback function.The application executes a shell command containing the user-supplied details. The output from the command is not returned in the response. However, you can use o…

星云穿越與超光速飛行特效的前端實現原理與實踐

文章目錄 1,引言2,特效設計思路3,技術原理解析1. 星點的三維分布2. 視角推進與星點運動3. 三維到二維的投影4. 星點的視覺表現5. 色彩與模糊處理4,關鍵實現流程圖5,應用場景與優化建議6,總結1,引言 在現代網頁開發中,炫酷的視覺特效不僅能提升用戶體驗,還能為產品增添…