LIteOS的RS485通讯--Freemodbus协议及RTU移植重点
Freemodbus
FreeMODBUS 是针对通用的Modbus协议栈在嵌入式系统中应用的一个实现。Modbus协议是一个在工业制造领域中得到广泛应用的一个网络协议。一个Modbus通信协议栈包括两层:定义了数据结构和功能Modbus应用协议和网络层。在FreeMODBUS的当前版本中,提供了RTU/ASCII传输模式。也支持在TCP传输。Freemodbus遵循BSD,这意味着本协议栈的实现代码可以应用于商业用途。目前版本的FreeModbus支持如下的功能码:
-
读输入寄存器 (0x04)
-
读保持寄存器 (0x03)
-
写单个寄存器 (0x06)
-
写多个寄存器 (0x10)
-
读/写多个寄存器 (0x17)
-
读取线圈状态 (0x01)
-
写单个线圈 (0x05)
-
写多个线圈 (0x0F)
-
读输入状态 (0x02)
-
报告从机标识 (0x11)
接收和传输Modbus RTU/ASCII数据帧是通过一个由硬件提取层的调用来驱动状态机来实现的。这就使得该协议非常容易移植到其他的平台之上。当收到一个完整的数据帧后,该数据帧被传入Modbus应用层,数据帧的内容在该层得到解析。为例方便增加新的Modbus功能,Freemodbus在应用层通提供了Hooks。
如果用到了Modbus TCP协议,那么当准备处理一个新数据帧的时候,移植层就必须首先向协议栈发送一个事件标志。然后,协议栈调用一个返回值为接收到的Modbus TCP数据帧的函数,并且开始处理这个数据帧。如果数据有效,则相应的Modbus反馈帧将提供给移植层生成反馈帧。最后,该反馈被发送到客户端。
硬件需求
最小的硬件需求:
-
大约5-10Kbyte的flash和300byte的RAM资源
-
一个支持中断的异步串行通讯接口
-
一个精度大约750微妙的定时器
有无操作系统都可以进行操作。如果有RTOS,则可以使用事件队列来避免在MODBUS任务中忙于等待。对于在没有RTOS的情况下运行的系统,可以使用结合全局变量的基于轮询的方法。
实际的内存要求取决于所使用的模块。下表显示了所需的内存以及已编译的所有可支持选择的函数。
MODULE |
ARM CODE |
ARM RAM (STATIC) |
AVR CODE |
AVR RAM (STATIC) |
Modbus RTU (Required) |
1132Byte |
272Byte |
1456Byte |
266Byte |
Modbus ASCII (Optional) |
1612Byte |
28Byte |
1222Byte |
16Byte |
Modbus Functions [1] |
1180Byte |
34Byte |
1602Byte |
34Byte |
Modbus Core (Required) |
924Byte |
180Byte |
608Byte |
75Byte |
Porting Layer (Required [2]) |
1756Byte |
16Byte |
704Byte |
7Byte |
Totals |
7304Byte |
530Byte |
5592Byte |
398Byte |
支持的设备类型
官方已经支持的设备类型包括:(官方都已经对这些支持提供了移植参考)
Cortex M3 、ARM、AVR 、Coldfire 、MSP430 、Z8Encore 、Win32、Linux。
功能配置
通过配置文件mbconfig.h来配置freemodbus的功能,也可对其进行剪裁
Defines
移植的重点
移植主要是对接口文件的修改,及Port文件夹中的四个文件portserial.c、porttimer.c、port.h三个文件,里面有串口的驱动的映射、定时器驱动的映射、及对中断的处理映射。
在port.h文件中,我们需要定义中断使能和中断去使能的宏,来freemodbus可以调用实现开关全局中断进入临界区功能。
如在ARM-Cortex,我们可以利用CMSIS函数实现中断的开关,
将这两个宏进行补全实现了freemodbus进入临界区的功能。
在portserial.c文件中,我们要实现将串口或RS485(UART)映射到Freemodbus的串口上,这里每个芯片或构架因为串口驱动各不相同,就需要参考自己的串口驱动进行配置,本文以STM32 HAL库驱动进行讲解说明。
首先串口使能开关控制的功能函数的映射,在这里Freemodbus来控制串口开关
void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
if (xRxEnable) //接收使能
{
__HAL_UART_ENABLE_IT(&husartx_rs485,UART_IT_RXNE);
}
else
{
__HAL_UART_DISABLE_IT(&husartx_rs485,UART_IT_RXNE);
}
if (xTxEnable) //发送使能
{
__HAL_UART_ENABLE_IT(&husartx_rs485,UART_IT_TXE);
}
else
{
__HAL_UART_DISABLE_IT(&husartx_rs485,UART_IT_TXE);
}
}
然后在下面两个函数实现freemodbus的发送和接收,这两个函数同样需要映射到串口的发送接收上
BOOL xMBPortSerialPutByte( CHAR ucByte ) //freemodbus发送
{
if(HAL_UART_Transmit(&husartx_rs485 ,(uint8_t *)&ucByte,1,0x01) != HAL_OK )
return FALSE ;
else
return TRUE;
}
BOOL xMBPortSerialGetByte( CHAR * pucByte ) //freemodbus接收
{
if(HAL_UART_Receive (&husartx_rs485 ,(uint8_t *)pucByte,1,0x01) != HAL_OK )
return FALSE ;
else
return TRUE;
}
在在在porttimer.c文件中,Modbus协议栈需要一个计时器来检测帧结束,计时器的分辨率应为串行字符时间的一半。我们通常使用硬件定时器或是软件定时实现该功能,如果是带操作系统的工程,则可以利用
BOOL xMBPortTimersInit( USHORT usTim1Timerout50us ) 映射定时初始化驱动
inline void vMBPortTimersEnable( ) 映射定时器开使能驱动
inline void vMBPortTimersDisable( ) 映射定时器关使能驱动
总结
freemodbus自己可以按照队列操作进行运行,开发者只需要配合自己的开发板的串口和定时器的驱动进行驱动PORT映射开发,就可以实现自己的modbus RTU的从站操作,利用freemodbus可以大大减低自己编写modbus RTU 出现代码冗余和漏洞的可能,只要简单配置就可以让自己的modbus协议跑起来。
如有相关问题请关注个人公众号;ashysage
- 点赞
- 收藏
- 关注作者
评论(0)