【詳細講解在STM32的UART通信中使用DMA機制】

詳細講解在STM32的UART通信中使用DMA機制

目錄

  • 詳細講解在STM32的UART通信中使用DMA機制
    • 一、DMA機制概述
    • 二、DMA在UART中的作用
    • 三、DMA的配置步驟
    • 四、UART初始化與DMA結合
    • 五、DMA傳輸的中斷處理
    • 六、DMA與中斷的結合使用
    • 七、注意事項與常見問題
    • 八、代碼示例
    • 九、總結

一、DMA機制概述

DMA(Direct Memory Access) 是一種硬件機制,允許外設不需要CPU干預的情況下直接訪問內存。它能夠顯著提升數據傳輸的效率,尤其是在需要頻繁數據傳輸的場景中。

二、DMA在UART中的作用

在STM32微控制器中, UART模塊支持DMA傳輸,能夠實現在CPU空閑的情況下,快速傳輸大量數據。具體來說,DMA可以將UART接收的數據直接傳輸到內存中的緩沖區,或者將內存中的數據緩沖區直接傳輸到UART發送緩沖區,從而降低CPU負載,提高系統效率。

三、DMA的配置步驟

  1. 使能DMA時鐘
    在使用DMA之前,需要先使能DMA外設的時鐘。不同的 DMA 通道對應不同的時鐘配置。
// 使能DMA1時鐘(例如,對于DMA1的信道)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  1. 設置DMA Channel和DMA Mode 配置DMA通道和傳輸模式(比如正常模式、循環模式等)。
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_Channel = DMA_Channel_0;  // 選擇DMA通道
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; // UART數據寄存器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)rxBuffer; // 接收緩沖區地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // 設置傳輸方向,外設到內存
DMA_InitStructure.DMA_BufferSize = RX_BUFFER_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_InitStructure.DMA_Mode = DMA_Mode_Normal; // DMA正常模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 設置DMA優先級為高
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; // FIFO模式關閉
DMA_Init(DMA1_Channel0, &DMA_InitStructure); // 初始化DMA通道
  1. 使能DMA傳輸 完成配置后,使能DMA通道。
DMA_Cmd(DMA1_Channel0, ENABLE);

四、UART初始化與DMA結合

  1. UART初始化配置 配置UART的基本參數,如波特率、數據格式、校驗位等。
// 配置USART1
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1, &USART_InitStructure);
  1. 配置UART的DMA傳輸 使能 UART的DMA傳輸功能,通常在UART的中斷配置中完成。
// 使能USART1的DMA接收功能
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);

五、DMA傳輸的中斷處理

  1. 配置DMA傳輸完成中斷 配置DMA傳輸完成后觸發中斷,以便進行后續處理。
    // 配置DMA中斷
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority = 2; // 中斷優先級
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
  2. 編寫DMA中斷服務函數 在中斷服務函數中進行數據處理和DMA重裝載操作。

void DMA1_Channel0_IRQHandler(void) {
if (DMA_GetFlagStatus(DMA1_Channel0, DMA_FLAG_TCIF0)) {
// 清除傳輸完成標志
DMA_ClearFlag(DMA1_Channel0, DMA_FLAG_TCIF0);
// 處理接收到的數據
processData(rxBuffer, RX_BUFFER_SIZE);
// 重新裝載DMA緩沖區
DMA_SetCurrDataCounter(DMA1_Channel0, RX_BUFFER_SIZE);
}
}

六、DMA與中斷的結合使用

1.DMA和中斷的區別
? DMA :在不占用CPU的情況下,直接完成內存和外設之間的數據傳輸,適合大數據量的傳輸。
? 中斷 :當外設需要CPU處理特定事件時,通過中斷機制通知CPU。

2.在UART通信中DMA的優勢
? 提高了數據傳輸的效率,減少了CPU的負載。
? 適用于需要大量數據傳輸的應用場景,如長時間的串口數據采集。

3.什么時候最適合使用DMA
? 當需要實現高效的、大量數據的UART傳輸時。
? 當希望降低CPU使用率,讓CPU專注于其他任務處理時。

七、注意事項與常見問題

1.DMA傳輸中的內存配置 確保DMA傳輸的內存區域是連續的,避免因內存碎片導致傳輸錯誤。

2.緩沖區的大小和管理 合理設置DMA傳輸的緩沖區大小,避免因為緩沖區過小而導致頻繁的DMA中斷,或因為緩沖區過大而導致內存浪費。

3.DMA傳輸方向的設置 根據實際需求設置正確的傳輸方向(外設到內存或內存到外設),否則會導致數據傳輸錯誤。

4.DMA優先級的設置 根據系統的實際工作情況,合理設置DMA通道的優先級,以確保關鍵任務的優先執行。

5.傳輸完成后DMA的重裝載 在DMA傳輸完成后,配置DMA為循環模式或手動重新裝載模式,以保證持續的數據傳輸需求。

八、代碼示例

以下是一個完整的示例代碼,展示了如何在STM32中配置和使用DMA進行UART數據接收:

#include "stm32f10x.h"#define RX_BUFFER_SIZE 256uint8_t rxBuffer[RX_BUFFER_SIZE];void DMA_Configuration(void) {DMA_InitTypeDef DMA_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;// 使能DMA1時鐘RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// 配置DMA通道0DMA_InitStructure.DMA_Channel = DMA_Channel_0;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)rxBuffer;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;DMA_InitStructure.DMA_BufferSize = RX_BUFFER_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_InitStructure.DMA_Mode = DMA_Mode_Normal;DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA1_Channel0, &DMA_InitStructure);// 使能DMA通道0DMA_Cmd(DMA1_Channel0, ENABLE);// 配置DMA中斷優先級NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);// 啟用DMA傳輸完成中斷DMA_ITConfig(DMA1_Channel0, DMA_IT_TC, ENABLE);
}
void USART_Configuration(void) {
USART_InitTypeDef USART_InitStructure;
// 使能USART1外設時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; // TX和RX引腳
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置USART
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1, &USART_InitStructure);
// 使能USART接收DMA
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
// 啟動USART
USART_Cmd(USART1, ENABLE);
}
void USART_NVIC_Configuration(void) {
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void USART1_IRQHandler(void) {
// 處理 USART 中斷,如有需要
//,...
}
void DMA1_Channel0_IRQHandler(void) {
if (DMA_GetFlagStatus(DMA1_Channel0, DMA_FLAG_TCIF0)) {
// 清除 DMA 傳輸完成標志
DMA_ClearFlag(DMA1_Channel0, DMA_FLAG_TCIF0);
// 數據處理操作
processData(rxBuffer, RX_BUFFER_SIZE);
// 重新裝載 DMA 緩沖區
DMA_SetCurrDataCounter(DMA1_Channel0, RX_BUFFER_SIZE);
}
}
int main(void) {
// 系統時鐘配置(假設已經完成)
// 配置DMA
DMA_Configuration();
// 配置USART1
USART_Configuration();
// 配置USART中斷
USART_NVIC_Configuration();
// 進入主循環
while (1) {
// 主循環可以執行其他任務
}
}

九、總結

通過在STM32的UART通信中使用DMA機制,可以在不占用CPU的情況下實現高效的數據傳輸,顯著提升系統的性能和響應速度。DMA的配置和使用需要仔細理解其工作原理和具體的配置步驟,確保在實際應用中的正確性和穩定性。
在實際開發中,還應結合具體的應用場景和硬件配置,進行合理的參數設置和優化,以達到最佳的傳輸效率和穩定

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

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

相關文章

M系列芯片 MacOS 在 Conda 環境中安裝 TensorFlow 2 和 Keras 3 完整指南

目錄 1. 引言2. 環境準備3. 安裝 TensorFlow 和必要依賴4. 結語Reference 1. 引言 Keras 是搞深度學習很可愛的工具,其友好的接口讓我總是將其作為搭建模型原型的首選。然而,當我希望在 M 系列芯片的MacBook Pro上使用 Keras時,使用Conda和P…

清華北大DeepSeek六冊

「清華北大-Deepseek使用手冊」 鏈接:https://pan.quark.cn/s/98782f7d61dc 「清華大學Deepseek整理) 1-6版本鏈接:https://pan.quark.cn/s/72194e32428a AI學術工具公測鏈接:https://pan.baidu.com/s/104w_uBB2F42Da0qnk78_ew …

paddlehub hub TypeError 錯誤

pip install paddlehub hub install chinese_ocr_db_crnn_mobile 提示錯誤: TypeError: Descriptors cannot be created directly. If this call came from a _pb2.py file, your generated code is out of date and must be regenerated with protoc > 3.19.0…

零信任沙箱:為網絡安全筑牢“隔離墻”

在數字化浪潮洶涌澎湃的今天,網絡安全如同一艘船在波濤洶涌的大海中航行,面臨著重重挑戰。數據泄露、惡意軟件攻擊、網絡釣魚等安全威脅層出不窮,讓企業和個人用戶防不勝防。而零信任沙箱,就像是一座堅固的“隔離墻”,…

【String】917. 僅僅反轉字母

917. 僅僅反轉字母 - 力扣(LeetCode) 使用雙指針,一個指針指向s的開始,一個指向s的末尾,同時遍歷即可。

大語言模型學習

大語言模型發展歷程 當前國內外主流LLM模型 ?一、國外主流LLM? ?LLaMA2? Meta推出的開源模型,參數規模涵蓋70億至700億,支持代碼生成和多領域任務適配?57。衍生版本包括Code Llama(代碼生成優化)和Llama Chat(對…

3dsmax烘焙光照貼圖然后在unity中使用

效果預覽 看不清[完蛋!] 實現步驟 使用 軟件 軟體名稱地址photoshophttps://www.adobe.com/products/photoshop.htmlunity3Dhttps://unity.com/3dsmaxhttps://www.autodesk.com.cn/products/3ds-max/free-trialpacker-iohttps://www.uv-packer.com/HDR 貼圖地址…

P8651 [藍橋杯 2017 省 B] 日期問題--注意日期問題中2月的天數 / if是否應該連用

P8651 [P8651 [藍橋杯 2017 省 B] 日期問題--注意日期問題中2月的天數 / if是否應該連用 題目 分析代碼 題目 分析 代碼中巧妙的用到3重循環,完美的解決了輸出的順序問題【題目要求從小到大】 需要注意的是2月的值,在不同的年份中應該更新2月的值 還有…

android 橫豎屏適配工作總結

1、創建一個橫屏文件夾,復制一份豎屏的布局。然后修改適配橫屏。只要布局id都有,其他想怎么改就怎么修改。 2、最好使用kotlin語言編寫和使用viewBinding綁定控件,可以使用?.判空控件是否存在,不至于缺少這個控件時候直接崩潰。 …

VS2022遠程調試Ubuntu中的C++程序

前言 最近想基于星火大模型的SDK開發第一些應用。但是,發現星火的SDK當中Linux版本的比較豐富,Windows 版本支持的比較少。但是,從調試的IDE而言,Visual Studio又是最方便的。所以,考慮采用Visual Studio Ubuntu的形式…

VS Code(Cursor)遠程開發調試教程(超詳細)

前言 📢 聲明:本文配置及開發方法同樣適合Cursor !! 在開始之前,你需要準備以下東西: 本地電腦: 安裝好 VS Code(Windows、Mac 或 Linux 都可以)。 官網下載&#xff0c…

【C++】類與對象:深入理解默認成員函數

類與對象:深入理解默認成員函數 引言1、默認成員函數概述2、構造函數與析構函數2.1 默認構造函數2.2 析構函數 3、拷貝控制成員3.1 拷貝構造函數3.2 賦值運算符重載 4、移動語義(C11)4.1 移動構造函數4.2 移動賦值運算符 5、三五法則與最佳實…

QT實現計算器

1:在注冊登錄的練習里面, 追加一個QListWidget 項目列表 要求:點擊注冊之后,將賬號顯示到 listWidget上面去 以及,在listWidget中雙擊某個賬號的時候,將該賬號刪除 Widget.h #ifndef WIDGET_H #define…

算法進階——二分

二分法: 一種高效查找方法,將問題搜索范圍一分為二,迭代地縮小范圍,直到找到目標。 二分法適用于有序的數據集合。 常見的二分類型有: 整數二分 浮點二分 二分答案 二分解題步驟: 1.研究并發現數據…

Kotlin函數式編程與Lambda表達式

Kotlin函數式編程與Lambda表達式 一、函數式編程基礎 1.1 什么是函數式編程 函數式編程是一種編程范式,它將計算過程視為數學函數的求值,強調使用不可變數據和純函數。在Kotlin中,函數式編程的特性讓我們能夠寫出更簡潔、更易維護的代碼。…

Java 并行流(parallelStream)詳解

目錄 1. 什么是 parallelStream?2. parallelStream 的優勢3. parallelStream 的使用3.1 基本使用3.2 計算總和示例3.3 結合groupingByConcurrent實現線程安全的分組操作 4. parallelStream 的注意事項4.1 適用場景4.2 并行流的局限性 5. 控制并行流線程數6. 總結 1.…

Ubuntu 20.04下配置VSCode以支持OpenCV庫開發

Ubuntu 20.04下配置VSCode以支持OpenCV庫開發 1. 安裝OpenCV庫安裝OpenCV(推薦使用APT安裝)或者從源碼安裝OpenCV(可選) 2. 安裝VSCode的C擴展3. 配置c_cpp_properties.json4. 編寫代碼并測試5. 配置tasks.json(編譯Op…

io學習----->標準io

思維導圖: 一.io的作用 io是實現對文件的操作,把運行結果存到文件中,讀取文件的數據,方便后期查詢。 二.io的概念 io是指系統 和外部設備或用戶之間的數據交互 I:input 表示數據從外部設備輸入到內存中; O:output…

使用消息隊列怎樣防止消息重復?

大家好,我是君哥。 使用消息隊列時,我們經常會遇到一個可能對業務產生影響的問題,消息重復。在訂單、扣款、對賬等對冪等有要求的場景,消息重復的問題必須解決。 那怎樣應對重復消息呢?今天來聊一聊這個話題。 1.三…

005 公網訪問 docker rocketmq

文章目錄 創建自定義網絡創建NameServer容器創建Broker容器正式開始啟動 Nameserver 容器啟動 Broker 容器并關聯 Nameserverdocker exec -it rmqbroker vi /etc/rocketmq/broker.conf檢查 namesrv 解析檢查 Broker 注冊狀態Nameserver 日志Broker 日志檢查容器日志手動指定 Br…