野火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
英文地址,請注明出處:http://en.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;一個經驗不足的工程師可能會立刻登錄服務器&…