关键词不能为空

当前您在: 主页 > 英语 >

完整版freeModbus代码解读及移植笔记

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-02-01 23:47
tags:

-

2021年2月1日发(作者:偏振子)




1.



FreeModbus


协议分析




2.



应用层协议




一个任务中调用


eMBPoll()


函数。

< br>



协议必须首先调用初始化功能


eMBinit()


函数。后调用


eMBEnable()< /p>


,最后,在循环体或者单独


2.1.





系统的启动




2.1.1.



eMBInit()


函数的源码分析





RTU


方 式为例,首先,检查调用的地址是否合法。如不合法,返回错误。如果合法则继续执


行,




首先,针对


RTU


方式还是


ASCII


方式,选 择不同的编译模块。




对需要调用的 函数指针进行复制。


如果移植需要改变其他用途,


则要修改相应 的指针,


包括如下


赋值:















pvMBFrameStartCur = eMBRTUStart;














pvMBFrameStopCur = eMBRTUStop;














peMBFrameSendCur = eMBRTUSend;














peMBFrameReceiveCur = eMBRTUReceive;














pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose :NULL;














pxMBFrameCBByteReceived= xMBRTUReceiveFSM;














pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM;














pxMBPortCBTimerExpired = xMBRTUTimerT35Expired;



然后调用


eStatus =eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity);


具体初始化通讯



2.1.2.



eMBRTUInit



端口。



eMBRTUInit


这个函数主要干两件事:




第一,




初始化串口:







if( xMBPortSerialInit(ucPort, ulBaudRate, 8, eParity ) != TRUE )



{





eStatus = MB_EPORTERR;



}



这个函数在


portserial.c


中,需要用户在移植的时候根据自己的处理器编写。




第二,




初 始化计时器:首先要根据波特率计算一下是


3.5~5.0


个字 节周期的时间,然后再调用


xMBPortTimersInit( ( USHORT ) usTimerT35_50us)


,初始化计时器。这个函数在

< br>


中,需要用



2.1.3.



eMBEnable


源码分析




户在移植的时候根据自己的处理器编写。

porttimer.c




首先 ,看看


Modbus


功能是否是被关闭的,如果不是被关闭(可 能是没有被初始化或者已经打


开)


,就返回错误。




如果是


disable


状态,就干下面两件事:




l


调用


pvMBFrameStar tCur()



由于这是个函数指针,


在模块


eMBInit


中,


指向了


eMBRTUStart


函数




n


在源代码中有这样一段注释:< /p>


,意思是,首先设置成


STATE_RX_INIT


,然后打开计时器,等



t3.5

< br>以后,进入


STATE_RX_IDLE


状态。




n


看源代码中, 首先有设置


Receiver


的状态,后调用

< br>vMBPortSerialEnable


,设置接收状态,

然后打开定时器。




n


当定时器中断后,自动调用中断服务程序,在中断服务程序中,只调用了


pxMBPortCBTimerExpired


,而这是一个函数指针,在


RTU


方式初始化时,被指向了


xMBRTUT imerT35Expired()


函数。




n xMBRTUTimerT35Expired


函数在


mbrtu.c


中,在这里,我们只看第 一种方式,就是进入初始


化状态,在


t35

时间以后,只调用了一个


xNeedPoll =



xMBPortEventPost( EV_READY );



n xMBPortEventPost

函数就是在事件队列里加了一个


EV_RDY


事件。




l


然后,将< /p>


eMB


状态改为使能状态,




l


初始化结束。




2.2.





总线侦听


eMBPoll()


首先,判断系统是否被使能,如果没有,则返回错误值。




然后,检查是否有事件发生,如果有,则根据不同类型的事件 响应:




l


如果是


EV_RDY


,表示系统刚刚进入侦听状态,则什么都 不做;





l


如果状态为


EV_FRAME_R ECEIVED


,也就是接收到完整的帧,做下面两件事情:




n


调用


e Status=peMBFrameReceiveCur( &ucRcvAddress,&ucMBFrame, &usLength)



这是一


个函数指针,在


eMBInit


中,被初始化指向


eMBRTUReceive




n eMBRTURece ive


这个函数首先校验帧的长度和


CRC

,然后从协议中解析出地址、数据和长


度。




n


然后检查地址,


如果是广播地址或者是本机地址,


就调用


xMBPor tEventPost( EV


-


EXECUTE)

< p>


将接收器的状态更改为


EV_EXECUTE< /p>





l


如果状态为


EV_EXECUTE


,就在函 数列表中检查,有没有与命令字段相符合的函数来解析相


应则执行该函数,否则返回非法 功能代码。





数据发送


2.3.



发送数据通过指针


eMBRTUSend


,调用


eMBRTUSend


函数。




2.3.1.



eMBRTUSend


函数




这个函数的作用就是打包,将数据打包成帧。




l


首先,检查接收状态。因为


MODBUS


是基于


RS

< br>-


485


半双工通讯,所以当正在接收数据时,


不发送该帧。




l


如果总线空,就将数据打包,将地址和


CRC

< br>加入数据帧




l


将总线状态改为发送。






2.4.


功能注册




l


对于指定的功能代码,需要一个功能回调函数来处理,格式 如下。




eMBException eMXXXXXX ( UCHAR *pucFrame, USHORT * usLen )



l


需要通过函数

< br>eMBRegisterCB(


功能代码,函数名


)


加到处理代码中。具体源码分析从略。




2.4.1.



prvvUARTTxReadyISR()



总线状态改为发送后,会在发送缓冲时,自动调用


prvvUARTTxRe adyISR()


中断服务程序。


prvvUARTTxRea dyISR()


只调用了一个函数,就是


pxMBFrameC BTransmitterEmpty ()





2.4.2.



pxMBFrameCBByteReceived()


< /p>


pxMBFrameCBTransmitterEmpty()


是一个指针,指向了


xMBRTUTransmitFSM


函数 。




3.



数据链路层协议



< br>数据链路层是最基本的打包部分,将数据打包成帧,送到应用层。


在数据链路层协 议中,使用中


断方式来接受。那么每次接收到字符就自动调用接收字符的


ISR


程序。按照规定,应该将中断


服务程序安装给< /p>


prvvUARTRxISR(void)


函数。实际上这个函数 只调用了一个函数:




pxMBFr ameCBByteReceived()


,这个指针调用了


x MBRTUReceiveFSM


函数。




3.1. xMBRTUReceiveFSM()


函数




函数首先检查是不是处于发送状态。如果处于发送状态,直接 退出。




l


首先调用


xMBPortSerialGetByte( ( CHAR * ) & ucByte)


,获取从串口读到的字符。




l


然后检查接受状态:




n


如果是错误状态或者处于初始化状态,那么直接等待,错过 该帧。




n


如果是


STATE_RX_IDLE


空闲状态,则将指针重置 ,将收到的第一个字节存储到缓冲区,并


将状态改为


STATE _RX_RCV


状态。




n


如果处于接收状态,就判断,如果缓冲区未满,就将收到的 字节放入缓冲区,否则改为错误


状态。




l


不管在任何状态,最后都开启了


t35


计时器。在


t35


结束的时候,通过指针调用了



函数。


xMBRTUTimerT35Expired()




这么长


l xMBRTUTimerT35Expired ()


函数检查状态,如果是接收状态那就表明,已经有


t35E V_FRAME_RECEIVED


的时间里,没有收到任新字节,当前的帧结束。在队 列里增加一个



事件。



如果是错误状态,什么都不做。


l




然后关掉计时器,将状态改为空闲。


l




3.2. xMBRTUTran smitFSM()


函数


首先判断总线是否忙,如果

< p>
忙,则终止。如果不忙,则继续,根据


xMBRTUTransmitFS M


发送状态变量:



(空闲)状态,


则打开端口发送


l


如果当前为


STATE_TX_IDLE


,则进一步判断发送队列是否为空,


l


如果当


前状态为


STATE_TX_XMIT


如果不空,则发送下一个字符


n




如果空,说明发送完成,关闭发送端口,改为侦听,并将状态 改为空闲。


n




4.



传输控制




除了传输控制以外,


还有传输控制的若干函数。


通过下面

-


-


-


-


-


-


-


-



本文更新与2021-02-01 23:47,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/595908.html

完整版freeModbus代码解读及移植笔记的相关文章