野火STM32Modbus主机读取寄存器/线圈失败(一)-解决接收中断不触发的问题

接收中断不触发

前情提要

在自己的开发板上移植了野火的modbus主机程序。
野火主机程序移植
野火主机代码理解与使用

问题背景

我使用STM32显示板作为Modbus主机连接电脑,并在电脑上运行Modbus Slave软件。测试中发现,读取保持寄存器和输入寄存器均失败,但写入操作正常。例如,当我的板子作为主机发送读取从机1的40、41地址(其中预先写入了4000和6500)的请求时,Modbus Slave可以正确接收到请求帧:

Rx: 001205-01 03 00 28 00 02 44 03
Tx: 001206-01 03 04 0F A0 19 64 B1 97

这说明主机发出的命令没有问题。然而,在我的代码中,用于存储保持寄存器的数组 usMRegHoldBuf[][] 始终为0,未能更新。进一步排查发现,程序并未进入回调函数 eMBMasterRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode)

后续测试表明,Modbus主机的接收中断从未被触发,因此初步判断问题出在Modbus主机的接收中断部分,可能存在配置或实现上的错误。


现象

在portserial_m.c中添加调试代码,变量tx_int_count递增,但是rx_int_count始终为0,说明没触发接收中断。

/* * Create an interrupt handler for the transmit buffer empty interrupt* (or an equivalent) for your target processor. This function should then* call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that* a new character can be sent. The protocol stack will then call * xMBPortSerialPutByte( ) to send the character.*/
void prvvUARTTxReadyISR(void)
{/* 发送状态机 */extern volatile uint32_t tx_int_count;tx_int_count++;pxMBMasterFrameCBTransmitterEmpty();
}/* * Create an interrupt handler for the receive interrupt for your target* processor. This function should then call pxMBFrameCBByteReceived( ). The* protocol stack will then call xMBPortSerialGetByte( ) to retrieve the* character.*/
void prvvUARTRxISR(void)
{/* 接收状态机 */extern volatile uint32_t rx_int_count;rx_int_count++;pxMBMasterFrameCBByteReceived();
}

解决

将portserial_m.c中的void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)进行修改。

void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{/* If xRXEnable enable serial receive interrupts. If xTxENable enable* transmitter empty interrupts.*/if(xRxEnable){/* 串口2接收中断使能 */__HAL_USART_ENABLE_IT(&huart2,USART_IT_RXNE); #if defined(MODBUS_MASTER_USE_CONTROL_PIN)	/* 485低电平接收 */HAL_GPIO_WritePin(MODBUS_MASTER_GPIO_PORT,MODBUS_MASTER_GPIO_PIN,MODBUS_MASTER_GPIO_PIN_LOW);#endif}else{/* 串口2接收中断关闭 */__HAL_USART_DISABLE_IT(&huart2,USART_IT_RXNE); #if defined(MODBUS_MASTER_USE_CONTROL_PIN)/* 485高电平发送 */HAL_GPIO_WritePin(MODBUS_MASTER_GPIO_PORT,MODBUS_MASTER_GPIO_PIN,MODBUS_MASTER_GPIO_PIN_HIGH);#endif}if(xTxEnable){/* 串口2发送中断使能 */__HAL_USART_ENABLE_IT(&huart2,USART_IT_TXE); #if defined(MODBUS_MASTER_USE_CONTROL_PIN)/* 485高电平发送*/HAL_GPIO_WritePin(MODBUS_MASTER_GPIO_PORT,MODBUS_MASTER_GPIO_PIN,MODBUS_MASTER_GPIO_PIN_HIGH);#endif}else{/* 串口2发送中断关闭 */__HAL_USART_DISABLE_IT(&huart2,USART_IT_TXE); #if defined(MODBUS_MASTER_USE_CONTROL_PIN)	/* 485低电平接收*/HAL_GPIO_WritePin(MODBUS_MASTER_GPIO_PORT,MODBUS_MASTER_GPIO_PIN,MODBUS_MASTER_GPIO_PIN_LOW);#endif}
}

改成

void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{/* If xRXEnable enable serial receive interrupts. If xTxENable enable* transmitter empty interrupts.*/if(xRxEnable){#if defined(MODBUS_MASTER_USE_CONTROL_PIN)	/* 485低电平接收 */HAL_GPIO_WritePin(MODBUS_MASTER_GPIO_PORT,MODBUS_MASTER_GPIO_PIN,MODBUS_MASTER_GPIO_PIN_LOW);/* 添加小延时确保485切换完成 */for(volatile int i = 0; i < 100; i++);#endif/* 串口2接收中断使能 */__HAL_USART_ENABLE_IT(&huart2,USART_IT_RXNE); }else{/* 串口2接收中断关闭 */__HAL_USART_DISABLE_IT(&huart2,USART_IT_RXNE); #if defined(MODBUS_MASTER_USE_CONTROL_PIN)/* 485高电平发送 */HAL_GPIO_WritePin(MODBUS_MASTER_GPIO_PORT,MODBUS_MASTER_GPIO_PIN,MODBUS_MASTER_GPIO_PIN_HIGH);#endif}if(xTxEnable){#if defined(MODBUS_MASTER_USE_CONTROL_PIN)/* 485高电平发送*/HAL_GPIO_WritePin(MODBUS_MASTER_GPIO_PORT,MODBUS_MASTER_GPIO_PIN,MODBUS_MASTER_GPIO_PIN_HIGH);/* 添加小延时确保485切换完成 */for(volatile int i = 0; i < 100; i++);#endif/* 串口2发送中断使能 */__HAL_USART_ENABLE_IT(&huart2,USART_IT_TXE); }else{/* 串口2发送中断关闭 */__HAL_USART_DISABLE_IT(&huart2,USART_IT_TXE); #if defined(MODBUS_MASTER_USE_CONTROL_PIN)	/* 485低电平接收*/HAL_GPIO_WritePin(MODBUS_MASTER_GPIO_PORT,MODBUS_MASTER_GPIO_PIN,MODBUS_MASTER_GPIO_PIN_LOW);#endif}
}

就可以触发了,rx_int_count递增。

原因分析

您遇到的问题非常典型,涉及到RS-485半双工通信中一个关键且容易忽视的细节:方向控制引脚(DE/RE)切换与UART中断使能的时序问题

问题根本原因分析

(暂不清楚,以下为ai的解释)
中断使能(__HAL_USART_ENABLE_IT)的操作在GPIO方向切换(HAL_GPIO_WritePin)之前。这会引发一个竞态条件(Race Condition):

  1. 使能接收中断的时刻:当调用 __HAL_USART_ENABLE_IT(&huart2, USART_IT_RXNE) 后,USART2的接收中断立即被打开。此时,USART硬件已经开始监听总线上的数据。
  2. 切换485方向的时刻:紧接着,代码才去设置GPIO引脚为接收模式(低电平)。从CPU执行完第一条指令到GPIO电平实际稳定、收发器切换到接收状态,存在一个极短但不可忽略的延迟。

在这个短暂的延迟窗口内,总线状态是不确定的:

  • 如果总线上恰好有数据(例如,上一帧数据的残留、噪声、或者其他设备的发送),USART的接收寄存器(RXNE)会立即被置位。
  • 由于接收中断已经使能,CPU会立刻响应并进入接收中断服务程序(ISR)。
  • 然而,此时485收发器可能还未完全切换到接收模式,导致它无法正确地将总线差分信号传递给USART,或者传递的是错误的电平。
  • 最终结果是,ISR读取到的可能是无效数据帧错误(FE)、或噪音。更常见的是,这个过早触发的中断会清空RXNE标志,但并没有读到有效数据。而当Modbus协议栈真正开始等待响应时,由于标志位已被清除,无法再次触发中断,导致接收超时。

修改后的代码为什么能工作?

修改后的代码调整了时序

  1. 先切换485方向:首先通过GPIO将收发器稳稳地设置为目标模式(接收或发送)。
  2. 添加短暂延时:使用 for 循环提供一个短暂的阻塞延时。这个延时确保了GPIO电平有足够的时间稳定下来,并且485收发器内部的电路已经完成了切换(通常需要几百纳秒到几微秒)。虽然用循环实现延时不是最优雅的方式(更好的做法是使用硬件定时器或精确延时函数),但它简单有效,解决了硬件切换的时序问题。
  3. 最后使能中断:在确保硬件已经完全准备好之后,再打开USART中断。这样,当中断使能时,总线状态和收发器状态都是稳定和正确的,只有在使能之后到来的新数据才会触发中断,从而避免了“旧”数据或噪音的误触发。

简单比喻:

  • 修改前:就像先打开麦克风的开关(中断使能),然后再告诉别人“现在你可以对我说话了”(485切接收)。在你告诉他之前,任何环境噪音(总线数据)都会被麦克风录进去。
  • 修改后:先告诉别人“现在你可以对我说话了”(485切接收),确保自己准备好了,然后再打开麦克风开关(中断使能)。这样录到的才是对方真正要对你说的话。

总结与建议

总结: 接收中断不触发的根本原因不是中断没打开,而是中断被过早地触发并在错误的时刻被处理掉了。修改后的代码通过调整GPIO操作和中断使能的顺序,并加入延时确保硬件稳定,解决了这个问题。

改进建议:

  1. 替换循环延时for循环延时受编译器优化和CPU频率影响,不精确。建议使用HAL_Delay(1)(延时1ms,对于485切换绰绰有余)或者查询硬件定时器来实现更可靠的微秒级延时。
  2. 检查中断优先级:确保USART中断的优先级设置合理,不会被其他高优先级中断长时间阻塞。
  3. 检查中断服务程序(ISR):确保在USART2的IRQHandler中正确处理了USART_IT_RXNE事件,并且清除了相应的标志位。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/920956.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/920956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5种常见的网络安全漏洞及防护建议

五种常见的网络安全漏洞及防护建议在数字化时代&#xff0c;网络安全已成为个人和企业面临的重要挑战。网络攻击手段不断升级&#xff0c;黑客利用各种漏洞入侵系统、窃取数据或破坏服务。了解常见的网络安全漏洞并采取相应的防护措施&#xff0c;是保障信息安全的关键。本文将…

mysql5.6+分页时使用 limit+order by 会出现数据重复问题

mysql5.6分页时使用 limitorder by 会出现数据重复问题 问题描述 在MySQL中我们通常会采用limit来进行翻页查询&#xff0c;比如limit(0,10)表示列出第一页的10条数据&#xff0c;limit(10,10)表示列出第二页。但是&#xff0c;当limit遇到order by的时候&#xff0c;可能会出现…

【XR技术概念科普】VST(视频透视)vs OST(光学透视):解码MR头显的两种核心技术路径

混合现实(MR)头显作为连接虚拟与现实世界的桥梁&#xff0c;其核心技术路径主要分为视频透视(VST)和光学透视(OST)两种。本文将深入探讨这两种技术的原理、优缺点、代表性产品、应用场景及未来发展趋势&#xff0c;为读者全面解析MR头显的技术选择。一、VST技术详解1.1 VST技术…

VR智慧楼宇技术:打造智能办公空间的卓越方案​

在华锐视点打造的极具创新性的VR智慧楼宇的智能办公空间里&#xff0c;员工的工作模式迎来了前所未有的、彻头彻尾的颠覆性变革。凭借华锐视点自主研发的先进VR设备&#xff0c;哪怕员工远在千里之外的不同城市&#xff0c;甚至身处不同国家&#xff0c;也能如同真切地置身于同…

C++ 面试考点 类成员函数的调用时机

构造函数和析构函数的调用时机 1. 对于全局定义的对象&#xff0c;每当程序开始运行&#xff0c;在主函数 main 接受程序控制权之前&#xff0c;就调 用构造函数创建全局对象&#xff0c;整个程序结束时&#xff0c;自动调用全局对象的析构函数。 2. 对于局部定义的对象&#…

59.螺旋矩阵II

59.螺旋矩阵II 螺旋矩阵没有什么算法&#xff0c;就是一道单纯模拟转圈的一道题目&#xff0c;因为转圈的过程需要处理的边界条件很多&#xff0c;所以有难度 那只能从第二个节点开始处理&#xff1b;从第二个节点开始处理&#xff0c;把最后一个节点也处理了&#xff08;第二…

MS SQL(Microsoft SQL Server)面试常考的知识点

MS SQL是Microsoft SQL Server的简称&#xff0c;是由微软公司开发的一款关系型数据库管理系统&#xff08;RDBMS,Relational DataBase Management System&#xff09;。它支持在Windows和Linux上运行&#xff0c;广泛应用于企业级数据库市场&#xff0c;适用于大型企业网站和应…

百胜软件获邀出席第七届中国智慧零售大会,智能中台助力品牌零售数智变革

8月28日&#xff0c;由深圳市智慧零售协会主办的第七届中国智慧零售大会在深圳福田希尔顿酒店成功召开。本届大会以“聚势AI共启智慧零售新生态”为主题&#xff0c;汇聚了来自北京大学、腾讯云、百果园、舍得酒业、美宜佳等众多知名企业与机构的专家代表&#xff0c;共同探讨A…

QEMU使用Qemu-Guest-Agent传输文件、执行指令等

简介 之前介绍过qemu传输文件,使用的挂载 / samba方式 :Qemu和宿主机不使用外网进行文件传输。 这是一种方式,这里还有另一种方式:使用Qemu-Guest-Agent,后面简称qga。 官网介绍:https://www.qemu.org/docs/master/interop/qemu-ga.html 安装 这里有一篇参考文章,会…

HTML 核心标签全解析:从文本排版到媒体嵌入

在网页开发中&#xff0c;HTML&#xff08;超文本标记语言&#xff09;是构建页面结构的基石。掌握各类核心标签的用法&#xff0c;是实现页面内容有序呈现、提升用户体验的关键。本文将系统讲解 HTML 中最常用的几类标签 —— 段落标签、文本格式标签、列表标签、表格&#xf…

[后端快速搭建]基于 Django+DeepSeek API 快速搭建智能问答后端

在 AI 应用开发中&#xff0c;将大模型 API 与 Web 框架结合是常见需求。本文将详细记录如何使用 Django 搭建后端服务&#xff0c;并集成 DeepSeek API 实现智能问答功能&#xff0c;包含环境配置、路由设计、API 调用及异常处理的完整流程&#xff0c;适合需要快速搭建 AI 问…

R 语言 + 卒中 Meta 分析

R 语言 卒中 Meta 分析&#xff1a;4 类核心场景完整代码&#xff08;含药物对比 / 剂量风险&#xff09; 卒中&#xff08;缺血性 / 出血性&#xff09;的临床决策高度依赖循证证据&#xff0c;而 Meta 分析是整合多中心研究结果的核心工具。本文以卒中临床研究为核心&#x…

Goframe 框架下HTTP反向代理并支持MCP所需的SSE协议的实现

一、需求背景 Go 语言开发 MCP 服务&#xff0c;并在 Goframe 框架下实现 Http 反向代理&#xff0c;代理该 MCP 服务。 二、效果演示 三、Goframe框架简介 GoFrame 是一款模块化、低耦合设计、高性能的Go 语言开发框架。包含了常用的基础组件和开发工具&#xff0c;既可以作…

Git将多笔patch合并成一笔

一、方法1、在你的代码中把这多笔patch都打上2、git reset到origin那一笔(默认模式&#xff0c;不带soft或者hard)3、再add和commit&#xff0c;push二、种模式对比模式命令示例影响范围适用场景--softgit reset --soft HEAD~1仅移动 HEAD&#xff0c;保留修改在暂存区修改提交…

【SpringBoot】Dubbo、Zookeeper

文章目录前提知识概要分布式系统单体架构垂直应用架构分布式架构流式架构RPCDubbo概念Dubbo环境搭建Zookeeper测试 ZookeeperWindow环境下使用Dubbo-admin版本匹配不对服务注册实战内容总结导入相关依赖选择 Zookeeper 版本配置并启用 Zookeeper创建服务接口和实现(DubboServic…

【不说废话】pytorch张量相对于numpy数组的优势

核心关系 我们首先需要了解&#xff1a;PyTorch 张量在设计上深受 NumPy 数组的影响&#xff0c;它们共享许多相似的 API 和概念。实际上&#xff0c;PyTorch 张量可以看作是支持 GPU 加速和自动求导功能的 NumPy 数组。PyTorch 张量的主要优势 1. GPU 加速支持&#xff08;最重…

拼团小程序源码分享拼团余额提现小程序定制教程开发源码二开

功能详细说明&#xff08;一&#xff09;首页功能进入首页&#xff0c;可看到以下核心功能&#xff1a;1、优惠券&#xff0c;钱包&#xff0c;签到&#xff0c;拼团&#xff0c;分销等各种功能入口2、推荐的商品和活动3、下方功能栏的各种功能&#xff08;二&#xff09;客服功…

pikachu之XSS

XSS&#xff08;跨站脚本&#xff09;概述Cross-Site Scripting 简称为“CSS”&#xff0c;为避免与前端叠成样式表的缩写"CSS"冲突&#xff0c;故又称XSS。一般XSS可以分为如下几种常见类型&#xff1a;1.反射性XSS;2.存储型XSS;3.DOM型XSS;XSS漏洞一直被评估为web漏…

【Element Plus `el-select` 下拉菜单响应式定位问题深度解析】

Element Plus el-select 下拉菜单响应式定位问题深度解析 本文档旨在深入剖析一个在响应式布局中常见的 UI 问题&#xff1a;如何确保一个靠近屏幕边缘的 el-select 组件的下拉菜单&#xff0c;在任何屏幕尺寸下都能以预期的、优雅的方式显示。 1. 需求背景 在一个大屏数据展示…

Qt 项目文件(.pro)中添加 UI 文件相关命令

在 Qt 的 .pro 项目文件中&#xff0c;处理 UI 文件&#xff08;.ui 文件&#xff09;通常需要以下配置&#xff1a; 基本 UI 文件配置 自动包含 UI 文件&#xff1a; qmake FORMS yourfile.ui \anotherfile.ui Qt 构建系统会自动使用 uic&#xff08;用户界面编译器&#xff…