在调试freemodbus 从机协议栈时发现,当从机协议栈使用(eMBDisable())
接口触发停止协议栈,协议栈成功被停止,再使用(eMBEnable())
接口打开协议栈时,有时候会打开成功,有时候会出现断言失败(报错位置:RT_ASSERT( eSndState == STATE_TX_IDLE ))
。
增大从机的通讯频率后,再次使用上述接口,出现报错的概率也大大增加。
仔细分析后发现,如果在协议栈是空闲的状态下,停止/打开是没有问题的,如果在协议栈忙碌(接收或者发送)的过程中停止/打开,就会出现报错,主要还是这两种接口并没有对资源的占用进行重置处理,这里的资源就包括忙碌过程中使用的一些状态或者缓存之类的。
这里我想到的两种方法解决这个问题:
方法一
在停止或者打开接口中重置协议栈在忙碌过程中被占用的资源,尝试修改停止接口如下:
void
eMBRTUStop( void )
{
ENTER_CRITICAL_SECTION( );
vMBPortSerialEnable( FALSE, FALSE );
vMBPortTimersDisable( );
//关闭协议栈时,协议栈处于忙碌状态,需要初始化协议栈占用的资源,防止下一次打开时出现错误,保证下一次打开时,协议栈是一个新的状态
if(eRcvState != STATE_RX_IDLE ) //接收过程中关闭协议栈
{
eRcvState = STATE_RX_INIT;
usRcvBufferPos = 0;
rt_memset((UCHAR *)ucRTUBuf,0,sizeof(ucRTUBuf));
}
if(eSndState != STATE_TX_IDLE) //发送过程中关闭协议栈
{
eSndState = STATE_TX_IDLE;
usSndBufferCount = 0;
pucSndBufferCur = RT_NULL;
}
EXIT_CRITICAL_SECTION( );
}
方法二
思想就是避免在协议栈忙碌的时候被打开或者被关闭,只有当协议栈空闲(freemodbus没有提供空闲状态,需要自己实现)时允许打开或者关闭,具体没有尝试过。
大家有什么更好的方法欢迎交流
方法一比起方法二感觉不是很安全,方法二保证了协议栈一个完整的操作不被打断。目前我在使用方法一的过程中还没有遇到问题。
再有一点,freemodbus主机协议栈对应的这两个接口在使用时也会出现问题,使用停止接口停止协议栈后,再使用使能接口偶尔无法打开主机协议栈了(如果通讯比较频繁,概率会很大),分析后发现应用线程被挂死,挂死的原因是eMBMasterWaitRequestFinish()接口永远无法等到事件导致的。
按照上述修改,在通讯速率依然出现发送和接收的断言,为了保证可靠性,修改了启动接收和关闭接收的时机,防止接收中断导致状态改变引起断言,在接收到一帧数据时,就立即关闭接收:如下图


在帧处理完成后再打开接收:如下图
这样做是比较安全的,尤其是通讯速率比较快的情况下
欢迎交流