STM32 HAL庫USART串口DMA IDLE中斷編程:避坑指南

HAL_UART_Receive接收最容易丟數據了,STM32 HAL庫UART查詢方式實例

可以考慮用中斷來實現,但是HAL_UART_Receive_IT還不能直接用,容易數據丟失,實際工作中不會這樣用,STM32 HAL庫USART串口中斷編程:演示數據丟失,

需要在此基礎優化一下.?STM32F103 HAL庫USART串口中斷,利用環形緩沖區來防止數據丟失.

本文介紹STM32F103 HAL庫USART串口DMA IDLE中斷.

IDLE 中斷 在串口通信里,IDLE 代表空閑狀態,其定義為:總線在一個字節的傳輸時間內未再接收到新數據。

或許有人會有疑問:UART 的DMA RxD 引腳初始狀態就是空閑的,那 IDLE 中斷會一直觸發嗎?其實并非如此。當我們使能 IDLE 中斷后,它不會立即產生。只有在至少接收到 1 個數據后,若發現接下來一個字節的時間里都沒有新數據到來,才會觸發 IDLE 中斷。

使用 DMA 進行數據接收時,雖然能顯著提升 CPU 的使用效率,但也存在一個問題,即“無法預先知曉要接收的數據量”。然而,我們往往希望能盡快處理接收到的數據。舉個例子,假設我們打算讀取 150 字節的數據,但在接收到 50 字節后,對方停止了數據發送,這種情況下該如何判斷數據傳輸已經中止呢?此時,IDLE 中斷就起作用了。

坑在HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)的DMA的半滿中斷-UART_DMARxHalfCplt,關閉 DMA 的半傳輸完成中斷? ? __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);? ?

目錄

?一、開發環境

二、配置STM32CubeMX

三、代碼實現與部署

四、運行結果:

?五、注意事項


主要是5個函數的調用和實現.

HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);? ?void circle_buf_init(p_circle_buf pCircleBuf, uint32_t len, uint8_t *buf);//初始化環形緩沖區int circle_buf_read(p_circle_buf pCircleBuf, uint8_t *pVal);//讀取環形緩沖區int circle_buf_write(p_circle_buf pCircleBuf, uint8_t val);//寫環形緩沖區

1.HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);調用此函數后,務必關閉 DMA 的半傳輸完成中斷。若未關閉,當接收到超過數據總長度一半的數據時,系統不僅會觸發一次空閑中斷,還會觸發一次半傳輸完成中斷。而這兩個中斷均會調用一次HAL_UARTEx_RxEventCallback?回調函數,導致該回調函數總共被調用兩次。

2.__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT); 禁用與 USART1 接收相關的 DMA 通道的半傳輸完成中斷。

__HAL_DMA_DISABLE_IT?是一個 HAL 庫提供的宏,專門用于禁用 DMA 的特定中斷。

&hdma_usart1_rx是指向 USART1 接收所用 DMA 句柄的指針,明確要操作的是哪個 DMA 通道。

DMA_IT_HT代表半傳輸完成中斷(Half Transfer Complete Interrupt),指定要禁用的具體中斷類型。

3.從源頭到調用回調函數的調用過程, ?HAL_UARTEx_ReceiveToIdle_DMA->UART_Start_Receive_DMA(huart, pData, Size)->huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt或? huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt;

DMA1_Channel5_IRQHandler->HAL_DMA_IRQHandler(&hdma_usart1_rx)->? hdma->XferHalfCpltCallback(hdma)或hdma->XferCpltCallback(hdma);

?一、開發環境

硬件:正點原子精英版?V2?STM32F103開發板

單片機:STM32F103ZET6

Keil版本:5.32

STM32CubeMX版本:6.9.2

STM32Cube?MCU Packges版本:STM32F1xx_DFP.2.4.1
串口:USART1(PA9,PA10)

二、配置STM32CubeMX

1.啟動STM32CubeMX,新建STM32CubeMX項目?

2.選擇MCU:在軟件中選擇你的STM32型號-STM32F103ZET6。?

3.選擇時鐘源:

4.配置時鐘:

?5.使能Debug功能:Serial Wire

?6.HAL庫時基選擇:SysTick

7.USART1配置:選擇異步模式,使能中斷。

8.配置工程參數:在Project標簽頁中,配置項目名稱和位置,選擇工具鏈MDK-ARM。? 9.生成代碼:在Code Generator標簽頁中,配置工程外設文件與HAL庫,勾選頭文件.c和.h文件分開,然后點擊Project > Generate Code生成代碼。?

三、代碼實現與部署

?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 "dma.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include"circle_buffer.h"/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
extern UART_HandleTypeDef huart1;
extern DMA_HandleTypeDef hdma_usart1_rx;
static circle_buf g_CircleBuf;
uint32_t buf_len;
static uint8_t g_RecvChar;
static uint8_t g_RecvTempBuf[10];
static uint8_t g_RecvBuf[150];
int UART1_read(uint8_t *pVal)
{return circle_buf_read(&g_CircleBuf, pVal);
}/* 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 */
char *str= "hello\r\n";
char c;
/* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 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();/* USER CODE BEGIN 2 */HAL_UART_Transmit(&huart1,str,strlen(str),1000);circle_buf_init(&g_CircleBuf, 150, g_RecvBuf);//初始化環形緩沖區HAL_UARTEx_ReceiveToIdle_DMA (&huart1,g_RecvTempBuf,10);//一開始就打開中斷__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);    //關閉DMA本身的半傳輸中斷/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */while (0 != UART1_read(&c)); HAL_UART_Transmit(&huart1, &c, 1, 1000);HAL_UART_Transmit(&huart1, "\r\n", 2, 1000);}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {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();}
}/* USER CODE BEGIN 4 */
static volatile int g_rx_cplt = 0;void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{for (int i = 0; i < Size; i++){circle_buf_write(&g_CircleBuf, g_RecvTempBuf[i]);}HAL_UARTEx_ReceiveToIdle_DMA(&huart1, g_RecvTempBuf, 10);//重新開中斷__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);    //關閉DMA本身的半傳輸中斷}
/* 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 */

2.增加代碼circle_buffer.h,circle_buffer.c

#ifndef _CIRCLE_BUF_H
#define _CIRCLE_BUF_H#include <stdint.h>typedef struct circle_buf {uint32_t r;uint32_t w;uint32_t len;uint8_t *buf;
}circle_buf, *p_circle_buf;void circle_buf_init(p_circle_buf pCircleBuf, uint32_t len, uint8_t *buf);int circle_buf_read(p_circle_buf pCircleBuf, uint8_t *pVal);int circle_buf_write(p_circle_buf pCircleBuf, uint8_t val);#endif /* _CIRCLE_BUF_H */
#include <stdint.h>
#include "circle_buffer.h"void circle_buf_init(p_circle_buf pCircleBuf, uint32_t len, uint8_t *buf)
{pCircleBuf->r = pCircleBuf->w = 0;pCircleBuf->len = len;pCircleBuf->buf = buf;
}int circle_buf_read(p_circle_buf pCircleBuf, uint8_t *pVal)
{if (pCircleBuf->r != pCircleBuf->w){*pVal = pCircleBuf->buf[pCircleBuf->r];pCircleBuf->r++;if (pCircleBuf->r == pCircleBuf->len)pCircleBuf->r = 0;return 0;}else{return -1;}
}int circle_buf_write(p_circle_buf pCircleBuf, uint8_t val)
{uint32_t next_w;next_w = pCircleBuf->w + 1;if (next_w == pCircleBuf->len)next_w = 0;if (next_w != pCircleBuf->r){pCircleBuf->buf[pCircleBuf->w] = val;pCircleBuf->w = next_w;return 0;}else{return -1;}
}

??3.連接USART1:用USB轉TTL工具連接當前硬件USART1的PA9、PA10,GND。???

?4.打開串口助手:???

?5.編譯代碼:Keil編譯生成的代碼。

?6.燒錄程序:將編譯好的程序用ST-LINK燒錄到STM32微控制器中。

四、運行結果

1. 程序燒錄完成并運行,復位打印hello,發送"abcdefghij"時候,打印"abcdefghij",數據沒有丟失.??2.可以把兩處關閉半滿中斷的程序屏蔽__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);?,觀察現象,編譯燒錄完成并運行,復位打印hello,發送"abcdefghij"時候,打印"abcdeabcdefghij","abcde"重復了,不正確.?

?五、注意事項

1.確保你的開發環境和工具已經正確安裝和配置。

2.如果沒有打印,按一下復位鍵,檢查連接和電源是否正確,注意根據你所用的硬件來接線,不要接錯線。
3.在串口打印數據時,要確保波特率等參數與串口助手設置一致。

通過上述步驟,講解STM32F103 HAL庫USART串口DMA IDLE中斷.坑在HAL_UARTEx_ReceiveToIdle_DMA()的DMA的半滿中斷-UART_DMARxHalfCplt.僅供參考,有任何問題,歡迎在評論區留言討論!

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

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

相關文章

sql注入中information_schema被過濾的問題

目錄 一、information_schema庫的作用 二、獲得表名 2.1 sys.schema_auto_increment_columns 2.2 schema_table_statistics 三、獲得列名 join … using … order by盲注 子查詢 在進行sql注入時&#xff0c;我們經常會使用information_schema來進行爆數據庫名、表名、…

Jenkins 給任務分配 節點(Node)、設置工作空間目錄

Jenkins 給任務分配 節點(Node)、設置工作空間目錄 創建 Freestyle project 類型 任務 任務配置 Node 打開任務-> Configure-> General 勾選 Restrict where this project can be run Label Expression 填寫一個 Node 的 Label&#xff0c;輸入有效的 Label名字&#x…

Electron:使用electron-react-boilerplate創建一個react + electron的項目

使用 electron-react-boilerplate git clone --depth 1 --branch main https://github.com/electron-react-boilerplate/electron-react-boilerplate.git your-project-name cd your-project-name npm install npm start 安裝不成功 在根目錄加上 .npmrc文件 內容為 electron_…

數控機床設備分布式健康監測與智能維護系統MTAgent

數控機床設備分布式健康監測與智能維護系統MTAgent-v1.1融合了目前各種先進的信號處理以及信息分析算法以算法工具箱的方式&#xff0c;采用了一種開發的、模塊化的結構實現信號各種分析處理&#xff0c;采用Python編程語言&#xff0c;滿足不同平臺需求(包括Windows、Linux)。…

FPGA VIVADO:axi-lite 從機和主機

FPGA VIVADO:axi-lite 從機和主機 TOC在這里插入代碼片 前言 協議就不詳細講解了&#xff0c;直接看手冊即可。下面主要如何寫代碼和關鍵的時序。 此外下面的代碼可以直接用于實際工程 一、AXI-LITE 主機 數據轉axi lite接口&#xff1a; 讀/寫數據FIFO緩存 仲裁&#xff1a…

1. 對比 LVS 負載均衡群集的 NAT 模式和 DR 模式,比較其各自的優勢 。2. 基于 openEuler 構建 LVS-DR 群集。

DR 模式 * 負載各節點服務器通過本地網絡連接&#xff0c;不需要建立專用的IP隧道 原理&#xff1a;首先負載均衡器接收到客戶的請求數據包時&#xff0c;根據調度算法決定將請求發送給哪個后端的真實服務器&#xff08;RS&#xff09;。然后負載均衡器就把客戶端發送的請求數…

ollama server啟動服務后如何停止

要停止 Ollama 服務器服務&#xff0c;取決于如何啟動該服務的。以下是幾種常見的啟動方法和相應的停止服務的步驟&#xff1a; 1. 直接在命令行中啟動 如果是在命令行中直接啟動 Ollama 服務器的&#xff0c;例如使用以下命令&#xff1a; ollama serve 可以通過以下方式停…

【設計模式】03-理解常見設計模式-行為型模式(專欄完結)

前言 前面我們介紹完創建型模式和創建型模式&#xff0c;這篇介紹最后的行為型模式&#xff0c;也是【設計模式】專欄的最后一篇。 一、概述 行為型模式主要用于處理對象之間的交互和職責分配&#xff0c;以實現更靈活的行為和更好的協作。 二、常見的行為型模式 1、觀察者模…

mapbox基礎,使用geojson加載line線圖層,實現純色填充、圖片填充、虛線和漸變效果

????? 主頁: gis分享者 ????? 感謝各位大佬 點贊?? 收藏? 留言?? 加關注?! ????? 收錄于專欄:mapbox 從入門到精通 文章目錄 一、??前言1.1 ??mapboxgl.Map 地圖對象1.2 ??mapboxgl.Map style屬性1.3 ??line線圖層樣式二、??使用geojson加載…

深入淺出:CUDA是什么,如何利用它進行高效并行計算

在當今這個數據驅動的時代&#xff0c;計算能力的需求日益增加&#xff0c;特別是在深度學習、科學計算和圖像處理等領域。為了滿足這些需求&#xff0c;NVIDIA推出了CUDA&#xff08;Compute Unified Device Architecture&#xff09;&#xff0c;這是一種并行計算平臺和編程模…

LNMP+Zabbix安裝部署(Zabbix6.0 Lnmp+Zabbix Installation and Deployment)

LNMPZabbix安裝部署&#xff08;Zabbix6.0&#xff09; 簡介 LNMP&#xff08;Linux Nginx MySQL PHP&#xff09;是一種流行的Web服務器架構&#xff0c;廣泛用于搭建高性能的網站和應用程序。Zabbix 是一個開源的監控軟件&#xff0c;可以用來監控網絡、服務器和應用程序…

Docker 部署 Dify:輕松集成 Ollama 和 DeepSeek

1 Ollama的安裝及使用 1.1 什么是Ollama&#xff1f; Ollama 是一個用于本地部署和運行大型語言模型的框架。 Ollama 的作用包括&#xff1a; 本地模型運行&#xff1a;Ollama 允許在本地機器上運行大型語言模型&#xff08;如 LLaMA、DeepSeek 等&#xff09;&#xff0c;無…

C++筆記之標準庫中用于處理迭代器的`std::advance`和`std::distance`

C++筆記之標準庫中用于處理迭代器的std::advance和std::distance code review! 文章目錄 C++筆記之標準庫中用于處理迭代器的`std::advance`和`std::distance`一.`std::advance`函數原型參數說明使用場景示例代碼示例 1:移動 `std::vector` 的隨機訪問迭代器示例 2:移動 `st…

工業制造能耗管理新突破,漫途MTIC-ECM平臺助力企業綠色轉型!

在工業制造領域&#xff0c;能源消耗一直是企業運營成本的重要組成部分。隨著“雙碳”目標的推進&#xff0c;如何實現高效能耗管理&#xff0c;成為制造企業亟待解決的問題。漫途MTIC-ECM能源能耗在線監測平臺&#xff0c;結合其自研的硬件產品&#xff0c;為工業制造企業提供…

C語言——深入理解指針(2)(數組與指針)

文章目錄 數組名的理解使用指針訪問數組一維數組傳參的本質冒泡排序二級指針指針數組指針數組模擬二維數組 數組名的理解 之前我們在使用指針訪問數組內容時&#xff0c;有這樣的代碼&#xff1a; int arr[10]{1,2,3,4,5,6,7,8,9,10}; int* p&arr[0];這里我們使用&ar…

在Windows系統中安裝Open WebUI并連接Ollama

Open WebUI是一個開源的大語言模型&#xff08;LLM&#xff09;交互界面&#xff0c;支持本地部署與離線運行。通過它&#xff0c;用戶可以在類似ChatGPT的網頁界面中&#xff0c;直接操作本地運行的Ollama等大語言模型工具。 安裝前的核心要求&#xff1a; Python 3.11&#…

Day4:強化學習之Qlearning走迷宮

一、迷宮游戲 1.環境已知 迷宮環境是定義好的&#xff0c;障礙物位置和空位置是已知的&#xff1b; # 定義迷宮 grid [[0, 0, 0, 1, 0],[0, 1, 0, 1, 0],[0, 1, 0, 0, 0],[0, 0, 0, 1, 0],[0, 1, 1, 1, 0] ] 2.獎勵方式已知 如果碰到障礙物則得-1&#xff0c;如果到終點則…

家里WiFi信號穿墻后信號太差怎么處理?

一、首先在調制解調器&#xff08;俗稱&#xff1a;貓&#xff09;測試網速&#xff0c;網速達不到聯系運營商&#xff1b; 二、網線影響不大&#xff0c;5類網線跑500M完全沒問題&#xff1b; 三、可以在臥室增加輔助路由器&#xff08;例如小米AX系列&#xff09;90~200元區…

視點開場動畫實現(九)

這個相對比較簡單&#xff1a; void COSGObject::FlyTo(double lon, double lat, double hei) {theApp.bNeedModify TRUE;while(!theApp.bCanModify)Sleep(1);em->setViewpoint(osgEarth::Viewpoint("0",lon, lat, 0, 0, -45, hei), 2);theApp.bNeedModify FAL…

保姆級GitHub大文件(100mb-2gb)上傳教程

GLF&#xff08;Git Large File Storage&#xff09;安裝使用 使用GitHub desktop上傳大于100mb的文件時報錯 The following files are over 100MB. lf you commit these files, you will no longer beable to push this repository to GitHub.com.term.rarWe recommend you a…