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

背景

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

调试思路

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

具体操作

在portevent_m.c的开头添加:

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文件

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

相关推荐
♞沉寂5 小时前
51单片机:发光二极管与动态数码管控制
单片机·嵌入式硬件·51单片机
jianqiang.xue6 小时前
Proteus8 + STM32CubeMX 实现 STM32F103R6 串口通信教程
stm32·单片机·嵌入式硬件·mcu·物联网·51单片机·proteus
KWTXX7 小时前
单片机键盘接口程序设计(汇编语言)
单片机·计算机外设·nosql
La Pulga8 小时前
【STM32】定时器输入捕获
c语言·stm32·单片机·嵌入式硬件·mcu
DebugKitty9 小时前
硬件开发1-51单片机3-串口
单片机·嵌入式硬件·51单片机·串口·全双工·同步通信·串口寄存器
殷忆枫10 小时前
基于STM32的智能家居语音控制系统设计
stm32·嵌入式硬件·智能家居
hazy1k10 小时前
8051单片机-成为点灯大师
驱动开发·嵌入式硬件·51单片机
weixin_4715257812 小时前
【单片机day02】
单片机·嵌入式硬件
翻斗花园牛姥姥13 小时前
51单片机GPIO与中断全解析
单片机·嵌入式硬件