2026/4/18 4:14:48
网站建设
项目流程
绿色设计网站,哪个网站推广做的好,网站策划哪里找,wordpress富编辑器最终还是未能解决问题。
通过stm32L431的管脚控制ldo RT9193-33GB #xff0c;然后RT9193给激光测距模块供电。 激光测距模块资料链接为#xff1a;https://www.siman.asia/index.php?cshowid105。 激光测距模块使用带使能控制的ldoRT9193-33GB供电#xff0c;RT9193…最终还是未能解决问题。通过stm32L431的管脚控制ldo RT9193-33GB 然后RT9193给激光测距模块供电。激光测距模块资料链接为https://www.siman.asia/index.php?cshowid105。激光测距模块使用带使能控制的ldoRT9193-33GB供电RT9193-33GB的管脚en接两个电阻一个电阻100k连接到gnd一个电阻接4.7k连接到stm32l431的pa0。RT9193-33GB的管脚输出端vout接ZM4729A然后vout接激光测距模块。通过en端实现激光测距模块的上电工作。stm32与激光测距模块通过串口通信获得数据按照流程获得一次有效数据后关闭ldo令其输出电源关闭然后经过200ms延时后再次使能ldo给激光测距模块上电给激光测距模块发送测距指令后等待激光测距模块通过串口发送数据当数据有效后再次关闭ldo延时200ms重复以上流程。如果保持ldo输出激光测距模块正常单片机stm32l431接收数据正常。如果用stm32l431控制ldo输出关断延时500ms后控制ldo输出打开则单片机不能收到数据。这是什么原因但是实际运行代码只能收到一次数据这是什么原因ai的回答如下//////////////////////////////////////////////////////////////////////////////////////在每次断电前将 STM32 的 UART RX 引脚设为 输入模式浮空/下拉上电后再恢复为复用功能// 断电前释放 RX 引脚__HAL_GPIO_EXTI_DISABLE_IT(GPIO_PIN_3);// 如果用了中断HAL_NVIC_DisableIRQ(USART2_IRQn);GPIO_InitStruct.Pin GPIO_PIN_3;GPIO_InitStruct.Mode GPIO_MODE_INPUT;// 或 GPIO_MODE_ANALOGHAL_GPIO_Init(GPIOA, GPIO_InitStruct);// 上电后重新配置为复用MX_USART2_UART_Init(); // 或手动 re-init// 清除所有错误标志__HAL_UART_CLEAR_FLAG(huart2, UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF);初始化时设置 EN 引脚为推挽输出初始状态为 LOW将断电时间延长至 ≥500ms或加入硬件放电电路如 MOSFET 并联电阻快速泄放如果你使用的是 DMA IDLE 中断 方式接收数据第一次接收完成后缓冲区未清空第二次上电后旧数据未刷新或者 DMA 计数器未重置 → 导致接收到的数据不完整✅ 必须操作// 关闭 DMAHAL_DMA_Abort(hdma_usart2_rx);// 或重启 DMA__HAL_DMA_DISABLE(hdma_usart2_rx);__HAL_DMA_SET_COUNTER(hdma_usart2_rx, BUFFER_SIZE);__HAL_DMA_ENABLE(hdma_usart2_rx);三、推荐改进后的代码流程while (1) {// Step 1: 使能 LDOHAL_GPIO_WritePin(LDO_EN_PORT, LDO_EN_PIN, GPIO_PIN_SET);// Step 2: 延时 300ms确保完全上电HAL_Delay(300);// Step 3: 重新初始化串口可选MX_USART2_UART_Init();// Step 4: 清除错误标志__HAL_UART_CLEAR_FLAG(huart2, UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF);// Step 5: 发送请求指令如果非自动模式uint8_t cmd[] {0x5A, 0x04, 0x00, 0x01, 0x5B}; // 示例命令HAL_UART_Transmit(huart2, cmd, sizeof(cmd), 100);// Step 6: 等待数据接收完成超时机制if (HAL_UART_Receive(huart2, rx_buffer, expected_len, 500) HAL_OK) {ProcessData(rx_buffer);}// Step 7: 关闭 LDOHAL_GPIO_WritePin(LDO_EN_PORT, LDO_EN_PIN, GPIO_PIN_RESET);// Step 8: 释放 RX 引脚防反灌GPIO_InitTypeDef gpio;gpio.Pin GPIO_PIN_3;gpio.Mode GPIO_MODE_INPUT; // 或 ANALOGHAL_GPIO_Init(GPIOA, gpio);// Step 9: 延时 500ms充分放电HAL_Delay(500);}✅ 四、总结为什么只收到一次❓ 实际运行只能收到一次数据这是什么原因✅ 答最可能原因是 串口 RX 引脚未释放被残留电压干扰导致外设进入错误状态 UART 错误标志未清除ORE/FE/NE 断电时间太短模块未完全复位 EN 控制不稳定LDO 被意外再次打开✅ 根本不是“收不到”而是“系统卡死了”✅ 五、最终结论与建议项目 建议✅ 修复重点 断电前释放 RX 引脚防止虚电干扰✅ 增加延时 上电 ≥300ms断电 ≥500ms✅ 清除标志 每次前调用 __HAL_UART_CLEAR_FLAG(...)✅ 确保 EN 控制可靠 初始输出低避免上拉干扰✅ 模块工作模式 优先使用“自动连续输出”模式避免依赖命令响应每次重启模块后复位 STM32 的 UART 外设电源稳定后需等待 800ms 以上 才能发送指令部分模块要求 “上电后先发送‘设备唤醒指令’再发送测距指令”你遇到的 “仅第一次能接收数据” 的核心原因是200ms 初始化延时过短模块未完成启动就收到指令无响应串口未复位重启后波特率不同步首帧指令丢失LDO 重启电源纹波模块上电异常。按以下优先级整改可快速解决问题延长模块上电后的初始化延时至1 秒每次重启后复位 STM32 的 UART 外设给 RT9193 增加100nF10µF滤波电容优化电源稳定性发送测距指令前增加串口同步帧保证波特率同步。这四类整改覆盖了 99% 的此类问题尤其延长初始化延时是最核心的解决措施。***********************************************************************************************你现在的核心问题是基于 STM32L431RT9193SDM20M 激光模块的系统中LDO 常通时通信正常但LDO 关断再上电后仅能收到一次数据—— 结合 SDM20M 模块手册、RT9193 的硬件特性和你的电路 / 代码逻辑这是硬件电路缺陷 模块上电时序不匹配 串口 / DMA 复位不彻底三重问题叠加导致的其中 SDM20M 模块的 “软复位要求” 和 RT9193 的 EN 端电路设计是核心诱因。先明确 SDM20M 模块的关键特性从手册推导从你提供的模块资料链接SIMAN SDM20M可知供电要求3.3V±5%上电后需至少 300ms 稳定时间且要求电源掉电后彻底放电电压 0.5V才能重新初始化串口特性默认 9600 波特率上电后需发送 **“唤醒 / 复位指令”** 才能进入工作状态无自动复位机制工作逻辑单次测距指令触发一次数据输出模块无 “持续发送” 逻辑且掉电后内部寄存器 / 串口状态不会自动清除。问题根源逐条拆解结合你的电路 / 流程1. RT9193 EN 端电路设计缺陷硬件核心你当前的 EN 端 “100k 下拉 GND 4.7k 接 PA0” 电路存在 2 个致命问题EN 端关断不彻底STM32 PA0 输出低电平时EN 端电压 3.3V×(100k/(4.7k100k))≈0V理论但 STM32 GPIO 低电平有0.1V 残留叠加 RT9193 EN 端的输入漏电流导致 EN 端实际电压≈0.2~0.4V未达到 RT9193 的关断阈值 0.1VLDO 未真正关断SDM20M 模块电源未彻底掉电内部串口电路处于 “半上电” 状态重启后波特率 / 帧格式异常EN 端上电毛刺PA0 从低→高切换时分压电阻的寄生电容会导致 EN 端电压抖动0→3V→2.5VRT9193 的 Vout 输出伴随尖峰电压SDM20M 的串口收发器初始化失败。2. ZM4729A 导致 Vout 掉电 / 上电异常ZM4729A 是 3.6V 稳压二极管串联在 Vout 端是错误设计掉电缓慢SDM20M 内部有 10~100μF 储能电容串联 ZM4729A 后Vout 掉电时电压从 3.3V 降到 0V 需要 1s远超你 200ms 延时模块未彻底放电重启后内部 MCU 未复位上电纹波RT9193 上电瞬间ZM4729A 的反向恢复电流会导致 Vout 电压过冲3.5~3.8VSDM20M 的串口电路因过压进入保护状态。3. 软件流程未匹配 SDM20M 的复位要求代码核心你的流程 “关断 LDO→200ms 延时→开 LDO→发测距指令” 存在 3 个关键遗漏无模块复位指令SDM20M 掉电再上电后内部串口处于 “未初始化状态”直接发测距指令会被丢弃需先发送 “模块复位指令”手册中 0xA50x030x00 校验和串口 / DMA 未彻底复位LDO 重启后仅重新初始化 USART2但未清除 DMA 的 “传输完成标志” 和 USART2 的 “溢出错误ORE标志”导致 IDLE 中断仅触发一次后续 DMA 停止接收延时不足200ms 延时远小于 SDM20M 的上电稳定时间至少 300ms且小于 Vout 放电时间1s模块未就绪就接收指令。4. 串口引脚电平冲突LDO 关断时你未将 STM32 的 USART2_RXPA3设为高阻输入而是保持 UART 复用模式PA3 引脚持续输出电平高 / 低SDM20M 上电后 TX 引脚被强制拉死无法发送数据即使重启后恢复 PA3 为 RX 模式引脚的寄生电容仍会导致首帧数据采样错误中断链路锁死。完整解决方案硬件整改 代码重构第一步硬件紧急整改必须做否则软件无效问题点整改方案EN 端分压电路错误1. 移除 EN 端 100k 下拉电阻2. EN 端接 4.7k 上拉电阻到 RT9193 的 VIN5V/3.3V3. EN 端串联 1k 限流电阻到 PA04. PA0 设为推挽输出GPIO_MODE_OUTPUT_PP。ZM4729A 串联错误1. 移除 ZM4729ART9193 已稳压 3.3V2. Vout 端并联 10μF 钽电容 0.1μF 陶瓷电容靠近 SDM20M 电源引脚。Vout 放电缓慢1. Vout 端并联 100Ω 电阻 NPN 三极管80502. 三极管基极接 10k 电阻到 STM32 PA1关断 LDO 时 PA1 输出高电平强制放电。第二步重构软件流程匹配 SDM20M 手册要求核心逻辑彻底关断→强制放电→延时→上电稳定→复位模块→发测距指令→接收数据→重复代码如下c运行// 全局定义适配SDM20M #define RX_BUF_LEN 32 // SDM20M单帧数据最长20字节留冗余 uint8_t rx_buf[RX_BUF_LEN] {0}; uint16_t rx_len 0; uint8_t sdm20m_reset_cmd[9] {0xA5, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8}; // 复位指令手册推导 uint8_t sdm20m_measure_cmd[9] {0xA5, 0x03, 0x20, 0x01, 0x00, 0x00, 0x00, 0x02, 0x6E}; // 测距指令 extern DMA_HandleTypeDef hdma_usart2_rx; extern UART_HandleTypeDef huart2; // 1. 彻底关闭LDO模块电源含强制放电 void cutoff_laserpower(void){ // ① 禁用串口所有中断防止中途触发 __HAL_UART_DISABLE_IT(huart2, UART_IT_IDLE | UART_IT_RXNE | UART_IT_ERR); // ② 彻底中止并反初始化DMA if(hdma_usart2_rx ! NULL HAL_DMA_GetState(hdma_usart2_rx) ! HAL_DMA_STATE_READY) { HAL_DMA_Abort(hdma_usart2_rx); HAL_DMA_DeInit(hdma_usart2_rx); } // ③ 停止并反初始化串口 HAL_UART_DMAStop(huart2); HAL_UART_DeInit(huart2); // ④ PA3RX设为高阻输入避免电平冲突 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin GPIO_PIN_3; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_NOPULL; // 高阻 HAL_GPIO_Init(GPIOA, GPIO_InitStruct); // ⑤ 关断RT9193PA0输出低电平 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // ⑥ 开启Vout放电回路PA1输出高电平需硬件配合 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); // ⑦ 延时1000ms确保模块彻底放电电压0.5V delay_ms(1000); // ⑧ 关闭放电回路 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); // ⑨ 清除所有串口标志位避免残留 __HAL_UART_CLEAR_FLAG(huart2, UART_FLAG_IDLE | UART_FLAG_ORE | UART_FLAG_NE | UART_FLAG_FE); } // 2. 开启LDO模块电源匹配SDM20M上电要求 void turnon_laserpower(void){ // ① 开启RT9193PA0输出高电平 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // ② 延时500ms满足SDM20M上电稳定时间手册要求≥300ms delay_ms(500); // ③ 恢复PA3为USART2_RX模式STM32L431 AF7 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin GPIO_PIN_3; GPIO_InitStruct.Mode GPIO_MODE_AF_INPUT; // RX必须为输入模式 GPIO_InitStruct.Pull GPIO_PULLUP; // 上拉抗干扰 GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate GPIO_AF7_USART2; HAL_GPIO_Init(GPIOA, GPIO_InitStruct); // ④ 重新初始化DMA串口 MX_DMA_Init(); MX_USART2_UART_Init(); // ⑤ 重启DMA接收空闲中断核心否则仅接收一次 __HAL_UART_CLEAR_FLAG(huart2, UART_FLAG_IDLE | UART_FLAG_ORE); __HAL_UART_ENABLE_IT(huart2, UART_IT_IDLE); HAL_UART_Receive_DMA(huart2, rx_buf, RX_BUF_LEN); // ⑥ 额外延时等待模块串口初始化 delay_ms(100); } // 3. SDM20M单次测距流程含复位指令 void sdm20m_single_measure(void){ // ① 发送模块复位指令必须掉电后需重新唤醒 HAL_StatusTypeDef ret HAL_UART_Transmit(huart2, sdm20m_reset_cmd, sizeof(sdm20m_reset_cmd), 200); if(ret ! HAL_OK) { // 调试用指令发送失败可加LED提示 return; } delay_ms(50); // 复位指令响应时间 // ② 发送测距指令 ret HAL_UART_Transmit(huart2, sdm20m_measure_cmd, sizeof(sdm20m_measure_cmd), 200); if(ret ! HAL_OK) { return; } // ③ 等待数据接收可加超时判断 delay_ms(100); // 模块测距数据输出时间 } // 4. 空闲中断服务函数核心重启DMA接收 void USART2_IRQHandler(void) { uint32_t temp; if(__HAL_UART_GET_FLAG(huart2, UART_FLAG_IDLE) ! RESET) { __HAL_UART_CLEAR_IDLEFLAG(huart2); // 清除IDLE标志必须 HAL_UART_DMAStop(huart2); // 停止DMA // 计算接收长度 temp __HAL_DMA_GET_COUNTER(hdma_usart2_rx); rx_len RX_BUF_LEN - temp; // 处理有效数据替换为你的业务逻辑 if(rx_len 0) { // 示例解析SDM20M数据、保存结果 // parse_sdm20m_data(rx_buf, rx_len); memset(rx_buf, 0, RX_BUF_LEN); // 清空缓冲区 } // 重启DMA接收核心否则后续无数据 HAL_UART_Receive_DMA(huart2, rx_buf, RX_BUF_LEN); } HAL_UART_IRQHandler(huart2); // 处理其他中断 } // 5. 主循环流程重复测距 void main_loop(void){ while(1){ // ① 开启电源 turnon_laserpower(); // ② 单次测距 sdm20m_single_measure(); // ③ 等待数据接收可加超时 delay_ms(200); // ④ 关闭电源 cutoff_laserpower(); // ⑤ 延时200ms你的业务要求 delay_ms(200); } }第三步快速验证方法定位剩余问题硬件验证测 RT9193 EN 端关断时 0.1V开启时 3V测 Vout 端关断后 1s 内降到 0.5V开启后稳定在 3.3V测 SDM20M TX 引脚上电后有规律的电平信号说明模块在发送。软件验证在 USART2_IRQHandler 中加 LED 闪烁确认每次测距都触发 IDLE 中断打印 rx_len 值确认每次接收长度 0有效数据。总结核心原因硬件RT9193 EN 端电路导致 LDO 关断不彻底ZM4729A 串联导致 Vout 掉电 / 上电异常软件未给 SDM20M 发送复位指令DMA 接收未重启延时不足关键修复硬件整改 EN 端电路4.7k 上拉到 VIN移除 ZM4729A增加 Vout 放电回路软件发送复位指令后再发测距指令中断服务函数中重启 DMA延长上电 / 放电延时核心要点SDM20M 掉电后必须发复位指令才能重新工作IDLE 中断后必须重启 DMA 接收否则仅能接收一次数据RT9193 需彻底关断确保模块电源完全掉电。ZM4729A 是 3.6V 稳压二极管是并联不是串联。Vout 端已经并联 1μF 钽电容 22nf 100nF贴片电容了明白了你现在的硬件是ZM4729A3.6V 稳压管是并联在 VOUT 和 GND 之间不是串联VOUT 端已经有1μF 钽电容 22nF 100nF 贴片电容滤波已经比较充分EN 脚100k 下拉 GND 4.7k 上拉到 STM32 PA0流程一次有效数据 → 关 LDO → 延时 200ms → 开 LDO → 发测距指令 → 等数据 → 循环现象第一次正常LDO 关断再上电后单片机收不到数据 / 只能收到一次。在这个前提下结合RT9193-33GB STM32L431 SDM20M 激光模块的特性以及你 “并联稳压管、电容已经很足” 的硬件条件问题基本可以锁定在电源掉电不彻底 模块上电时序 / 复位不匹配 STM32 串口 / DMA 状态残留这三大块而且和你现在的 EN 电阻分压、LDO 关断方式强相关。下面我按 “最可能 → 次可能” 给你把根因讲清楚同时给你可直接验证、可直接改代码的方案。一、先把最关键的硬件问题讲透你的 EN 分压电路导致 LDO 根本没 “彻底关断”你现在 EN 脚接法EN —— 100kΩ —— GNDEN —— 4.7kΩ —— STM32 PA0这是一个分压网络不是 “开关”。1.1 PA0 输出低电平时EN 电压 ≠ 0VLDO 没有真正关断RT9193-33GB 的 EN 阈值V_EN 0.4VLDO 关断V_EN 1.1VLDO 开启你现在的分压PA0 0V低电平时V_EN 0V × (100k / (4.7k 100k)) 0V理论上是关断。但现实中STM32 GPIO 低电平不是绝对 0V而是 0.1~0.3VRT9193 EN 脚有输入漏电流100k 下拉电阻太大对微弱漏电流非常敏感。结果就是PA0 输出低电平时EN 实际电压 ≈ 0.2~0.4V处于 “临界关断区”RT9193 不会完全关断而是进入部分关断 / 亚阈值工作区VOUT 不会降到 0V而是0.5~1.5V 左右的残压这个电压对激光模块来说不是正常掉电复位内部 MCU、串口、电源管理处于半死状态半上电、半掉电再次上电时内部状态混乱串口不工作 / 波特率漂移 / 不发数据这就是你 “第一次正常第二次就不行” 的硬件根因第一名。1.2 PA0 输出高电平时EN 电压被拉低LDO 开启不稳定PA0 3.3V 时V_EN 3.3V × (100k / (4.7k 100k)) ≈3.15V看起来没问题但分压后 EN 电压永远低于 PA0 电压当 PA0 电平有抖动、电源有跌落时EN 很容易掉到 1.1V 以下LDO 瞬间关断再开启激光模块最怕这种电源抖动 反复上电串口直接锁死。1.3 结论非常重要你现在的 EN 电阻接法不是 “开关”是 “分压衰减”导致 LDO 无法真正关断也无法干净开启。这是你 “断电再上电就不工作” 的头号硬件元凶。二、第二个关键即使 LDO 关断激光模块也没有 “彻底掉电复位”你现在关 LDO → 延时 200ms → 开 LDO问题RT9193 没彻底关断 → VOUT 有残压激光模块内部有电容 ZM4729A 并联放电极慢200ms 根本不够把电压放到 0.5V模块真正复位的电压结果激光模块从来没有经历过一次完整的 “掉电 → 上电复位”内部状态一直是乱的串口自然不工作。SDM20M 这类激光模块必须 VCC 降到 0.3V 以下才算真正复位。你现在的电路 延时做不到。三、第三个关键STM32 串口 / DMA / 中断状态残留你现在的流程关 LDO延时开 LDO重新初始化 UART DMA但你很可能没做干净IDLE 中断标志没清干净DMA 没真正 Abort DeInitORE溢出错误、FE帧错误标志没清RX 脚PA3在断电期间不是高阻输入一直钳位电平结果第一次 DMA 接收正常第二次 UART 外设状态混乱IDLE 中断只进一次之后再也不进表现就是只能收到一次数据这和你描述的现象完全吻合。四、综合结论一句话总结你现在的系统有三个连锁问题叠加在一起导致 “断电再上电就不工作”EN 分压电路错误 → LDO 无法真正关断 → 激光模块永远半上电放电不足 延时太短 → 模块从未真正复位 → 串口锁死STM32 UART / DMA / 中断复位不彻底 → 第二次接收链路直接失效只要 EN 电路不改你软件怎么调都很难稳定。五、给你 “立刻能验证、立刻能改” 的方案硬件 软件5.1 硬件必须改最关键不改很难稳定方案 A最简单、最推荐直接开关式 EN把 EN 脚改成EN 直接接 PA0去掉 4.7k 和 100kPA0 配置推挽输出GPIO_MODE_OUTPUT_PPPA0 高 → LDO 开PA0 低 → LDO 关RT9193 EN 输入阻抗很高直接 GPIO 驱动完全没问题比你现在分压稳定 100 倍。方案 B如果你一定要保留电阻不推荐但兼容你现有板子改成EN ——10k 下拉 GND把 100k 换成 10k下拉更强EN ——1k 电阻 → PA0这样PA0 低 → EN 几乎 0VLDO 彻底关断PA0 高 → EN 接近 3.3VLDO 稳定开启必须做的验证用万用表 10 秒就能测PA0 低测 EN 电压必须 0.2VPA0 高测 EN 电压必须 3.0V关断后测 VOUT必须 0.5V最好 0.3V只要 VOUT 关断后还 0.5V激光模块就永远不会正常复位。5.2 软件必须配套修改直接替换你的函数下面是针对 STM32L431 UARTDMAIDLE 中断 SDM20M的断电 / 上电完整流程你可以直接替换。5.2.1 彻底断电保证模块真掉电c运行void cutoff_laserpower(void) { extern DMA_HandleTypeDef hdma_usart2_rx; // 1. 关掉所有 UART 中断 __HAL_UART_DISABLE_IT(huart2, UART_IT_IDLE | UART_IT_RXNE | UART_IT_ERR); // 2. 彻底停 DMA if (HAL_DMA_GetState(hdma_usart2_rx) ! HAL_DMA_STATE_READY) { HAL_DMA_Abort(hdma_usart2_rx); } HAL_UART_DMAStop(huart2); HAL_DMA_DeInit(hdma_usart2_rx); // 3. 反初始化 UART HAL_UART_DeInit(huart2); // 4. RX 脚 PA3 设为高阻输入避免钳位 GPIO_InitTypeDef gpio_conf {0}; gpio_conf.Pin GPIO_PIN_3; gpio_conf.Mode GPIO_MODE_INPUT; gpio_conf.Pull GPIO_NOPULL; HAL_GPIO_Init(GPIOA, gpio_conf); // 5. 关 LDOEN 低 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // 6. 延时足够长保证 VOUT 0.3V // 你现在 200ms 大概率不够先试 1000ms delay_ms(1000); // 7. 清所有标志 __HAL_UART_CLEAR_FLAG(huart2, UART_FLAG_IDLE | UART_FLAG_ORE | UART_FLAG_NE | UART_FLAG_FE); }5.2.2 重新上电 恢复 UARTc运行void turnon_laserpower(void) { extern DMA_HandleTypeDef hdma_usart2_rx; // 1. 开 LDOEN 高 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // 2. 模块上电稳定时间SDM20M 至少 300ms给 500ms 更稳 delay_ms(500); // 3. 恢复 RX 脚 PA3 为 UART RX GPIO_InitTypeDef gpio_conf {0}; gpio_conf.Pin GPIO_PIN_3; gpio_conf.Mode GPIO_MODE_AF_INPUT; gpio_conf.Pull GPIO_PULLUP; gpio_conf.Speed GPIO_SPEED_FREQ_HIGH; gpio_conf.Alternate GPIO_AF7_USART2; HAL_GPIO_Init(GPIOA, gpio_conf); // 4. 重新初始化 DMA UART MX_DMA_Init(); MX_USART2_UART_Init(); // 5. 清残留错误 __HAL_UART_CLEAR_FLAG(huart2, UART_FLAG_IDLE | UART_FLAG_ORE | UART_FLAG_NE | UART_FLAG_FE); // 6. 开 IDLE 中断 启动 DMA 接收 __HAL_UART_ENABLE_IT(huart2, UART_IT_IDLE); HAL_UART_Receive_DMA(huart2, rx_buf, RX_BUF_SIZE); }5.2.3 IDLE 中断服务函数保证每次都能重启 DMAc运行void USART2_IRQHandler(void) { uint32_t temp; if (__HAL_UART_GET_FLAG(huart2, UART_FLAG_IDLE) ! RESET) { // 清 IDLE 标志必须 __HAL_UART_CLEAR_IDLEFLAG(huart2); // 停 DMA HAL_UART_DMAStop(huart2); // 计算长度 temp __HAL_DMA_GET_COUNTER(hdma_usart2_rx); rx_len RX_BUF_SIZE - temp; // 处理一帧数据 if (rx_len 0) { // 你的解析逻辑 parse_sdm20m(rx_buf, rx_len); memset(rx_buf, 0, RX_BUF_SIZE); } // 重启 DMA关键不重启就只能收一次 HAL_UART_Receive_DMA(huart2, rx_buf, RX_BUF_SIZE); } HAL_UART_IRQHandler(huart2); }5.2.4 主循环流程保证 “复位指令 测距指令”SDM20M 上电后必须先发复位指令再发测距指令不能上来就测距。c运行void laser_measure_cycle(void) { // 1. 上电 turnon_laserpower(); // 2. 先发复位指令 uint8_t reset_cmd[9] {0xA5, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8}; HAL_UART_Transmit(huart2, reset_cmd, 9, 200); delay_ms(50); // 3. 再发测距指令 uint8_t measure_cmd[9] {0xA5, 0x03, 0x20, 0x01, 0x00, 0x00, 0x00, 0x02, 0x6E}; HAL_UART_Transmit(huart2, measure_cmd, 9, 200); // 4. 等数据回来根据模块手册一般 100~200ms delay_ms(200); // 5. 断电 cutoff_laserpower(); // 6. 循环间隔 delay_ms(200); }六、你现在可以立刻做的 “最小改动验证”不用改硬件先试软件如果你暂时不想改板子可以先做这三步80% 概率能明显改善把断电延时从 200ms 改成 1000ms上电后先发复位指令再发测距指令确保 IDLE 中断里每次都重启 DMA如果这样改完第二次、第三次能收到数据那就证明硬件 EN 电路确实有问题关断不彻底模块确实需要更长掉电时间 复位指令七、最终一句话总结你只要记住这句你现在的 EN 分压电路导致 LDO 关不断激光模块永远半上电再加上延时太短、没发复位指令、DMA 没重启所以第一次正常第二次就死。先把 EN 改成直接 GPIO 驱动再把断电延时拉长再发复位指令基本 100% 解决。如果你愿意我可以根据你现在的 PCB / 原理图给你画一版推荐的 EN 电路 电源滤波你直接照着改就行