该代码是基于RT-thread操作系统的主机通信程序。 现将代码分析写下来,以便自己的移植操作以后后期的维护。 1,首先要有一个线程(函数)进行主机发出请求。 具体内部操作是:准备了 从机地址,数据帧指令,数据帧地址,数据帧长度, 然后建立一个事件:EV_MASTER_FRAME_SENT,探后等待请求完成。 2,在eMBMasterPoll(void)函数中,Poll线程(函数),检测到有事件EV_MASTER_FRAME_SENT 发生,则进行该事件的执行。该事件的执行过程是:peMBMasterFrameSendCur()函数。 该函数是一个函数指针,指向了eMBMasterRTUSend(),实际上是调用了RTU层的发送函数。 实际上第1步进行的准备工作操作的数据帧地址都是在RTU层的静态缓冲区。第2步进行的发送 也是在这个静态缓冲区进行的。 函数eMBMasterRTUSend()执行过程: 首先检测一下当前的接收状态机是 空闲状态,则在静态数据缓冲区进行数据的操作,写入数据长 度,写入CRC校验码。最后一步设置发送状态机的当前状态为开始传送状态为: STATE_M_TX_XMIT,并且开启发送口。 3,接下来的执行就是在中断服务程序中。中断服务程序中执行的回调函数也是一个状态机形式: 实际就是:xMBMasterRTUTransmitFSM(),在该函数中的状态机执行情况:在 STATE_M_TX_XMIT状态只要没有发送结束将一直进行数据发送直到usMasterSndBufferCount 数据为0。更新当前数据帧是否为广播地址,关闭发送口,开启接收口。同时设置发送状态机 状态为:STATE_M_TX_XFWR。如果是广播地址则使能广播延时定时器,如果不是广播开启 响应延时定时器。 4, 在定时器服务函数xMBMasterRTUTimerExpired中,根据第3步,当前发送状态机是STATE_M_TX_XFWR 状态. 如果当前数据帧是广播则直接设置当前发送状态机为STATE_M_TX_IDLE,空闲状态。同时关闭定时器。 如果当前数据帧不是广播帧,则告诉监听进程数据发送错误,设置从机响应超时错误。同时设置主机 发送状态机为空闲状态,同时关闭定时器。如果是主机当前的定时模式是:MB_TMODE_CONVERT_DELAY 则关闭主机忙状态。 5 ,截止目前为止eRcvState(接收状态机)是STATE_M_RX_IDLE。发送状态机(eSndState)为STATE_M_TX_IDLE 主机指令已经完成了送出动作。 下一步应该就是,主机接收来自从机的回传数据。 当串口接收中断到来,则调用prvvUARTRxISR() -> pxMBMasterFrameCBByteReceived() 而pxMBMasterFrameCBByteReceived作为一个回调函数,在mb_m.c文件中被初始化为:xMBMasterRTUReceiveFSM 则mbrtu_m.c文件中的xMBMasterRTUReceiveFSM()函数最终被中断函数调用。 6, 现在进入xMBMasterRTUReceiveFSM()函数中分析。 进入函数执行接收动作。如果是首次进入该函数,接受状态机为空闲模式STATE_M_RX_IDLE 则关闭主机超时定时器,设置发送状态机为空闲,同时主机接收缓冲区位置指针(usMasterRcvBufferPos)置0。 根据usMasterRcvBufferPos,在缓冲区ucMasterRTURcvBuf[],里面放置接收数据。 同事设置接收状态机为接收状态STATE_M_RX_RCV。同时开启超时定时器。 还是在xMBMasterRTUReceiveFSM()函数中,接受状态机为空闲模式STATE_M_RX_RCV,只要缓冲区位置指针小于一帧数据 的最大值,则一直往缓冲区写数据。否则大于一帧数据的最大值,则接收状态机置错误标志。下一步更新T3.5定时器。 直到数据接收完成后。T3.5定时器超时到达,表示一帧数据完成。那么在xMBMasterRTUTimerExpired()中断服务函数中, 根据接收状态机模式STATE_M_RX_RCV,则设置事件xMBMasterPortEventPost(EV_MASTER_FRAME_RECEIVED)。表示 一帧数据接收完成。 7 ,现在根据当前事件EV_MASTER_FRAME_RECEIVED,在eMBMasterPoll()函数中,调用peMBMasterFrameReceiveCur(), 进行长度检测和CRC检测,完成之后获取接收的数据帧中数据地址(pucRcvAddress),同事传出数据帧的缓冲区有效数据的 帧地址给上层应用。 将接收的数据帧地址和主机发送的地址进行比较,正确时候则设置事件:xMBMasterPortEventPost( EV_MASTER_EXECUTE ) 8, 仍然是根据当前事件EV_MASTER_EXECUTE ,在eMBMasterPoll()函数中,提取数据帧的功能码,根据功能码,调用对应 功能码的函数指针。 举例:如果一开始主机发送了读取从机地址为2,3X区域,区地址100的20个数据,那么返回的数据中, 肯定提取到功能码04,然后根据04功能码对应的函数,进行对应的数据更新。 如果功能码超出协议规定的范围,则抛出EV_MASTER_ERROR_PROCESS异常事件。 9, 如果真的有异常事件EV_MASTER_ERROR_PROCESS,那么则清除主机忙状态。 到此为止,我们完成了主机从发送数据到接收数据并且处理完成的分析。
|