当前位置: 首页 > news >正文

野火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.dtcms.com/a/366812.html

相关文章:

  • 腾讯云国际代理:如何在腾讯云GPU服务器上部署私有化大模型?附GPU简介
  • SQLmap 完整使用指南:环境搭建 + 命令详解 + 实操案例
  • 打开 solidworks当前文件 所在的文件夹 python pywin32
  • Effective Python 第10条 - 用赋值表达式减少重复代码
  • 上位机知识篇---conda run
  • KingbaseES一体化架构与多层防护体系如何保障企业级数据库的持续稳定与弹性扩展
  • 关于在自然语言处理深层语义分析中引入公理化体系的可行性、挑战与前沿展望
  • 谁才是企业级开源平台的优选?OpenCSG与Dify、Coze、Langflow、Ollama 的差异化之路
  • 深度学习——ResNet 卷积神经网络
  • 高并发商城 商品为了防止超卖,都做了哪些努力?
  • 2025国赛C题保姆级教程思路分析 NIPT 的时点选择与胎儿的异常判定
  • Spring Cloud Alibaba快速入门01
  • C语言结构体:轻松管理球员数据
  • SpringMVC的异常处理和拦截器
  • 【C语言】深入理解指针(4)
  • nextcyber——常见应用攻击
  • 一个老工程师的“新生”:良策金宝AI,让我重新爱上设计
  • [光学原理与应用-389]:设计 - 深紫外皮秒脉冲激光器 - 元件 - 1064nm种子光准直透镜
  • 2025年经管领域专业资格认证发展路径分析
  • 数据结构 之 【模拟实现哈希表】
  • Python 值传递 (Pass by Value) 和引用传递 (Pass by Reference)
  • 电池预测 | 第36讲 Matlab基于CNN-BiGRU-Attention的锂电池剩余寿命预测
  • JVM 运行时数据区域
  • 开源本地LLM推理引擎(Cortex AI)
  • 【PZ-AU15P】璞致fpga开发板 Aritx UltraScalePlus PZ-AU15P 核心板与开发板用户手册
  • ZooKeeper核心ZAB选举核心逻辑(大白话版)
  • 性能堪比claude sonnet4,免费无限使用!claude code+魔搭GLM4.5在ubuntu上安装完整流程
  • 三高项目-缓存设计
  • SQL常见索引失效导致慢查询情况
  • Java 双亲委派机制解析和破坏双亲委派的方式