野火STM32Modbus主机读取寄存器/线圈失败(三)-尝试将存贮事件的地方改成数组(非必要解决方案)(附源码)

背景

尽管crc校验正确了,也成功发送了EV_MASTER_EXECUTE事件,但是eMBMasterPoll( void )中总是接收的事件是EV_MASTER_FRAME_RECEIVED或者EV_MASTER_FRAME_SENT,一次都没有执行EV_MASTER_EXECUTE。EV_MASTER_EXECUTE事件被别的事件给覆盖了,于是尝试把发送的事件存在数组里,避免被覆盖。

调试思路

把发送的事件发在一个先进先出的数组里,这样事件就不会被覆盖

具体操作

在portevent_m.c的开头添加:

volatile uint8_t debug_queue_count = 0;        /* 当前队列中的事件数量 */
volatile uint8_t debug_queue_head = 0;         /* 队列头部位置 */
volatile uint8_t debug_queue_tail = 0;         /* 队列尾部位置 */
volatile eMBMasterEventType debug_last_posted = 0;  /* 最后发布的事件 */
volatile eMBMasterEventType debug_last_got = 0;     /* 最后获取的事件 */
volatile uint32_t debug_post_total = 0;       /* 总发布事件数 */
volatile uint32_t debug_get_total = 0;        /* 总获取事件数 */
volatile uint32_t debug_queue_full_count = 0; /* 队列满的次数 */
volatile uint32_t debug_queue_empty_count = 0;/* 队列空的次数 *//* 直接查看事件队列内容 - 在Watch窗口中展开这个数组 */
volatile eMBMasterEventType debug_event_queue[EVENT_QUEUE_SIZE];  /* 事件队列的副本 */
Yes
调用
xMBMasterPortEventPost
事件的数量
queueCount小于范围
eventQueue[queueTail] = eEvent;
queueTail = (queueTail + 1) % EVENT_QUEUE_SIZE;
queueCount++;
Yes
调用
xMBMasterPortEventGet
检查是否有
待处理的事件
*eEvent = eventQueue[queueHead];
queueHead = (queueHead + 1) % EVENT_QUEUE_SIZE;
queueCount--;
queueTail = (queueTail + 1) % EVENT_QUEUE_SIZE;
queueCount++;

修改portevent.c文件


/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbport.h"
#include "port.h"#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
extern BOOL xMBMasterRTUTimerExpired(void);
/* ----------------------- Defines ------------------------------------------*/
/* ----------------------- Variables ----------------------------------------*/
static eMBMasterEventType eMasterQueuedEvent;//排队中的事件类型
static BOOL    xMasterEventInQueue;//是否有待处理的事件在排队
static eMBMasterEventType eCurrentEvent;//当前要处理的事件
/* Debug counters: record EV_MASTER_EXECUTE occurrences */
volatile uint32_t ev_exec_post_count = 0;  /* times EV_MASTER_EXECUTE was posted */
volatile uint32_t ev_receive_post_count = 0;  /* times EV_MASTER_FRAME_RECEIVED was posted */
volatile uint32_t ev_sent_post_count = 0;  /* times EV_MASTER_FRAME_SENT was posted */volatile uint32_t ev_exec_get_count  = 0;  /* times EV_MASTER_EXECUTE was fetched */
volatile uint32_t get_event_count  = 0;  /* times eEvent was fetched */
volatile uint32_t post_event_count  = 0;  /* times eEvent was posted */
volatile uint32_t get_event  = 0;  /* times eEvent was fetched */volatile eMBMasterEventType xMasterEventInQueue_get_value=0;/* 简单事件队列 - 避免事件覆盖 */
#define EVENT_QUEUE_SIZE 16
//static eMBMasterEventType eventQueue[EVENT_QUEUE_SIZE];eMBMasterEventType eventQueue[EVENT_QUEUE_SIZE];
static uint8_t queueHead = 0;
static uint8_t queueTail = 0;
static uint8_t queueCount = 0;/* 完成事件状态 - 独立于队列 */
static volatile eMBMasterReqErrCode g_completion_status = MB_MRE_NO_ERR;
static volatile BOOL g_completion_ready = FALSE;/* 队列调试变量 - 在Watch窗口中观察 */
volatile uint8_t debug_queue_count = 0;        /* 当前队列中的事件数量 */
volatile uint8_t debug_queue_head = 0;         /* 队列头部位置 */
volatile uint8_t debug_queue_tail = 0;         /* 队列尾部位置 */
volatile eMBMasterEventType debug_last_posted = 0;  /* 最后发布的事件 */
volatile eMBMasterEventType debug_last_got = 0;     /* 最后获取的事件 */
volatile uint32_t debug_post_total = 0;       /* 总发布事件数 */
volatile uint32_t debug_get_total = 0;        /* 总获取事件数 */
volatile uint32_t debug_queue_full_count = 0; /* 队列满的次数 */
volatile uint32_t debug_queue_empty_count = 0;/* 队列空的次数 *//* 直接查看事件队列内容 - 在Watch窗口中展开这个数组 */
volatile eMBMasterEventType debug_event_queue[EVENT_QUEUE_SIZE];  /* 事件队列的副本 */
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBMasterPortEventInit( void )
{/* 初始化队列 */queueHead = 0;queueTail = 0;queueCount = 0;xMasterEventInQueue = FALSE;/* 初始化调试变量 */debug_queue_count = 0;debug_queue_head = 0;debug_queue_tail = 0;debug_last_posted = 0;debug_last_got = 0;debug_post_total = 0;debug_get_total = 0;debug_queue_full_count = 0;debug_queue_empty_count = 0;/* 初始化调试队列 */for (int i = 0; i < EVENT_QUEUE_SIZE; i++) {debug_event_queue[i] = 0;}return TRUE;
}BOOL
xMBMasterPortEventPost( eMBMasterEventType eEvent )
{post_event_count++;   /* 将事件添加到队列 */if (queueCount < EVENT_QUEUE_SIZE) {eventQueue[queueTail] = eEvent;/* 同步更新调试队列 */debug_event_queue[queueTail] = eEvent;queueTail = (queueTail + 1) % EVENT_QUEUE_SIZE;queueCount++;xMasterEventInQueue = TRUE;/* 更新调试变量 */debug_queue_count = queueCount;//数量debug_queue_head = queueHead;//头部下标debug_queue_tail = queueTail;//尾部下标debug_last_posted = eEvent;//新发送的事件debug_post_total++;//总共发出的事件/* 测试:记录EV_MASTER_EXECUTE事件发生*/if (eEvent == EV_MASTER_EXECUTE) {ev_exec_post_count++;}if (eEvent == EV_MASTER_FRAME_RECEIVED) {ev_receive_post_count++;}if (eEvent == EV_MASTER_FRAME_SENT) {ev_sent_post_count++;}/* 测试:记录发布的事件值 */extern volatile eMBMasterEventType posted_event_value;posted_event_value = eEvent;return TRUE;}/* 队列满了,丢弃事件(仅在满时计数) */debug_queue_full_count++;return FALSE;
}BOOL
xMBMasterPortEventGet( eMBMasterEventType * eEvent )
{get_event_count++;/* 先处理定时器事件,驱动状态机 */xMBMasterRTUTimerExpired();//定时器服务函数/* 检查是否有待处理的事件 */if (queueCount > 0) {/* 从队列头部取出事件 *//* 记录当前队头,便于清槽位 */uint8_t headBefore = queueHead;*eEvent = eventQueue[queueHead];queueHead = (queueHead + 1) % EVENT_QUEUE_SIZE;queueCount--;/* 更新调试变量 */debug_queue_count = queueCount;debug_queue_head = queueHead;debug_last_got = *eEvent;debug_get_total++;/* 同步更新调试队列 - 清除已取出的事件 */debug_event_queue[headBefore] = 0;  /* 清除已处理的事件 *//* 测试:记录取出的事件值 */xMasterEventInQueue_get_value = *eEvent;/* 如果队列为空,清除标志 */if (queueCount == 0) {xMasterEventInQueue = FALSE;}/* 测试:记录EV_MASTER_EXECUTE事件被取出 */if (*eEvent == EV_MASTER_EXECUTE) {ev_exec_get_count++;}return TRUE;}/* 没有事件 */debug_queue_empty_count++;xMasterEventInQueue = FALSE;return FALSE;
}
/*** This function is initialize the OS resource for modbus master.* Note:The resource is define by OS.If you not use OS this function can be empty.**/
void vMBMasterOsResInit( void )
{return ;
}/*** This function is take Mobus Master running resource.* Note:The resource is define by Operating System.If you not use OS this function can be just return TRUE.** @param lTimeOut the waiting time.** @return resource taked result*/
BOOL xMBMasterRunResTake( LONG lTimeOut )
{/*If waiting time is -1 .It will wait forever */return TRUE ;
}/*** This function is release Mobus Master running resource.* Note:The resource is define by Operating System.If you not use OS this function can be empty.**/
void vMBMasterRunResRelease( void )
{/* release resource */return;
}/*** This is modbus master respond timeout error process callback function.* @note There functions will block modbus master poll while execute OS waiting.* So,for real-time of system.Do not execute too much waiting process.** @param ucDestAddress destination salve address* @param pucPDUData PDU buffer data* @param ucPDULength PDU buffer length**/
void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData,USHORT ucPDULength) {/*** @note This code is use OS's event mechanism for modbus master protocol stack.* If you don't use OS, you can change it.*///  xMasterEventInQueue = TRUE;//eMasterQueuedEvent = EV_MASTER_ERROR_RESPOND_TIMEOUT;xMBMasterPortEventPost(EV_MASTER_ERROR_RESPOND_TIMEOUT);return ;/* You can add your code under here. */}/*** This is modbus master receive data error process callback function.* @note There functions will block modbus master poll while execute OS waiting.* So,for real-time of system.Do not execute too much waiting process.** @param ucDestAddress destination salve address* @param pucPDUData PDU buffer data* @param ucPDULength PDU buffer length**/
void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData,USHORT ucPDULength) {/*** @note This code is use OS's event mechanism for modbus master protocol stack.* If you don't use OS, you can change it.*///xMasterEventInQueue = TRUE;//eMasterQueuedEvent = EV_MASTER_ERROR_RECEIVE_DATA;xMBMasterPortEventPost(EV_MASTER_ERROR_RECEIVE_DATA);return;/* You can add your code under here. */}/*** This is modbus master execute function error process callback function.* @note There functions will block modbus master poll while execute OS waiting.* So,for real-time of system.Do not execute too much waiting process.** @param ucDestAddress destination salve address* @param pucPDUData PDU buffer data* @param ucPDULength PDU buffer length**/
void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUData,USHORT ucPDULength) {/*** @note This code is use OS's event mechanism for modbus master protocol stack.* If you don't use OS, you can change it.*///  xMasterEventInQueue = TRUE;// eMasterQueuedEvent = EV_MASTER_ERROR_EXECUTE_FUNCTION;xMBMasterPortEventPost(EV_MASTER_ERROR_EXECUTE_FUNCTION);return;/* You can add your code under here. */}/*** This is modbus master request process success callback function.* @note There functions will block modbus master poll while execute OS waiting.* So,for real-time of system.Do not execute too much waiting process.**/
void vMBMasterCBRequestScuuess( void ) {/*** @note This code is use OS's event mechanism for modbus master protocol stack.* If you don't use OS, you can change it.*/// xMasterEventInQueue = TRUE;// eMasterQueuedEvent = EV_MASTER_PROCESS_SUCESS;xMBMasterPortEventPost(EV_MASTER_PROCESS_SUCESS);return;/* You can add your code under here. */}/*** This function is wait for modbus master request finish and return result.* Waiting result include request process success, request respond timeout,* receive data error and execute function error.You can use the above callback function.* @note If you are use OS, you can use OS's event mechanism. Otherwise you have to run* much user custom delay for waiting.** @return request error code*/
eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) 
{eMBMasterReqErrCode    eErrStatus = MB_MRE_NO_ERR;/* 等待直到有事件 */while (queueCount == 0) {/* 等待事件 */HAL_Delay(1);  /* 小延时避免死循环 */}/* 检查队列头部的事件 */eMBMasterEventType eEvent = eventQueue[queueHead];switch (eEvent){case EV_MASTER_PROCESS_SUCESS:/* 从队列中取出成功事件 */
//				debug_event_queue[queueHead] = 0;  /* 清除已处理的事件 */
//        queueHead = (queueHead + 1) % EVENT_QUEUE_SIZE;
//        queueCount--;if (queueCount == 0) {xMasterEventInQueue = FALSE;}break;case EV_MASTER_ERROR_RESPOND_TIMEOUT:  
//					debug_event_queue[queueHead] = 0;  /* 清除已处理的事件 */
//        /* 从队列中取出超时事件 */
//        queueHead = (queueHead + 1) % EVENT_QUEUE_SIZE;
//        queueCount--;if (queueCount == 0) {xMasterEventInQueue = FALSE;}eErrStatus = MB_MRE_TIMEDOUT;break;case EV_MASTER_ERROR_RECEIVE_DATA: 
//		debug_event_queue[queueHead] = 0;  /* 清除已处理的事件 */			
//        /* 从队列中取出接收错误事件 */
//        queueHead = (queueHead + 1) % EVENT_QUEUE_SIZE;
//        queueCount--;if (queueCount == 0) {xMasterEventInQueue = FALSE;}eErrStatus = MB_MRE_REV_DATA;break;case EV_MASTER_ERROR_EXECUTE_FUNCTION:
//					debug_event_queue[queueHead] = 0;  /* 清除已处理的事件 */
//        /* 从队列中取出执行错误事件 */
//        queueHead = (queueHead + 1) % EVENT_QUEUE_SIZE;
//        queueCount--;if (queueCount == 0) {xMasterEventInQueue = FALSE;}eErrStatus = MB_MRE_EXE_FUN;break;default:
//					debug_event_queue[queueHead] = 0;  /* 清除已处理的事件 */
//        /* 其他事件,从队列中取出但不处理 */
//        queueHead = (queueHead + 1) % EVENT_QUEUE_SIZE;
//        queueCount--;if (queueCount == 0) {xMasterEventInQueue = FALSE;}break;}/* 更新调试变量 */debug_queue_count = queueCount;debug_queue_head = queueHead;debug_queue_tail = queueTail;return eErrStatus;
}#endif

调试

可以通过watch窗口查看进入的数据

结果

事件不被覆盖掉,能顺利执行事件,进入回调函数,usMRegHoldBuf中能写入接收到的数据

附件

代码下载:

2.only_modbus_master - success_带事件缓存数组.zip

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

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

相关文章

微信小程序校园助手程序(源码+文档)

源码题目&#xff1a;微信小程序校园助手程序&#xff08;源码文档&#xff09;☑️ 文末联系获取&#xff08;含源码、技术文档&#xff09;博主简介&#xff1a;10年高级软件工程师、JAVA技术指导员、Python讲师、文章撰写修改专家、Springboot高级&#xff0c;欢迎高校老师、…

59-python中的类和对象、构造方法

1. 认识一下对象 世间万物皆是"对象" student_1{ "姓名":"小朴", "爱好":"唱、跳、主持" ......... }白纸填写太落伍了 设计表格填写先进一些些 终极目标是程序使用对象去组织数据程序中设计表格&#xff0c;我们称为 设计类…

向成电子惊艳亮相2025物联网展,携工控主板等系列产品引领智造新风向

2025年8月27-29日&#xff0c;IOTE 2025 第二十四届国际物联网展深圳站在深圳国际会展中心&#xff08;宝安&#xff09;盛大启幕&#xff01;作为全球规模领先的物联网盛会之一&#xff0c;本届展会以“生态智能&#xff0c;物联全球”为核心&#xff0c;汇聚超1000家全球头部…

阵列信号处理之均匀面阵波束合成方向图的绘制与特点解读

阵列信号处理之均匀面阵波束合成方向图的绘制与特点解读 文章目录前言一、方向图函数二、方向图绘制三、副瓣电平四、阵元个数对主瓣宽度的影响五、阵元间距对主瓣宽度的影响六、MATLAB源代码总结前言 \;\;\;\;\;均匀面阵&#xff08;Uniform Planar Array&#xff0c;UPA&…

算法在前端框架中的集成

引言 算法是前端开发中提升性能和用户体验的重要工具。随着 Web 应用复杂性的增加&#xff0c;现代前端框架如 React、Vue 和 Angular 提供了强大的工具集&#xff0c;使得将算法与框架特性&#xff08;如状态管理、虚拟 DOM 和组件化&#xff09;无缝集成成为可能。从排序算法…

网络爬虫是自动从互联网上采集数据的程序

网络爬虫是自动从互联网上采集数据的程序网络爬虫是自动从互联网上采集数据的程序&#xff0c;Python凭借其丰富的库生态系统和简洁语法&#xff0c;成为了爬虫开发的首选语言。本文将全面介绍如何使用Python构建高效、合规的网络爬虫。一、爬虫基础与工作原理 网络爬虫本质上是…

Qt Model/View/Delegate 架构详解

Qt Model/View/Delegate 架构详解 Qt的Model/View/Delegate架构是Qt框架中一个重要的设计模式&#xff0c;它实现了数据存储、数据显示和数据编辑的分离。这种架构不仅提高了代码的可维护性和可重用性&#xff0c;还提供了极大的灵活性。 1. 架构概述 Model/View/Delegate架构将…

光谱相机在手机行业的应用

在手机行业&#xff0c;光谱相机技术通过提升拍照色彩表现和扩展健康监测等功能&#xff0c;正推动摄像头产业链升级&#xff0c;并有望在AR/VR、生物医疗等领域实现更广泛应用。以下为具体应用场景及技术突破的详细说明&#xff1a;‌一、光谱相机在手机行业的应用场景‌‌拍照…

FASTMCP中的Resources和Templates

Resources 给 MCP 客户端/LLM 读取的数据端点&#xff08;只读、按 URI 索引、像“虚拟文件系统”或“HTTP GET”&#xff09;&#xff1b; Templates 可带参数的资源路由&#xff08;URI 里占位符 → 运行函数动态生成内容&#xff09;。 快速要点 • 用途&#xff1a;把文件…

OpenBMC之编译加速篇

加快 OpenBMC 的编译速度是一个非常重要的话题,因为完整的构建通常非常耗时(在高性能机器上也需要数十分钟,普通电脑上可能长达数小时)。以下是从不同层面优化编译速度的详细策略,您可以根据自身情况组合使用。 一、核心方法:利用 BitBake 的缓存和共享机制(效果最显著…

Kafka面试精讲 Day 8:日志清理与数据保留策略

【Kafka面试精讲 Day 8】日志清理与数据保留策略 在Kafka的高吞吐、持久化消息系统中&#xff0c;日志清理与数据保留策略是决定系统资源利用效率、数据可用性与合规性的关键机制。作为“Kafka面试精讲”系列的第8天&#xff0c;本文聚焦于日志清理机制&#xff08;Log Cleani…

基于Hadoop的网约车公司数据分析系统设计(代码+数据库+LW)

摘 要 本系统基于Hadoop平台&#xff0c;旨在为网约车公司提供一个高效的数据分析解决方案。随着网约车行业的快速发展&#xff0c;平台上产生的数据量日益增加&#xff0c;传统的数据处理方式已无法满足需求。因此&#xff0c;设计了一种基于Hadoop的大规模数据处理和分析方…

Python反向迭代完全指南:从基础到高性能系统设计

引言&#xff1a;反向迭代的核心价值在数据处理和算法实现中&#xff0c;反向迭代是解决复杂问题的关键技术。根据2024年Python开发者调查报告&#xff1a;85%的链表操作需要反向迭代78%的时间序列分析依赖反向处理92%的树结构遍历需要后序/逆序访问65%的加密算法使用反向计算P…

ClickHouse使用Docker部署

OLTP和OLAP介绍基本业务量到达分库分表量级&#xff0c;则离不开数据大屏、推荐系统、画像系统等搭建&#xff0c;需要搭建以上系统&#xff0c;则离不开海量数据进行存储-分析-统计。 而海量数据下 TB、PB级别数据存储&#xff0c;靠Mysql进行存储-分析-统计无疑是灾难。所以就…

Python 算数运算练习题

计算数字特征值题目描述 编写一个程序&#xff0c;接收用户输入的两个整数 a 和 b&#xff08;a > b > 0&#xff09;&#xff0c;计算并输出以下结果&#xff1a;a 与 b 的和的平方a 除以 b 的商和余数a 与 b 的平均数&#xff08;保留 2 位小数&#xff09;示例请输入整…

【物种分布模型】R语言物种气候生态位动态量化与分布特征模拟——气候生态位动态检验、质心转移可视化、适生区预测等

R语言是一种广泛用于统计分析和图形表示的编程语言&#xff0c;强大之处在于可以进行多元数据统计分析&#xff0c;以及丰富的生态环境数据分析的方法&#xff0c;在生态学领域得到广泛应用。本次教程将通过R语言多个程序包与GIS融合应用&#xff0c;提升物种气候生态位动态量化…

【算法速成课2 | 题单】背包问题

专栏指路&#xff1a;《算法速成课》 前导&#xff1a; 动态规划问题中最入门、也最多变的&#xff0c;当属背包问题。 简单来说&#xff0c;就是在有限的空间&#xff0c;&#xff08;花费最小的代价&#xff09;达成最大的收益。 本文会讲一些常见的背包问题&#xff08;可…

计算机视觉与深度学习 | 深度学习图像匹配算法在不同纹理复杂度场景下的鲁棒性和计算效率评估方法

如何评估深度学习图像匹配算法在不同纹理复杂度场景下的鲁棒性和计算效率? 文章目录 如何评估深度学习图像匹配算法在不同纹理复杂度场景下的鲁棒性和计算效率? 一、评估框架概述 1.1 核心评估维度 1.2 评估流程 二、纹理复杂度场景分类方法 2.1 纹理特征量化指标 2.2 场景分…

AI 提示词工程与上下文工程:从入门到深入的系统实践指南

前言近年来&#xff0c;随着大语言模型&#xff08;LLM&#xff0c;Large Language Model&#xff09;的快速发展&#xff0c;提示词工程&#xff08;Prompt Engineering&#xff09;与上下文工程&#xff08;Context Engineering&#xff09;逐渐成为 AI 应用开发中至关重要的…

救火!Linux服务器慢如蜗牛:一套从根源到应用的性能问题诊断全攻略

前言&#xff1a;从“玄学”到“科学” “服务又卡了&#xff01;” 这是我们每个Linux运维/SRE工程师最不想听到&#xff0c;却又最常听到的一句话。随之而来的&#xff0c;往往是开发、产品、甚至老板的连环追问。此时&#xff0c;一个经验不足的工程师可能会立刻登录服务器&…