FreeModbus笔记doc.docx

上传人:b****5 文档编号:8291803 上传时间:2023-01-30 格式:DOCX 页数:19 大小:20.14KB
下载 相关 举报
FreeModbus笔记doc.docx_第1页
第1页 / 共19页
FreeModbus笔记doc.docx_第2页
第2页 / 共19页
FreeModbus笔记doc.docx_第3页
第3页 / 共19页
FreeModbus笔记doc.docx_第4页
第4页 / 共19页
FreeModbus笔记doc.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

FreeModbus笔记doc.docx

《FreeModbus笔记doc.docx》由会员分享,可在线阅读,更多相关《FreeModbus笔记doc.docx(19页珍藏版)》请在冰豆网上搜索。

FreeModbus笔记doc.docx

FreeModbus笔记doc

 

FreeModbus笔记

 

Modbus-RTU是基于485总线基础上一个主从协议,主站主动发起通信,从站接收主站的消息并响应主站的指令。

 

这里主要探讨

 

FreeModbus

 

中的

 

RTU从站协议的实现。

 

从站的串口每次接收一个字节数据,并产生串口中断(中断打开)

个个字节如何组成一个Modbus的数据帧呢?

,那么串口中传过来的一

 

这是通过一个重要的参数

T3.5来进行判断的。

 

T3.5就是串口传递

3.5个字符的时间,这个时间和波特率相关,不同波特率下,

T3.5时

间不等。

 

3.5个字符时间区分不同的帧,即接收到的两个字符之间时间间隔小于3.5个字符时间时认为是同一个帧的,如果间隔大于3.5个字符时间则认为是不同帧的,在一般的串口通信中,发送1个字符需要:

1位起始位,8位数据位,1位校验位

(可无),1位停止位,总共1+8+1+1=11位,3.5个字符时间就是3.5*11=38.5位,假如波特率是9600,那么传输1位的时间是1000/9600=0.10416667(ms),这样,3.5个字符时间就大约是4ms,即定时器需要的中断时间

 

串行口数据帧

D0D1D2D3D4D5D6D7Par停止位

起始位

 

1个字节1个字节1个字节1个字节1个字节

t>T3.5

T>T3.5

T

 

Modbus数据帧

 

也就是串口在静默了

 

T3.5秒以后收到的第一个字节作为一个

 

Modbus

 

数据帧的首字节,然

后收到的字符间隔只要不超出

T3.5的时间间隔,都作为这一帧数据来处理。

当串口在>

T3.5

没有收到数据时,则认为当前主站

Modbus

发送完了一个数据帧。

可以进行后面的

Modbus

数据帧处理了。

再收到的数据回作为下一个

Modbus

数据帧的首字节。

 

接收一个字节,是由串口中断来进行完成的,判断是否超时是由定时器中断来完成的。

因此

以上看是很清楚的一个协议流程需要串口和定时器配合共同完成。

所以在看RTU实现协议

时一定要记住这点。

 

从站主要是接收,被动响应,所以先分析接收机的状态:

 

接收状态机

 

接收状态包含以下几种:

 

STATE_RX_INIT,/*!

<接收机在初始态*/

 

STATE_RX_IDLE,/*!

<接收机在空闲态*/

 

STATE_RX_RCV,/*!

<接收到一帧数据*/

 

STATE_RX_ERROR/*!

<错误数据帧*/

 

状态机转换图:

 

串口收到一个字节

eMBEnable()

重启T3.5开始下一个

T3.5延迟

发送一个EV_READY

事件

eMBRTUStart()

设置初态

T3.5超时

T3.5

超时

STATE_RX_INIT

STATE_RX_IDLE

启动T3.5定时

T3.5超时

串口收到一

个字节

发送一个EV_FRAME_RECEIVED

事件

 

STATE_RX_RCV

串口收到一个新字

节,且总字节数不

超过最大帧长

 

串口收到一个新字节,但总字节数超过最大帧长

STATE_RX_ERROR

 

串口收到一个新字节

 

状态机的转换不是由一个函数来确定的,是由多个函数共同作用的结果。

主要要T3.5的定

时中断和串口的接收中断。

 

所以在程序一开始要对串口和定时器进行正确的设置。

 

当初始化完毕后,接收状态机初始态是STATE_RX_INIT,同时T3.5定时器启动。

如果在T3.5

定时到来之前,串口收到了一个字节,则认为是还没准备好的情况下,总线发起的一次

Modbus传输,此时这帧数据是不处理的,所以,要等到这一帧数据传送完(T3.5超时)。

 

当发生T3.5超时事件时,说明总线上的数据帧已经传完,处于空闲状态,为发起下一帧数

据传输做好了准备。

所以接收状态机转换为STATE_RX_IDLE,同时发送一个EV_READY事件,

告诉Modbus以及准备好接收数据了。

同时关闭T3.5定时。

 

在STATE_RX_IDLE状态下,只会接收串口数据来触发状态转换(定时被关闭)。

当接收到一

个字节时,认为总线开始了一个新的数据帧的传输,把这个字节保存在Modbus数据缓冲区,并将缓冲区指针加1,并将接收状态机转换为STATE_RX_RCV。

 

在STATE_RX_RCV状态下,接收到一个新字节,将该字节保存在缓冲区,并将缓冲区指针加

1,判断接收的字节总长是否>最大帧长,如果不大于,继续保持STATE_RX_RCV状态,等待

接收下一个字节或超时(接收完成)。

当大于最大帧长,说明接收到了错误帧。

状态转到

STATE_RX_ERROR。

 

在STATE_RX_RCV状态下,产生了一个T3.5超时,此时认为总线已经发送完成一个Modbus

数据帧,将状态转换到STATE_RX_IDLE,等待下一个数据帧到来。

同时触发EV_FRAME_RECEIVED事件,告诉ModbusPoll已经成功接收一帧数据,可以解析并处理了。

 

在STATE_RX_ERROR状态下,接收到再多的字节都认为是错误的,所以一直停留在错误态,直到来了一个T3.5超时事件,此时认为总线上错误的数据帧发送完毕,总线静默,为下一

个数据帧准备好!

接收状态机转换为STATE_RX_IDLE。

 

Modbus的初始化流程:

 

eMBRTUInit()

调用

eMBInit()

ModBus初始化:

调用

调用

1、设置从机号

eQueuedEvent为空

2、设置eMode(RTU)

eMBState=

3、设置波特率

STATE_DISABLED

Uart_Init()

xMBPortTimersInit()

4、设置T35定时器

 

ModBus使能:

eMBState=

1、置端口为接收状态

STATE_ENABLED

2、开端口定时功能

eRcvState=

此时串口中断开,定时中断开

STATE_RX_INIT;

 

以下是FreeModbus的各个功能函数解析:

 

1、//-----初始化Modbus协议------------------------

 

eMBInit(MB_RTU,Slave_Adress,0,115200,MB_PAR_NONE);

 

eMBInit()

 

状态码=无错误

 

地址号是否有效

 

 

状态码=非法参数

 

MB_RTU

 

eMBRTUInit

 

返回状态码

设备号=地址号

 

eMode=?

 

MB_ASCII

 

eMBASCIIInit

 

返回状态码

 

状态码=无错误

 

 

xMBPortEventInit

 

正确

 

eMBState=

STATE_DISABLED

 

default

 

状态码=非法参数

 

错误

 

状态码

=MB_EPORTERR

 

返回状态码

 

eMBRTUInit(UCHARucSlaveAddress,UCHARucPort,ULONGulBaudRate,eMBParityeParity)

 

eMBRTUInit()

 

调用库函数对串口初始化

uart_init(ulBaudRate);

 

 

usTimerT35_50us

=更长些

 

根据超时时间

初始化定时器

3.5个字符时间区分不同的帧,即接收到的两个字符之间时间间隔小于3.5个字符时间时认为是同一个帧的,如果间隔大于3.5个字符时间则认为是不同帧的,在一般的串口通信中,发送1个字符需要:

1位起始位,8位数据位,1位校验位(可无),1位停止位,总共1+8+1+1=11位,3.5个字符时间

就是3.5*11=38.5位,假如波特率是9600,那么传输1位的时间是1000/9600=0.10416667(ms),这

样,3.5个字符时间就大约是4ms,即定时器需要的中断时间

 

状态码=无错误

 

xMBPortSerialInit()

 

初始化是否成功

状态码

根据波特率设

定超时时间

=MB_EPORTERR

波特率>19200

usTimerT35_50us

=35

 

xMBPortTimersInit()

 

初始化是否成功

 

状态码

=MB_EPORTERR

 

返回状态码

 

至此,Modbus的初始化工作完成。

 

串口中断被打开,超时定时器配置好。

 

eMBEnable()

 

该函数指针指向

eMBRTUStart

 

eMBRTUStart

 

eMBEnable()

 

eStatus状态码=无错误

 

初始化时

的状态否

eMBState==

STATE_DISABLED

 

pvMBFrameStartCur()

 

eMBState=

STATE_ENABLED

 

返回eStatus状态码

 

eMBRTUStart()

 

eStatus=

MB_EILLSTATE

 

置接收状态位初

始化状态

 

置端口为接收状态

开端口定时功能

 

eRcvState=

STATE_RX_INIT;

 

vMBPortSerialEnable(TRUE,FALSE);

在端口使能函数中

vMBPortTimersEnable();

设置485的收发状态

 

返回

 

当串口接收到数据时发生中断,由串口中断程序处理USART1_IRQHandler()

 

USART1_IRQHandler

()

接收事件?

调用prvvUARTRxISR()

处理

发送准备好事件?

调用

调用prvvUARTTxReadyISR()

处理

pxMBFrameCBByteReceived();

处理

在RTU模式,该函数指针指向

xMBRTUReceiveFSM()

调用

实际调用的是

返回

pxMBFrameCBTransmitterEmpty();

xMBRTUTransmitFSM()

处理

在RTU模式,该函数指针指向

xMBRTUTransmitFSM

()

实际调用的是xMBRTUTransmitFSM()

 

实际是调用函数:

USART_ReceiveDa

ta(USART1);

 

STATE_RX_INIT

 

vMBPortTimersEnable();

 

xMBRTUReceiveFSM()

 

确认当前发送为空闲状态

 

调用

xMBPortSerialGetByte()

接收一个字节数据

 

判断当前接收状态

eRcvState

 

STATE_RX_ERRORSTATE_RX_IDLESTATE_RX_RCV

 

vMBPortTimersEnable();

接收第一个字节,并将状

将当前接收字节加入到接收缓冲

态置为STATE_RX_RCV

区,当接收字节数大于最大帧

同时,启动T3.5定时器

长,将放弃该帧(eRcvState=

STATE_RX_ERROR)

每收到一个字节复位T3.5定时器

 

返回

 

xMBRTUTransmitFSM()

 

确认当前接收为空闲状态

 

判断当前接收状态

eSndState

 

STATE_TX_IDLE

 

vMBPortSerialEnable(TRUE,FALSE);

由发变收

 

产生一个发送完毕事件

xNeedPoll=xMBPortEventPost(

EV_FRAME_SENT);

vMBPortSerialEnable(TRUE,FALSE);

由发变收

 

STATE_TX_XMIT

 

发送缓冲区不为零

 

 

发送当前字节

xMBPortSerialPutByte((CHAR

)*pucSndBufferCur)

 

实际是调用函数:

USART_SendData(USART1,ucByte);

 

更新缓冲器指针和大小

 

返回

 

TIM2_IRQHandler

中断函数调用

调用

 

TIMERExpiredISR(void)

 

调用

 

pxMBPortCBTimerExpired()

RTU模式下,该函数指针指向

xMBRTUTimerT35Expired()

判断当前接收状态

eRcvState

STATE_RX_INIT

STATE_RX_ERROR

STATE_RX_RCV

Default

置返回值为错误态

产生一个准备好事件

xMBPortEventPost(

产生一个接收一帧事件

确认各参数正常?

EV_READY);xMBPortEventPost(

EV_FRAME_RECEIVED)

 

vMBPortTimersDisable();

eRcvState=STATE_RX_IDLE;

 

返回

 

Modbus的主查询函数eMBPoll()

 

eMBPoll()

 

状态码=无错误

 

ModBus是否使能协议栈出错,并返回错误码

 

EV_READY

获取当前MB_EVENT成功

 

 

判断当前EVENT

EV_FRAME_SENT

EV_FRAME_RECEIVEDEV_EXECUTE

peMBFrameReceiveCur(

//从接收缓冲取出功能码

&ucRcvAddress,

&ucMBFrame,&usLength

Break;

);//查询接收结果,并将结

依次查询各个功能码

Break;果保存到ucMBFrame

查询接收结果无错误

本机支持该功能码

判断当前数据帧是本机

调用该功能码处理函数

数据或是广播数据

派送一个执行事件

xMBPortEventPost(

地址不等于广播地址

EV_EXECUTE);

按照MB协议,发送应答帧

 

返回

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1