xukai871105 发表于 2014-3-20 22:52:40

freemodbus modbus TCP 学习笔记

1.前言
    使用modbus有些时间了,期间使用过modbus RTU也使用过modbus TCP,通过博文和大家分享一些MODBUS TCP的东西。在嵌入式中实现TCP就需要借助一个以太网协议栈,在这里我选择最简单的uIP协议栈。uIP协议栈简单易用方便上手,相比于LwIP无论是移植还是使用难度都低些,这样就可以把更多的精力花在modbus tcp协议本身而不必花大量的时间研究以太网协议栈。modbus协议栈为freemodbus
    【发表本文主要目的,还文字债】


【其他资料】
    【1】uIP学习笔记
    【2】MODBUS协议整理——汇总

【工程代码】
    示例代码托管于GitHub——【Github Clone】
    如果有问题我会及时更新。
【使用说明】
    【1】工具链为IAR 6.5
    【2】从机IP为固定IP 192.168.1.15,请保证从机和路由器位于同一个网段中。
    【3】modbus tcp的侦听端口号为502

2.MODBUS TCP注意点
2.1 主机和从机、服务端和客户端


图1 MODBUS请求响应模型
【在modbus协议中】
主机发送modbus请求,从机根据请求内容向主机返回响应。在modbus协议中,主机总是主动方,从机总是被动方。
【在网络应用中】
在网络应用中存在客户端和服务器端,客户端(例如浏览器)发送请求到服务器,服务器向客户端返回内容(例如HTML文本)。
【在modbus tcp中】
主机是客户端,而从机是服务器端。千万不要以为服务器端重要,主机也重要,所以主机就是服务器端。

2.2 是否可以多主机
    通过前面的分析,主机为客户端那么modbus tcp支持多个主机,在一个局域网中可存在多个主机和多个从机。从机的连接能力(连接主机的数量)由uIP的最大TCP连接个数决定。

2.3 modbus TCP协议简述
modbus TCP和modbus RTU基本相同,但是也存在一些区别
    【1】从机地址变得不再重要,多数情况下忽略。从某种意义上说从机地址被IP地址取代
    【2】CRC校验变得不再重要,甚至可以忽略。由于TCP数据包中已经存在校验,为了不重复造轮子,modbus TCP干脆取消了CRC校验。

modbus TCP和modbus RTU的区别可使用下图概括


图2 modbus TCP数据包和modbus RTU数据包比较

在modbus TCP中包含一个MBAP头,该头包含以下几个部分

区域长度
描述
客户端
服务器

传输标志
2字节
MODBUS 请求和响应传输过程中
序列号
客户端生成应答时复制该值

协议标志2字节
Modbus协议默认为0
客户端生成
应答时复制该值

长度
2字节
剩余部分的长度客户端生成
应答时由服务器端生成

单元标志
1字节
从机标志(从机地址)客户端生成
应答时复制该值

【注意】
【1】传输标志可理解为序列号,防止MODBUS TCP通信错位,例如后发生的响应先到了主机,而早发生的响应后到主机
【2】单元标志可理解为从机地址,此时已经不再重要

2.4 modbus tcp 和 TCP IP的关系
    modbus TCP可以理解为发生在TCP上的应用层协议,既然是TCP协议那么一个完整的MODBUS TCP报文必然包括TCP首部,IP首部和Ethernet首部。

    下面就通过uIP协议栈来实现modbus TCP

3.代码实现


3.1 侦听502端口


BOOL
xMBTCPPortInit( USHORT usTCPPort )
{
    BOOL bOkay = FALSE;
   
    USHORT usPort;
    if( usTCPPort == 0 )
    {
      usPort = MB_TCP_DEFAULT_PORT;
    }
    else
    {
      usPort = (USHORT)usTCPPort;
    }
   
    // 侦听端口 502端口
    uip_listen(HTONS(usPort));
   
    bOkay = TRUE;
    return bOkay;
}

    【代码说明】
    【1】uip_listen(HTONS(usPort)) 侦听502端口,注意大小端变化。

3.2 uIP循环处理——porttcp.c


void uip_modbus_appcall(void)
{
    if(uip_connected())
    {
      PRINTF("connected!\r\n");
    }
   
    if(uip_closed())
    {
      PRINTF("closed\r\n");
    }
   
    if(uip_newdata())
    {
      PRINTF("request!\r\n");
      // 获得modbus请求
      memcpy(ucTCPRequestFrame, uip_appdata, uip_len );
      ucTCPRequestLen = uip_len;
      // 向 modbus poll发送消息
      xMBPortEventPost( EV_FRAME_RECEIVED );
    }
   
    if(uip_poll())
    {
      if(bFrameSent)
      {
            bFrameSent = FALSE;
            // uIP发送Modbus应答数据包
            uip_send( ucTCPResponseFrame , ucTCPResponseLen );
      }
    }
}
    【代码说明】
    【1】uip_newdata()返回为True表示存在新的数据
    【2】复制uip_appdate中的数据到ucTCPRequestFrame,该变量为全局变量,通过该全部变量”中转“到modbus处理的缓冲区中。然后向modbus协议栈发送消息,消息内容为EV_FRAME_RECEIVED 。由于没有使用操作系统
    【3】如果处理完成则通过uip_send发送响应。
    【4】ucTCPRequestFrame和ucTCPResponseFrame均为全局数组,用于和modbus缓冲区交换数据。
static UCHAR ucTCPRequestFrame;
static USHORT ucTCPRequestLen;
static UCHAR ucTCPResponseFrame;
static USHORT ucTCPResponseLen;

3.3 modbus 接收处理


BOOL
xMBTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength )
{
    *ppucMBTCPFrame = &ucTCPRequestFrame;
    *usTCPLength = ucTCPRequestLen;
   
    /* Reset the buffer. */
    ucTCPRequestLen = 0;
    return TRUE;
}
    【代码说明】
    【1】** ppucMBTCPFrame为一个指向数据的指针,而*ppucMBTCPFrame可以指向一个数组,在这里可把ucTCPRequestFrame复制给该变量,配合usTCPLength,那么从uIP接收到的内容就”转移“到freemodbus中。

3.4 modbus 发送处理
BOOL
xMBTCPPortSendResponse( const UCHAR * pucMBTCPFrame, USHORT usTCPLength )
{
    memcpy( ucTCPResponseFrame , pucMBTCPFrame , usTCPLength);
    ucTCPResponseLen = usTCPLength;
   
    bFrameSent = TRUE; // 通过uip_poll发送数据
    return bFrameSent;
}
【代码说明】
【1】把传入的内容 pucMBTCPFrame复制给ucTCPResponseFrame,并设置bFrameSent为True,那么在下一次uip_poll时便会把响应发送会主机。

4.测试与分析
    【1】连接从机
    选择IP地址为192.168.1.15,端口号为502


图3 打开modbus tcp连接
    【2】尝试读出保持寄存器


图4 读取保持寄存器
    【3】抓包分析
    请使用ip.addr == 192.168.1.15 表达式过滤报文,其中192.168.1.100为PC机,此处为modbus 主机
    【简单分析】
    【1】115行为modbus主机请求,此时传输标志为25.
    【2】116行为modbus从机给出的TCP应答,TCP应答为TCP协议规定的内容,TCP应答中不包含modbus 响应
    【3】117行为modbus从机响应,此时传输标志依然为25.
    【4】118行为modbus主机 TCP应答,同16行。


图5 抓包分析

5.总结

6.参考资料
【基于EncEthernet的FreeModbus-TCP 在stm32上的移植与测试】
【simple modbus】


飞剑 发表于 2014-3-20 23:06:48

顶一下楼主。

HANGKONG15 发表于 2014-3-20 23:31:47

好东西必须支持{:handshake:}

lrzxc 发表于 2014-3-21 07:56:14

楼主,这么好帖,让大家都看到。

mainbp 发表于 2014-3-21 08:09:16

mark
最近在学这个
板凳学习

yu0405jie 发表于 2014-3-21 08:10:01

好东西,顶楼主

ibichao 发表于 2014-3-21 08:16:53

看起来很牛x,留个脚印先

fsmd@163.com 发表于 2014-3-25 09:58:28

好资料,最近也在学习Modbus-TCP的实现。

dz_xinyu 发表于 2014-3-25 14:50:04

好东西啊,学习!!!!

waterx3 发表于 2014-3-26 10:34:29

怎么区分主机的命令还是从机的响应?

fenglove 发表于 2014-3-27 14:07:31

谢谢楼主分享。

linlingpeng 发表于 2014-3-27 14:08:34

卧槽,又更新了,屌炸天了!

xukai871105 发表于 2014-3-28 14:07:37

waterx3 发表于 2014-3-26 10:34
怎么区分主机的命令还是从机的响应?

您的问题,我没有理解??

waterx3 发表于 2014-3-28 14:23:34

modbus发送和接收都带着功能号,怎么能知道数据帧是命令还是从机响应?

skyformat 发表于 2014-3-28 22:30:08

谢谢楼主无私分享。太牛了

305546594 发表于 2014-4-2 12:16:58

无私的楼主 感谢

randyzzy 发表于 2014-4-2 13:38:57

这个必须要顶!

worldsing 发表于 2014-4-3 16:11:54

好帖子{:smile:}

kingie2006 发表于 2014-4-3 18:56:38

不错,力作.......

Elex 发表于 2014-4-3 19:55:00

MODBUS差不多是最为简单的通讯协议了,格式固定,命令也就那么几个。觉得协议栈复杂完全可以自己写代码实现。
我当年就是自己手敲的代码写了MODBUS的TCP和RTU的接口协议,主要麻烦的是几百个寄存器的读写操作实现。

icemagicisme 发表于 2014-4-4 10:33:26

问一个问题,一个工程中 既要用到modbus tcp 也要用到 modbus rtu,可以实现吗?比如一个典型应用,rtu与hmi连接,tcp与pc连接,谢谢。

xukai871105 发表于 2014-4-4 13:51:40

icemagicisme 发表于 2014-4-4 10:33
问一个问题,一个工程中 既要用到modbus tcp 也要用到 modbus rtu,可以实现吗?比如一个典型应用,rtu与hm ...

如果使用STM32我看实现起来比较困难,但是使用linux的话实现起来非常简单。
可能刚开始熟悉linux需要些时间,但是过了这个阶段就好了!

如果你不嫌弃,看看这个

树莓派学习笔记——实现modbus RTU从机
MODBUS学习笔记——modbus tk modbus TCP主机实现

ziho2005 发表于 2014-4-5 10:20:14

价值好帖!

良马一号 发表于 2014-4-30 15:32:10

Lz看过你的帖子,我刚刚接触modbus,我想请教一下,modbus能不能在单片机之间传大量的数据(不是操作寄存器,io口什么的),怎么没看到传输数据的功能码??

hejiang177 发表于 2014-5-1 21:03:30

这个必须得顶

Zigbee2012 发表于 2014-5-2 02:11:13

先定了 再说。。。

xukai871105 发表于 2014-5-2 23:56:09

良马一号 发表于 2014-4-30 15:32
Lz看过你的帖子,我刚刚接触modbus,我想请教一下,modbus能不能在单片机之间传大量的数据(不是操作寄存器 ...

modbus不适合传输大数据量内容!如果需要传输大数据量内容,请参考其他协议。
如果是linux系统的话,FTP就可以了,简单方便容易实现。

dlmaowf 发表于 2014-5-3 08:35:12

收藏了   

peiyan 发表于 2014-5-3 10:25:53

谢谢分享,、、、、

larry.wong 发表于 2014-5-14 21:01:49

又看到楼主大作了,楼主的RTU还没看懂,TCP就来了!

xukai871105 发表于 2014-5-19 08:31:40

larry.wong 发表于 2014-5-14 21:01
又看到楼主大作了,楼主的RTU还没看懂,TCP就来了!

称不上大作,简单的一个例子!

liuyingqing139 发表于 2014-5-19 08:41:32

感谢楼主分享经验,

ddqq 发表于 2014-5-19 08:56:19

楼主威武,楼主好人

hejiang177 发表于 2014-5-21 13:49:01

收藏先,三克LZ

wangweihua 发表于 2014-5-21 15:48:58

非常感谢无私的分享

A644072458 发表于 2014-6-4 11:12:39

楼主,能不能贴一下,ModbuBus TCP 的源码,谢谢。

xukai871105 发表于 2014-6-11 12:44:05

A644072458 发表于 2014-6-4 11:12
楼主,能不能贴一下,ModbuBus TCP 的源码,谢谢。

请到Github上clone或者下载zip包!
这样的方式可能你没用过,不过慢慢会习惯的!

zhou.ui 发表于 2014-6-11 19:34:24

mark,正好在找这个东西。顶!

kaomantou 发表于 2014-6-12 09:31:10

mark freemodbus modbus TCP 学习笔记

yufanyufan77 发表于 2014-6-20 17:32:02

楼主什么时候能分享一下程序,期待中。。。

yzb1019 发表于 2014-6-21 10:31:30

感觉TCP/IP协议的什么东西都好难的样子

xukai871105 发表于 2014-6-26 19:52:38

yzb1019 发表于 2014-6-21 10:31
感觉TCP/IP协议的什么东西都好难的样子

网络非常好用也很有用,并且modbus tcp比modbus RTU简单。

slzm40 发表于 2014-7-7 17:20:18

报告版主,该文得置酷。

自从学习了楼主移植FreeModbus教程,现在自己学着移植到PIC的MCU上,替换掉自己写的MODBUS,再也不丢帧了。跟着也学习了源码的编程思路。用起来爽爽的

lucasphh 发表于 2014-7-7 21:10:22

占座留名,以备后用

Myheartisbroken 发表于 2014-7-31 16:15:40

请教,MODBUS TCP连接多从机的时候实时性如何,从机数量大于50?

xukai871105 发表于 2014-8-1 08:41:02

Myheartisbroken 发表于 2014-7-31 16:15
请教,MODBUS TCP连接多从机的时候实时性如何,从机数量大于50?

如果是uIP+STM32的话。同时接入50个从机,从我个人的认知范围来说是很难实现的。

我建议,linux系统,至少128M内存。保守些,一个从机占用2M 内存高,50个消耗100M,还有可怜的28M留给内核。

电子小生 发表于 2014-8-1 13:07:28

支持下楼主的好文

kevin_me 发表于 2014-8-7 15:00:11

请教楼主,我现在也要移植MODBUS TCP,看了一些文档,确定要使用到porttcp.c这个文件,但是下载的freemodbus代码包里面没有该文件。请问这是为何?

naiqiqnus 发表于 2014-8-7 15:27:35

顶{:smile:}{:smile:}{:smile:}

zhoust 发表于 2014-11-27 04:08:32

支持下楼主的好文!!!

jiming716 发表于 2014-11-30 06:29:25

楼主的MODBUS RTU程序,我在STM32和STC单片机上均移植成功了,最近在调试MODBUS TCP的移植,感谢楼主1

知行合一 发表于 2014-12-1 10:51:52

楼主好厉害,!!!

停靠点 发表于 2014-12-1 10:58:09

感谢分享!

优酷会员 发表于 2014-12-29 21:28:18

楼主好强大,有没有lwip modbus的哪,拜谢

chengsong 发表于 2015-2-6 13:48:35

感谢分享!

green-hand 发表于 2015-2-6 14:59:10

感谢楼主。

XIUQIN 发表于 2015-3-3 11:53:26

你好前辈!问个modbus RTU中保持寄存器的问题,当主机间隔一秒一次读取从机的保持寄存器地址0-9的10个数据时,当主机一来读取时而我这时只更新了前5个新数据,这时后面的5个还是旧的历史数据。而这10个数据是一个联合数据,必须整体判断执行的结果。我想了,从机要是关中断后再去一次刷新10个值也不可行,因为这时主机有可能正在读取数据,并读取了一部分。请问有没有好的办法保证数据的完整性?谢谢!

whm_WUHAN 发表于 2015-3-3 13:23:47

modules RTU还是很不错,现在看看TCP协议

xukai871105 发表于 2015-3-5 11:13:00

whm_WUHAN 发表于 2015-3-3 13:23
modules RTU还是很不错,现在看看TCP协议

我觉得modbus tcp更好用一点

zhan_li 发表于 2015-3-5 12:11:34

MARK   。。。

569350810 发表于 2015-6-27 17:30:46

Modbus的从机是TCP的服务器。STM32是工作在TCP服务器模式和Modbus的从机模式。

szszjdb 发表于 2015-12-9 15:25:27

本帖最后由 szszjdb 于 2015-12-9 15:37 编辑

xukai871105 发表于 2015-3-5 11:13
我觉得modbus tcp更好用一点

多谢楼主,GIT上的代码好像无法下载了,能否请楼主放到AMO上来?或者EMAI : 13603052469@139.com, 多谢!

am_shui9jing 发表于 2017-1-10 21:00:02

MARK,MODBUS-TCP

lhaoyue 发表于 2017-1-10 21:14:22

freemodbus modbus TCPmark

jacktau 发表于 2017-1-11 10:51:11

总结得非常好,收藏备用~~~~~~~~~~~~~~~

pdabug 发表于 2017-1-11 11:17:43

非常完整,lz用心了

ycwjl728 发表于 2017-1-11 14:42:29

Mark!最近在做tcp modbus,学习,谢谢楼主!

diyer_zhou 发表于 2017-1-11 20:27:41

MARK,MODBUS-TCP

YuQingLiang 发表于 2017-1-12 10:46:10

学习学习

hagong2008 发表于 2017-9-21 18:45:15

MARK嗯嗯 嗯嗯

newphj 发表于 2017-10-6 18:55:55

真是厉害,下过来学习

yinian 发表于 2022-7-27 22:50:39

谢谢,学习一下
最近研究arduino modbus

liang16888 发表于 2022-7-28 09:23:47

楼主强大 是否有试过用这个显示出Camera画面? 只显示一张图也行?
页: [1]
查看完整版本: freemodbus modbus TCP 学习笔记