1.前言
    使用modbus有些时间了,期间使用过modbus RTU也使用过modbus TCP,通过博文和大家分享一些MODBUS TCP的东西。在嵌入式中实现TCP就需要借助一个以太网协议栈,在这里我选择最简单的uIP协议栈。uIP协议栈简单易用方便上手,相比于LwIP无论是移植还是使用难度都低些,这样就可以把更多的精力花在modbus tcp协议本身而不必花大量的时间研究以太网协议栈。modbus协议栈为freemodbus
 
【其他有用的博文】
    【1】uIP学习笔记
 
【工程代码】
    示例代码托管于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端口
  1. BOOL
  2. xMBTCPPortInit( USHORT usTCPPort )
  3. {
  4. BOOL bOkay = FALSE;
  5. USHORT usPort;
  6. if( usTCPPort == 0 )
  7. {
  8. usPort = MB_TCP_DEFAULT_PORT;
  9. }
  10. else
  11. {
  12. usPort = (USHORT)usTCPPort;
  13. }
  14. // 侦听端口 502端口
  15. uip_listen(HTONS(usPort));
  16. bOkay = TRUE;
  17. return bOkay;
  18. }
    【代码说明】
    【1】uip_listen(HTONS(usPort)) 侦听502端口,注意大小端变化。
 
3.2 uIP循环处理——porttcp.c
  1. void uip_modbus_appcall(void)
  2. {
  3. if(uip_connected())
  4. {
  5. PRINTF("connected!\r\n");
  6. }
  7. if(uip_closed())
  8. {
  9. PRINTF("closed\r\n");
  10. }
  11. if(uip_newdata())
  12. {
  13. PRINTF("request!\r\n");
  14. // 获得modbus请求
  15. memcpy(ucTCPRequestFrame, uip_appdata, uip_len );
  16. ucTCPRequestLen = uip_len;
  17. // 向 modbus poll发送消息
  18. xMBPortEventPost( EV_FRAME_RECEIVED );
  19. }
  20. if(uip_poll())
  21. {
  22. if(bFrameSent)
  23. {
  24. bFrameSent = FALSE;
  25. // uIP发送Modbus应答数据包
  26. uip_send( ucTCPResponseFrame , ucTCPResponseLen );
  27. }
  28. }
  29. }
    【代码说明】
    【1】uip_newdata()返回为True表示存在新的数据
    【2】复制uip_appdate中的数据到ucTCPRequestFrame,该变量为全局变量,通过该全部变量”中转“到modbus处理的缓冲区中。然后向modbus协议栈发送消息,消息内容为EV_FRAME_RECEIVED 。由于没有使用操作系统
    【3】如果处理完成则通过uip_send发送响应。
    【4】ucTCPRequestFrame和ucTCPResponseFrame均为全局数组,用于和modbus缓冲区交换数据。
static UCHAR ucTCPRequestFrame[MB_TCP_BUF_SIZE];
static USHORT ucTCPRequestLen;
static UCHAR ucTCPResponseFrame[MB_TCP_BUF_SIZE];
static USHORT ucTCPResponseLen;
 
3.3 modbus 接收处理
  1. BOOL
  2. xMBTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength )
  3. {
  4. *ppucMBTCPFrame = &ucTCPRequestFrame[0];
  5. *usTCPLength = ucTCPRequestLen;
  6. /* Reset the buffer. */
  7. ucTCPRequestLen = 0;
  8. return TRUE;
  9. }
    【代码说明】
    【1】** ppucMBTCPFrame为一个指向数据的指针,而*ppucMBTCPFrame可以指向一个数组,在这里可把ucTCPRequestFrame复制给该变量,配合usTCPLength,那么从uIP接收到的内容就”转移“到freemodbus中。
 
3.4 modbus 发送处理
  1. BOOL
  2. xMBTCPPortSendResponse( const UCHAR * pucMBTCPFrame, USHORT usTCPLength )
  3. {
  4. memcpy( ucTCPResponseFrame , pucMBTCPFrame , usTCPLength);
  5. ucTCPResponseLen = usTCPLength;
  6. bFrameSent = TRUE; // 通过uip_poll发送数据
  7. return bFrameSent;
  8. }
【代码说明】
【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 抓包分析
转摘:http://blog.csdn.net/xukai871105/article/details/21652287

freemodbus modbus TCP 学习笔记的更多相关文章

  1. 毕向东tcp学习笔记1

    项目功能: 实现一次发送和接收,服务器接收客户端发送的内容并打印出来 用最通俗的语言讲解下,上图中大椭圆是服务器,A.C是客户端,当客户端和服务器通过socket建立连接后 1.两者之间形成一个通道, ...

  2. [原创]Modbus协议学习笔记

    一.参考资料 1.老罗传奇的2篇博文,写的不错,通俗易懂.链接地址为:http://www.cnblogs.com/luomingui/tag/Modbus/ 2.阿莫论坛精华资料:http://ww ...

  3. Modbus协议学习笔记

    之前也有写过基于 Modbus 通讯协议的控制远程监控程序,但是由于当时时间赶.人手少(软硬件前后台都是在下一人

  4. TCP学习笔记

    TCP/IP 协议分层模型 TCP/IP 协议族按层次分别分为以下 4 层:应用层.传输层.网络层和数据链路层.层次化之后,每个层级只需要考虑自己的任务就可以了,不再需要弄清其他层级的功能了. TCP ...

  5. EasyARM i.mx287学习笔记——通过modbus tcp控制GPIO

    0 前言     本文使用freemodbus协议栈,在EasyARM i.mx287上实现了modbus tcp从机. 在该从机中定义了线圈寄存器.当中线圈寄存器地址较低的4位和EasyARM的P2 ...

  6. uIP学习笔记

    uIP学习笔记 从零开始使用uIP freemodbus modbus TCP 学习笔记

  7. C#ModBus Tcp的学习及Master的实现

    Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式. 所以这也是我们工控领域软件开发的所必懂的通讯协议,我也是初次学习,先贴上我的学习笔记 一 ...

  8. TCP/IP详解学习笔记

    TCP/IP详解学习笔记(1)-基本概念 TCP/IP详解学习笔记(2)-数据链路层 TCP/IP详解学习笔记(3)-IP协议,ARP协议,RARP协议 TCP/IP详解学习笔记(4)-ICMP协议, ...

  9. TCP/IP协议学习笔记

    计算机网络基础知识复习汇总:计算机网络基础知识复习 HTTP协议的解析:剖析 HTTP 协议 一个系列的解析文章: TCP/IP详解学习笔记(1)-- 概述 TCP/IP详解学习笔记(2)-- 数据链 ...

随机推荐

  1. 在一个Activity中启动另一个Activity

    一.新建一个空的工程 二.添加一个Activity并命名为BAty 三.在activity_main.xml中添加一个按钮,设置id号为btnStartB <Button android:lay ...

  2. 有了Docker的程序猿们就能开启“上帝视角”?

    现在,如果有程序猿说不知道Docker,这将是难以想象的. 百科是这样描述Docker的."Docker是dotCloud开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植 ...

  3. 初识django框架

    django框架 1.框架介绍 根据第一部分内容介绍,我们可以总结出一个web框架应该包含如下三部分:a.sockect服务.b.根据不同的url调用不同函数(包含逻辑).c.返回内容(模板渲染).常 ...

  4. 【MFC】断言(ASSERT)的用法

    摘自:Moondark  http://www.cnblogs.com/moondark/archive/2012/03/12/2392315.html 断言(ASSERT)的用法   我一直以为as ...

  5. phpcms V9二级目录下分页路径不正确问题的彻底解决方法

    在用phpcms V9做二次开发的时候,我们有时候会把一个栏目生成到根目录下,而且这个栏目又有子栏目,我们生成静态的时候分页会出现问题,就是分页的路径的地址错误.有一种解决方法就是,把这个栏目生成动态 ...

  6. C++中继承关系中的同名隐藏和对策

    在C++及其面向对象的理论中,有这样的场景:一个类继承自另外一个类,如果这两个类都有一个函数名和参数及其返回值一样的成员函数,那么子类的函数会自动将父类对应的函数隐藏.即同名隐藏.在有时的开发过程中, ...

  7. NOIP模拟题 序列

    题目大意 给定长为$n$的序列$A$,定义长为$k$的区间中位数为从小到大排完序后第$\lfloor\frac{k}{2}\rfloor$个数的大小. 每次询问给定$l_1,r_1,l_2,r_2$有 ...

  8. sapconnector.dll download

    Sapnoc30Demo_Yan.rar Sap30Server.rar SAPNCO_Sample_Code.zip sapcon3.0_X64.rar DbEntry.Net.4.1.Setup. ...

  9. 【JVM】JVM参数说明和分析

    不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略, 调整JVM.GC的参数,可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Jav ...

  10. WPF 自定义BarChartControl(可左右滑动的柱状图)(转)

    自定义可左右滑动.拖拽滑动的平面柱状图 在做这种样式控件之前,可先浏览我之前预研的控件: A.自定义左右滑动ScrollViewer(可拖动滑动) B.自定义Bar柱状图 OK,现在说下控件具体设计过 ...