【STM32】HAL庫中的實現(七):DMA(直接存儲器訪問)

DMA 是什么?

DMA(Direct Memory Access)是 外設直接和內存之間數據搬運的機制,不需要 CPU 參與。

? 舉個例子:

傳統方式: ADC → CPU → RAM
使用 DMA:ADC → DMA → RAM(CPU 不需干預)

DMA分管著7條DMA通道,DMA2分管著5條DMA通道,不過只有大容量的芯片才會有DMA2。

請添加圖片描述
使用DMA的優點顯而易見:高效(無 CPU 干預),快速(并行執行),實時性好(適合高頻采樣),釋放 CPU(可以做其他任務)。


CubeMX 配置說明

ADC 配置(如下圖):

選項						設置
通道						IN10(PC0)
Regular Conversion		Enable
Trigger					Software Start
Sampling Time			239.5 cycles(穩定)

DMA 配置(如下圖):

選項					內容
Channel				DMA1 Channel 1
Direction			Peripheral to Memory
Mode				Circular(循環模式)?
Priority			Low(可調)注:Circular 模式:DMA 采完一圈自動從頭開始,適合連續采樣

請添加圖片描述

NVIC 中斷優先級設置
啟用:

? DMA1 Channel1 global interrupt
? ADC global interrupt
優先級可設置為較低(如 14)(不要和其他響應優先級沖突)

請添加圖片描述

工程結構

使用 DMA 方式從 ADC1(通道10) 采集數據,將數據通過 DMA 自動搬運到 ADC_Value[] 數組,串口打印采樣值。

使用 HAL 庫函數 HAL_ADC_Start_DMA()

  1. 變量定義(存儲一個通道的采樣值)
uint16_t ADC_Value[1] = {0};  // 存儲一個通道的采樣值
  • 也可以擴展為多通道:uint16_t ADC_Value[3];
  1. 啟動 DMA 采集
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_Value, 1);
  • 每次調用都會重啟 DMA 采樣(通常建議只啟一次)

     參數				含義&hadc1				ADC 1 句柄ADC_Value			數據存儲地址1					采樣通道個數(數據長度)
    
  1. 打印采樣值
printf("CH10 = %d\r\n", ADC_Value[0]); //每秒打印一次,觀察 ADC 值隨輸入電壓變化。

DMA 實現 ADC 的核心步驟:

步驟:
① CubeMX 配置 DMA(ADC1 → DMA1_Channel1)
② 設置 DMA 模式為 Circular
③ 啟用中斷(可選)
④ 寫代碼啟動采樣:HAL_ADC_Start_DMA()
⑤ 在主循環中讀取數組中的值
⑥ 可配合 HAL_ADC_ConvCpltCallback() 做中斷處理

數據流邏輯:

	   +------------+       +-------------+       +-------------+
AIN10 →|   ADC1     | ====> |    DMA      | ====> |   RAM數組    |+------------+       +-------------+       +-------------+↑                       ↓|                   不用CPU搬運|                   由DMA自動完成軟件觸發             Circular循環方式
完整代碼

📄 main.c

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "string.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint16_t ADC_Value[1] = {0};
/* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_USART1_UART_Init();MX_ADC1_Init();/* USER CODE BEGIN 2 */HAL_UARTEx_ReceiveToIdle_IT(  &huart1 , U1RxData, U1RxDataSize);HAL_ADCEx_Calibration_Start( &hadc1 );  //開啟校準/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){HAL_ADC_Start_DMA( &hadc1, (uint32_t* )ADC_Value, 1  );printf(" CH10 = %d \r\n",ADC_Value[0]);HAL_Delay(1000);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief  This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef  USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

因為DMA的CPU干預幾乎為0(除了啟動的時候),DMA在高頻采樣、連續采樣的場景中十分適用,可以配合ADC連續+DMA循環使用。


測試結果:

請添加圖片描述

其他測試結果的方法:

接電位器調節電壓			看 ADC 值是否變化
用波形發生器加信號			觀察 DMA 是否持續采樣
用示波器測試 PC0 電壓		與 ADC 值對應

可能會出現的場景問題排查:

問題								原因
ADC 值不變						沒有接電壓 / PC0 無信號
printf 值不更新					DMA 沒啟動成功 / ADC 沒觸發
HAL_ADC_Start_DMA 每次都調用		會重啟 DMA,建議只調用一次
串口亂碼							波特率不一致

其他擴展性應用:

擴展應用
多通道 DMA 采樣ADC + Scan Mode + DMA
ADC + DMA + 濾波DMA 采樣后做均值濾波
ADC + DMA + OLED實時顯示電壓變化曲線
ADC + DMA + FFT做聲音/振動頻譜分析
音頻采樣使用 ADC + DMA 連續采樣音頻信號

以上。這便是 STM32 中 打開DMA通道,啟用外設直接和內存之間數據搬運機制,用于數據的傳輸 的過程。

以上,歡迎有從事同行業的電子信息工程、互聯網通信、嵌入式開發的朋友共同探討與提問,我可以提供實戰演示或模板庫。希望內容能夠對你產生幫助!

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

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

相關文章

【LeetCode熱題100道筆記+動畫】字母異位詞分組

題目描述 給你一個字符串數組,請你將 字母異位詞 組合在一起。可以按任意順序返回結果列表。 示例 1: 輸入: strs = [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”] 輸出: [[“bat”],[“nat”,“tan”],[“ate”,“eat”,“tea”]] 解釋: 在 strs 中沒有字符串可…

【Kafka】常見簡單八股總結

為什么使用消息隊列? 解耦: 我以我的一段開發經驗舉例: 【Kafka】登錄日志處理的三次階梯式優化實踐:從同步寫入到Kafka多分區批處理 我做過一個登錄日志邏輯,就是在登錄邏輯末尾,加一段寫進數據庫登錄日志…

微信小程序連接到阿里云物聯網平臺

目錄準備階段阿里云配置下載mqtt.min.js文件小程序實現注意小程序配置服務器域名概述:介紹使用微信小程序連接到阿里云平臺的快捷方法和完整過程。 阿里云平臺建立設備,提供mqtt連接參數,小程序借助mqtt.min.js,也就是基于Github下…

2-3〔O?S?C?P? ? 研記〕? 漏洞掃描?AppScan(WEB掃描)

鄭重聲明: 本文所有安全知識與技術,僅用于探討、研究及學習,嚴禁用于違反國家法律法規的非法活動。對于因不當使用相關內容造成的任何損失或法律責任,本人不承擔任何責任。 如需轉載,請注明出處且不得用于商業盈利。 …

LeetCode 刷題【47. 全排列 II】

47. 全排列 II 自己做 解1&#xff1a;檢查重復 class Solution { public:void circle(vector<int> nums, vector<vector<int>> &res,int start){int len nums.size();if(start len - 1){ //到頭了//檢查重復bool is_exist fa…

Https之(一)TLS介紹及握手過程詳解

文章目錄簡介 TLSTLS第一次握手1.Client HelloTLS第二次握手2.Server Hello3.Certificate4.Server Hello DoneTLS第三次握手5.Client Key Exchange6.Change Cipher Spec7.Encrypted Handshake MessageTLS第四次握手8.New Session Ticket9.Change Cipher Spec10.Encrypted Hands…

【WEB 】從零實現一個交互輪播圖(附源碼)

文章目錄 一、輪播圖整體功能規劃二、HTML結構深度解析三、CSS樣式實現細節1. 定位系統詳解2. 顯示/隱藏機制3. 按鈕交互效果實現4. 純CSS箭頭實現5. 指示器&#xff1a;當前位置可視化 四、JavaScript邏輯深入解析1. 核心變量與DOM獲取2. 圖片切換函數&#xff08;核心邏輯&am…

機器學習--PCA降維

一核心部分 1解決的問題&#xff1a;應對高維數據帶來的計算量大、冗余信息多、易出現過擬合等問題&#xff0c;在減少數據維度的同時盡可能保留原始數據的關鍵信息。2核心思想&#xff1a…

leetcode 1277. 統計全為 1 的正方形子矩陣 中等

給你一個 m * n 的矩陣&#xff0c;矩陣中的元素不是 0 就是 1&#xff0c;請你統計并返回其中完全由 1 組成的 正方形 子矩陣的個數。示例 1&#xff1a;輸入&#xff1a;matrix [[0,1,1,1],[1,1,1,1],[0,1,1,1] ] 輸出&#xff1a;15 解釋&#xff1a; 邊長為 1 的正方形有…

知識蒸餾 - 各類概率分布

知識蒸餾 - 各類概率分布 flyfish一、離散概率分布 離散分布描述的是取值為離散值&#xff08;如0,1,2,…&#xff09;的隨機變量的概率規律&#xff0c;通常用概率質量函數&#xff08;PMF&#xff09; 表示某一取值的概率。 1. 伯努利分布&#xff08;Bernoulli Distribution…

軟件測試-Selenium學習筆記

""" 目標&#xff1a; driver.find_element() 需求&#xff1a; 1. 使用driver.find_element()方法 2. 輸入用戶名&#xff1a;admin 3. 輸入密碼&#xff1a;123456 """ # 導包 from selenium import webdriver from time import …

知微傳感3D相機上位機DkamViewer使用:給相機升級固件

寫在前面 本人從事機器視覺細分的3D相機行業。編寫此系列文章主要目的有&#xff1a; 1、便利他人應用相機&#xff0c;本系列文章包含公司所出售相機的SDK的使用例程及詳細注釋&#xff1b;2、促進行業發展及交流。 知微傳感Dkam系列3D相機可以應用于定位分揀、焊接焊縫提取、…

CMake進階: CMake Modules---簡化CMake配置的利器

目錄 1.簡介 2.為什么需要 CMake Modules&#xff1f; 3.內置模塊&#xff1a;開箱即用的工具 3.1.依賴查找模塊&#xff08;FindXXX.cmake&#xff09; 3.2.功能檢測模塊&#xff08;CheckXXX.cmake&#xff09; 3.3.通用工具模塊&#xff08;如 FetchContent.cmake、CT…

【Docker】Ubuntu上安裝Docker(網絡版)

【Docker】Ubuntu上安裝Docker注意&#xff1a;一、環境準備1. 系統要求2. 卸載舊版本二、安裝步驟1.配置倉庫源2.安裝 Docker引擎3.驗證安裝情況三、解決報錯1、檢查網絡連接2、檢查Docker服務狀態3、換源4.重載生效、重啟服務、查看是否配置成功5.驗證解決情況四、權限與配置…

Socket 編程 TCP

TCP 網絡程序 和剛才 UDP 類似. 實現一個簡單的英譯漢的功能。TCP是面向字節流的可靠傳輸&#xff0c;如同前文的管道流&#xff0c;只要是流&#xff0c;它的操作就是文件的寫出與讀入。TCP socket API 詳解下面介紹程序中用到的 socket API,這些函數都在 sys/socket.h 中。so…

使用AWS S3 + Lambda + MediaConvert 實現上傳視頻文件并自動轉碼

前言 最近團隊在做短視頻平臺的技術調研&#xff0c;其中有一個環節便是音視頻開發&#xff0c;即對用戶上傳的視頻進行自適應轉碼。自適應的原理其實就是預先將視頻轉換為幾個常用的分辨率&#xff0c;app端根據用戶手機分辨率拉取相應分辨率的視頻。 目前嘗試了兩種方案&…

QT之QWaitCondition降低cpu占用率,從忙等待到高效同步

在多線程編程中&#xff0c;線程間的同步是一個核心問題。在處理線程等待時&#xff0c;經常會寫出高CPU占用率的代碼&#xff0c;其中最典型的就是使用忙等待&#xff08;busy waiting&#xff09;。本文將詳細介紹如何使用Qt框架中的QWaitCondition類來優雅地解決這一問題&am…

pcl求平面點云的邊界凸包點

基本流程1&#xff0c;讀入點云&#xff0c;并去除無效點2&#xff0c;擬合平面3&#xff0c;去除離平面距離較遠的點4&#xff0c;對點云進行平面投影5&#xff0c;進行convex_hull運算初學者&#xff0c;暫時不知道能用來干嘛。練手還是非常不錯的&#xff01;#define _CRT_S…

Windows系統上使用GIT

首先破除一下畏懼心理&#xff1a;在Windows上使用git和在linux系統中的使用方法是一樣的&#xff0c;只是安裝方式沒那么便捷&#xff0c;畢竟linux中安裝git只需要一行命令 GIT下載地址 如果你的電腦的CPU是64位的&#xff0c;就點擊&#xff1a; Git-2.50.1-64-bit.exe 如果…

《設計模式之禪》筆記摘錄 - 17.模板方法模式

模板方法模式的定義模板方法模式(Template Method Pattern)是如此簡單&#xff0c;以致讓你感覺你已經能夠掌握其精髓了。其定義如下&#xff1a;Define the skeleton of an algorithm in an operation, deferring some steps to subclasses.Template Method lets subclasses r…