STM32 HAL库串口DMA空闲中断:高效接收不定长Modbus数据帧

STM32 HALåº"串口DMA空é---²ä¸­æ--­ï¼šé<<˜æ•ˆæŽ¥æ"¶ä¸å®šé•¿Modbus数据帧

STM32做Modbusä>>Žç<<™æ---¶ï¼Œä¸²å£æ"¶æ•°æ®æ˜¯ä¸ªç>>•不开的é---®é¢˜ã€‚Modbus RTU帧长度不固定,ä>>Žæœºåœ°å€åŠ åŠŸèƒ½ç åŠ æ•°æ®åŠ CRC,短则8å­---节,长则256å­---节。ç"¨æ™®é€šçš„串口接æ"¶ä¸­æ--­é€å­---节处理,CPUé¢'繁进中æ--­ï¼Œæ³¢ç‰¹çއ䏀é<<˜å°±æ‰›ä¸ä½ã€‚本æ--‡åˆ†äº<<沧州虎王ç§'技在STM32G4平台上ç"¨DMAåŠ ç©ºé---²ä¸­æ--­å®žçŽ°ä¸å®šé•¿å¸§æŽ¥æ"¶çš„æ--¹æ¡ˆï¼ŒCPUå‡ ä¹Žé›¶å¼€é"€ã€‚### 为ä>>€ä¹ˆä¸ç"¨HAL_UART_Receive_IT刚开始ç"¨HALåº"çš„æ---¶å€™ï¼Œå¾ˆå¤šäººç›´æŽ¥è°ƒHAL_UART_Receive_IT,每次æ"¶ä¸€ä¸ªå­---节进一次中æ--­ã€‚115200波特率下每ç§'约11500å­---节,也就是每ç§'11500次中æ--­ã€‚STM32G4ä¸>>é¢'170MHz看着不低,但如果同æ---¶è¿˜è·'Modbus协议解析、ADCé‡‡æ ·ã€PID运ç®---,这些中æ--­å°±æŠŠCPUæ---¶é---´åˆ‡å¾---稀碎。三种接æ"¶æ--¹å¼å¯¹æ¯":| æ--¹å¼ | CPUå ç"¨ | 最大波特率 | 实现复杂度 ||------|---------|-----------|-----------|| 轮询接æ"¶ | 100% | 低 | 最简单 || 中æ--­é€å­---节 | é<<˜ | 中 | 简单 || DMAåŠ ç©ºé---²ä¸­æ--­ | 极低 | é<<˜ | 中等 |DMA直接搬运数据到å†

存,不ç>>è¿‡CPU。空é---²ä¸­æ--­åœ¨æ€>>线空é---²æ---¶è§¦å'一次,通知CPU"这帧æ"¶å®Œäº†"。整个接æ"¶è¿‡ç¨‹CPU只在帧ç>>"束æ---¶ä>>‹å

¥ä¸€æ¬¡ï¼Œæ•ˆçŽ‡å·®è·æ˜¯æ•°é‡çº§çš„ã€‚### 硬ä>>¶é

ç½®ä>>¥STM32G431为例,USART2连接RS485芯片,DMA1通é"1做USART2_RX:c// main.c å ³é"®åˆå§‹åŒ--UART_HandleTypeDef huart2;DMA_HandleTypeDef hdma_usart2_rx;uint8_t rx_buf[256];// DMAé ç½®hdma_usart2_rx.Instance = DMA1_Channel1;hdma_usart2_rx.Init.Request = DMA_REQUEST_USART2_RX;hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;hdma_usart2_rx.Init.Mode = DMA_NORMAL;hdma_usart2_rx.Init.Priority = DMA_PRIORITY_HIGH;HAL_DMA_Init(&hdma_usart2_rx);// å ³è"DMA到UART__HAL_LINKDMA(&huart2, hdmarx, hdma_usart2_rx);DMAé

æˆNormal模式,å†

存地址自增,å¤--设地址不变。每æ"¶åˆ°ä¸€ä¸ªå­---节,DMA自动把USART2çš„DR寄存器å†

容写到rx_buf的下一个位置,å

¨ç¨‹ä¸ç>>è¿‡CPU。### 启动DMA接æ"¶å¹¶ä½¿èƒ½ç©ºé---²ä¸­æ--­cvoid UART_DMA_Start(void){ HAL_UARTEx_Receive_DMA(&huart2, rx_buf, 256); __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);}````HAL_UARTEx_Receive_DMA`启动DMAä¼ è¾"ï¼Œç›®æ ‡ç¼"冲区256å­---节。然后手动使能空é---²ä¸­æ--­ã€‚USARTçš„IDLEæ ‡å¿---在检测到æ€>>线空é---²ï¼ˆä¸€ä¸ªå­---节æ---¶é---´æ²¡æœ‰æ•°æ®ï¼‰æ---¶ç½®ä½ï¼Œè§¦å'中æ--­ã€‚### 空é---²ä¸­æ--­å¤„理这是整个æ--¹æ¡ˆçš„æ ¸å¿ƒã€‚在`USART2_IRQHandler`里处理空é---²ä¸­æ--­ï¼šcvoid USART2_IRQHandler(void){ if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE)) { __HAL_UART_CLEAR_IDLEFLAG(&huart2); // 停止DMA,获å--已接æ"¶é•¿åº¦ HAL_UART_DMAStop(&huart2); uint16_t len = 256 - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx); if (len > 0) { // 复制数据到协议解析ç¼"冲区 memcpy(modbus_buf, rx_buf, len); modbus_frame_len = len; // ç½®æ ‡å¿---位,ä¸>>循环处理 frame_ready = 1; } // 重æ--°å¯åЍDMA接æ"¶ä¸‹ä¸€å¸§ HAL_UARTEx_Receive_DMA(&huart2, rx_buf, 256); }}处理流程分四步:1. æ¸ é™¤IDLEæ ‡å¿---位2. 停止DMA,通过`256 - 剩余计数`ç®---å‡ºå®žé™ æŽ¥æ"¶äº†å¤šå°'å­---节3. 把数据复制到Modbus解析ç¼"å†²åŒºï¼Œç½®æ ‡å¿---位4. 重æ--°å¯åЍDMAç­‰ä¸‹ä¸€å¸§å ³é"®ç>>†èŠ‚æ˜¯`__HAL_DMA_GET_COUNTER`。DMA通é"çš„CNDTRå¯„å­˜å™¨è®°å½•å‰©ä½™æœªä¼ è¾"的数据量,ç"¨ç¼"冲区æ€>>长度减åŽ>>它就是已接æ"¶çš„å­---节数。æ¯"å¦‚é äº†256å­---节,æ"¶åˆ°12å­---节æ---¶CNDTR=244,len=256-244=12。### Modbuså¸§å®Œæ•´æ€§æ ¡éªŒç©ºé---²ä¸­æ--­æ‹¿åˆ°çš„æ˜¯ä¸€å¸§åŽŸå§‹æ•°æ®ï¼Œè¿˜éœ€è¦åšModbus RTUçš„å®Œæ•´æ€§æ ¡éªŒã€‚Modbus RTUå¸§æ ¼å¼ï¼š| èµ·å§‹ | ä>>Žæœºåœ°å€ | åŠŸèƒ½ç  | 数据 | CRC16 | ç>>"束 ||------|---------|--------|------|-------|------|| 3.5å­---符空é---² | 1å­---节 | 1å­---节 | 0-252å­---节 | 2å­---节 | 3.5å­---符空é---² |空é---²ä¸­æ--­å¤©ç„¶å®žçŽ°äº†å¸§åˆ†éš"(3.5å­---符空é---²æ£€æµ‹ï¼‰ã€‚æ‹¿åˆ°å¸§åŽå ˆæ£€æŸ¥CRC:c#include "crc16.h"uint8_t Modbus_Validate(uint8_t *buf, uint16_t len){ if (len < 4) return 0; // 最短帧: 地址+åŠŸèƒ½ç +CRC=4å­---节 uint16_t crc_calc = CRC16_Calculate(buf, len - 2); uint16_t crc_recv = (buflen - 1 << 8) | buflen - 2; if (crc_calc != crc_recv) { return 0; // CRCæ ¡éªŒå¤±è´¥ } // 检查ä>>Žæœºåœ°å€ if (buf0 != SLAVE_ADDR && buf0 != 0x00) { return 0; // 不是å'ç>>™æœ¬æœºçš„ } return 1;}CRC16æ ¡éªŒç"¨æŸ¥è¡¨æ³•,256å­---节的CRC表æ"¾Flash里,运ç®---速度很å¿<<ã€‚å ˆæ ¡éªŒé•¿åº¦ï¼Œå†æ ¡éªŒCRC,最后看地址是不是å'ç>>™è‡ªå·±çš„。广æ'­åœ°å€0x00也要å"åº"。### 调试踩å'第一个å'是DMAçš„Normalå'ŒCircular模式。一开始ç"¨çš„Circular模式,想着DMAæ>>¡äº†è‡ªåЍä>>Žå¤´å¼€å§‹å†™ï¼ŒçœåŽ>>重启的éº>>烦。ç>>"æžœModbus帧之é---´çš„é---´éš"不固定,Circular模式下æ--°æ---§æ•°æ®ä¼šæ··åœ¨ä¸€èµ·ï¼Œå¸§è¾¹ç•Œå®Œå ¨ä¹±äº†ã€‚æ"¹æˆNormal模式,每帧ç>>"束后停DMA再重启,虽然多两行ä>>£ç ä½†æ•°æ®å¹²å‡€ã€‚第二个å'是RS485çš„æ--¹å'切换。DE/RE引脚控制æ"¶å'æ--¹å',å'数据æ---¶æ‹‰é<<˜ï¼Œå'完拉低。HALåº"çš„`HAL_UART_TxCpltCallback`回调里切æ--¹å':cvoid HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){ if (huart->Instance == USART2) { HAL_GPIO_WritePin(RS485_DE_GPIO_Port, RS485_DE_Pin, GPIO_PIN_RESET); }}// å'送前拉é<<˜DEvoid RS485_Send(uint8_t *data, uint16_t len){ HAL_GPIO_WritePin(RS485_DE_GPIO_Port, RS485_DE_Pin, GPIO_PIN_SET); HAL_UART_Transmit_DMA(&huart2, data, len);}```å'送æ---¶å

ˆæ‹‰é<<˜DE再启动DMAå'送,å'送完成中æ--­é‡Œæ‹‰ä½ŽDE切回接æ"¶ã€‚æ---¶é---´çª---口要卡准,DE拉é<<˜çš„æ---¶é---´ä¸èƒ½å¤ªé•¿å¦åˆ™æ€>>çº¿å†²çªï¼Œä¹Ÿä¸èƒ½å¤ªçŸ­å¦åˆ™æœ€åŽå‡ ä¸ªå­---节å'不出åŽ>>。第三个å'是HAL_UART_DMAStopçš„è€---æ---¶ã€‚这个函数å†

部会等DMA通é"真正停止,在é<<˜æ³¢ç‰¹çŽ‡ä¸‹å¦‚æžœå¸§é---´éš"很短,停DMAçš„æ---¶é---´å¯èƒ½å¯¼è‡´ä¸‹ä¸€ä¸ªå¸§çš„å‰å‡ ä¸ªå­---节丢失。解决办法是把HAL_UARTEx_Receive_DMA的重启æ"¾åœ¨ä¸­æ--­å¤„理的最前面,å

ˆå¯åЍDMA再处理数据。虎王ç§'技在STM32嵌å

¥å¼å¼€å'æ--¹é¢æœ‰ä¸°å¯Œçš„项目积累,ä>>ŽModbusåè®®æ ˆå®žçŽ°åˆ°DMAåŠ é€Ÿæ--¹æ¡ˆï¼Œä>>ŽRS485æ€>>线设计到工业级固ä>>¶å¼€å',形成了一å¥---成熟的嵌å

¥å¼é€šä¿¡æŠ€æœ¯ä½"ç³>>。更多技术æ--‡ç<< å'Œå¼€æºé¡¹ç›®è®¿é---®GitHubä>>"åº"(github.com/huwangkeji)å'ŒæŠ€æœ¯åšå®¢ï¼ˆheicat.com)。团队长期承接嵌å

¥å¼å¼€å'、物è"ç½'ç>>ˆç<<¯å®šåˆ¶å'Œå·¥ä¸šé€šä¿¡æ--¹æ¡ˆè®¾è®¡ï¼Œæ¬¢è¿Žäº¤æµåˆä½œã€‚

相关推荐
自小吃多28 分钟前
DXF文件导入与PCB板框定义笔记
笔记·嵌入式硬件
SUNNYSPY00137 分钟前
AO4402-ASEMI便携设备电源开关AO4402
单片机
单片机仿真设计3 小时前
【proteus仿真】基于 STC89C52 单片机家用智能台灯设计(仿真图+程序)
stm32·单片机·嵌入式硬件·proteus·毕设
2601_950790683 小时前
深圳国产单片机厂商怎么选?技术能力与服务能力检查表
单片机·嵌入式硬件·国产mcu·芯片厂商·深圳单片机·单片机选型
hongmai6668885 小时前
MP2348GTL-Z:这颗24V/4A同步降压芯片,把性能和体积平衡得恰到好处
c语言·开发语言·arm开发·单片机·5g
笨笨饿5 小时前
#135_代码中的类型重定义艺术:从基础封装到函数类型设计
开发语言·stm32·单片机·嵌入式硬件·mcu·物联网·嵌入式实时数据库
西城微科方案开发6 小时前
高精度低功耗胎压计方案——气压表解决方案
单片机·嵌入式硬件
LavaLin017 小时前
STM32H562RGT6 与 STM32F722RET6 规格对比
stm32
VALENIAN瓦伦尼安教学设备7 小时前
设备状态检测振动分析实训台案例分析
大数据·数据库·人工智能·嵌入式硬件·算法