FreeModbus 移植笔记
目录
1 FreeMODBUS介绍
2 FreeMODBUS官网及源码下载地址
3 移植之前的准备
3.1 FreeModbus V1.6
3.2 Modbus
3.3 Modbus Registers
3.4 Modbus Configuration
3.5 Utilities
3.6 移植和头文件
3.7 FreeModbus Examples
3.8 Porting for RTU/ASCII
3.8.1 创建移植文件及目录
3.8.2 平台特性(port.h)
3.8.3 定时器功能实现
3.8.4 Modbus-RTU/ASCII的移植
3.8.5 事件队列的实现
3.9 Tips
FreeMODBUS 是针对通用的Modbus协议栈在嵌入式系统中应用的一个实现。Modbus协议是一个在工业制造领域中得到广泛应用的一个网络协议。一个Modbus通信协议栈包括两层:定义了数据结构和功能Modbus应用协议和网络层。在FreeMODBUS的当前版本中,提供了Modbus Application Protocol v1.1a 的实现并且支持在Modbus over serial line specification 1.0中定义的RTU/ASCII传输模式。从0.7版本开始,FreeModbus也支持在TCP defined in Modbus Messaging on TCP/IP Implementation Guide v1.0a中定义的TCP传输。Freemodbus遵循BSD[1] ,这意味着本协议栈的实现代码可以应用于商业用途。目前版本的FreeModbus支持如下的功能码:
读输入寄存器 (0x04)
读保持寄存器 (0x03)
写单个寄存器 (0x06)
写多个寄存器 (0x10)
读/写多个寄存器 (0x17)
读取线圈状态 (0x01)
写单个线圈 (0x05)
写多个线圈 (0x0F)
读输入状态 (0x02)
报告从机标识 (0x11)
本实现基于最新的标准并且与标准完全兼容。接收和传输Modbus RTU/ASCII数据帧是通过一个由硬件提取层的调用来驱动状态机来实现的。这就使得该协议非常容易移植到其他的平台之上。当收到一个完整的数据帧后,该数据帧被传入Modbus应用层,数据帧的内容在该层得到解析。为例方便增加新的Modbus功能,Freemodbus在应用层通提供了Hooks。
如果用到了Modbus TCP协议,那么当准备处理一个新数据帧的时候,移植层就必须首先向协议栈发送一个事件标志。然后,协议栈调用一个返回值为接收到的Modbus TCP数据帧的函数,并且开始处理这个数据帧。如果数据有效,则相应的Modbus反馈帧将提供给移植层生成反馈帧。最后,该反馈被发送到客户端。
官网地址:https://www.embedded-experts.at/en/freemodbus/about/
源码下载地址:https://www.embedded-experts.at/en/freemodbus-downloads/
在移植FreeModbus之前,应该先看一下freeModbus的API文档,了解一下freeModbus的接口和使用方法,对freeModbus建立初步认识。
https://www.embedded-experts.at/en/freemodbus/api-documentation/
上面网站可以打开FreeModbus的API文档.
FreeModbus中简单介绍了FreeModbus版本的演进和功能的增加,然后Port列出了不同类型单片机的移植示例名称。
Modbus文件中详细说明了mb.h文件中的宏定义,枚举含义,调用的函数已经FreeModbus的使用方法。
重点:FreeModbus的应用方法。
先调用eMBInit(),然后调用eMBEnable()使能协议站,最后在循环中调用eMBPoll()。
Modbus Register文件中说明了输入寄存器、保持寄存器、线圈、离散输入寄存器各种寄存器回调函数的功能、参数和返回值的含义。
Modbus Configuration文件说明了mbconfig.h文件中宏定义的功能,通过对宏定义的配置可实现对FreeModbus的裁剪,如,如果不使用Modbus-ASCII和Modbus-TCP可以配置MB_ASCII_ENABLED(0),MB_TCP_ENABLED(0).
Utilities文件说明了Modbus中位和字符串数组操作函数的功能和参数返回值。
主要在操作线圈和离散寄存器时使用。
移植和头文件只列举例文件名称。
列举了各类单片机的移植示例代码和说明
描述了modbus移植步骤和需要移植的文件
这部分内容非常重要。
第一步,为移植文件创建目录。推荐创建“demo/PLATFORM”的顶层目录,用于存放应用文件和工程文件,在”PLATFORM”的次级文件目录下创建“port”文件夹用于存放FreeModbus移植文件,如下图:
可以直接复制下载的freeModbus的源码中的“demo/BARE”文件夹的内容到新建的工程中,开始移植工作。
应该检查一下port.h文件,检查其是否适合当前的平台,并且定义两个宏定义ENTER_CRITICAL_SECTION和EXIT_CRITICAL_SECTION。用于关闭全局中断和打开全局中断。
注意:进入临界区ENTER_CRITICAL_SECTION和退出临界区EXIT_CRITICAL_SECTION主要应用于保护数据的完整性,尤其是使用操作系统后,避免一组数据在读取和写入时别打断而造成数据错位的情况发生。
Modbus协议栈需要一个定时器来检测数据帧的末尾。这个定时器的精度应该是半个字符的传输时间。例如,假设一个字符需要11位,波特率位38400时,一个字符的传输时间大约是280us。两帧数据之间最小的超时时间间隔是3.5个字符传输间隔。
首先应该实现xMBPortTimersInit( USHORT usTim1Timerout50us) 和 vMBPortTimersEnable( )这两个函数。测试代码如下:
在中断函数中调用pxMBPortCBTimerExpired,并且设置一个断点或者反转LED.在调用vMBPortTimersEnable( )之后,应该每隔1ms发生一次中断,最后需要检查vMBPortTimersDisable( )是否工作正常。
注:xMBPortTimersInit( USHORT usTim1Timerout50us)实现的是50us整数倍的定时间隔,参数usTim1Timerout50us用于设置50us的倍数。
串口层的移植需要实现以下功能:串口的初始化、接收功能的使能和失能、发送功能的使能和失能、单个字符的接收和发送回调函数等。
需要实现的函数有:
串口初始化函数xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )。
串口接收发送设置函数vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ).
此外,还需要创建两个串口的中断服务程序,一个是接收中断,一个是发送中断,通常从接收中断开始创建比较简单。
调用如下代码开始测试接收中断程序,
创建串口接收中断,设置断点并且检查xMBPortSerialGetByte( CHAR * pucByte )是否正确返回了接收到的字符。
串口接收中断如下:
接下来,实现发送中断部分,测试代码如下:
开启要给终端程序,并且在发送缓存空中断中仅调用xMBPortSerialPutByte( 'a' ),发送中断的测试代码如下:
如果上面的功能都测试正常,就可以在portserial.c中逐个实现。
如果你的工程没有使用操作系统,那么事件队列的的实现已经完成。如果您有幸在操作系统中使用FreeModbus协议栈,其不同之处如下:
1、在启动时创建一个任务,在循环中调用eMBPoll(),如下图:
可以参照STR71x对FreeRTOS的移植例子。
2、修改xMBPortEventPost函数,发送一个事件到队列。请注意,此函数将从中断服务程序(ISR)调用,因此请查看RTOS文档
3、修改xMBPortEventGet从队列中接收事件。eMBPoll()会定期去查询队列,直到有事件发送到队列时,eMBPoll都应该是阻塞的。
此外,必须修改串口和定时器中断功能。每当协议处理程序回调函数pxMBFrameCBByteReceived、pxMBFrameCBTransmitterEmpty和pxMBPortCBTimerExpired返回TRUE时,都应在退出ISR后进行上下文切换,因为事件已发布到队列。忘记这样做会导致协议栈的性能降低
Tips文件中说明了如何优化代码的方法。
这部分为使用FreeMODBUS协议栈提供一些使用技巧。
减少存储的使用。
FreeMODBUS对存储的使用情况可以通过下面几个方法改变。这里有几个基础的技巧而且很容易实现。
如果对存储空间有更严格的限制,可以尝试下面几个选项,注意这几个选项对协议栈的特性有影响。