背景
盡管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]; /* 事件隊列的副本 */
修改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