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. QT Designer 的汉化

    Designer是很好用的设计器,通过 pip 安装PyQt5之后,一般都是英文的 所以给有需要的人带来汉化的包(这个是通过替换  translations 文件夹来实现的) translations ...

  2. docker-es

    镜像地址https://hub.docker.com/_/elasticsearch/ docker pull elasticsearch 这个版本是dockerhub最新,官方最新版:https:/ ...

  3. Mac下webpack安装

    最近开始接触构建工具webpack,公司电脑是 windows,而我自己的呢是mac.本来以为在自己电脑安装很简单,但是出了点问题,所以写出来分享下. 这里用npm的方式安装,首先你要安装node.j ...

  4. postgresql recovery.conf改变需要重启吗

    之前在研究pgpoll时,发现trigger_file参数指定的文件存在后,会自动将standby节点提升为可写节点.不需要手动执行pg_ctl promote,但是这个时间一般有延迟,因为进程会定期 ...

  5. Mysql中文汉字转拼音的实现(每个汉字转换全拼)

    -- 创建汉字拼音对照临时表 CREATE TABLE IF NOT EXISTS `t_base_pinyin` ( `pin_yin_` varchar(255) CHARACTER SET gb ...

  6. 在ubuntu14.4里编译UBOOT出错

    出错信息如下: OBJCOPY examples/standalone/hello_world.bin  LDS     u-boot.lds  LD      u-boot./scripts/dtc ...

  7. mac brew安装使用卸载

    (一)安装 1.浏览器打开brew.sh,进入homebrew主页.找到install homebrew 的命令: /usr/bin/ruby -e "$(curl -fsSL https: ...

  8. POJ 1265 Area (pick定理)

    题目大意:已知机器人行走步数及每一步的坐标变化量,求机器人所走路径围成的多边形的面积.多边形边上和内部的点的数量. 思路:叉积求面积,pick定理求点. pick定理:面积=内部点数+边上点数/2-1 ...

  9. 时间由yyyy-MM-dd HH:mm:ss专为yyyy-MM-dd

    (1)类用date 注意:如果用string会报错  页面无法使用string(...): (2)数据库表 (3)页面

  10. java如何获取当前时间,精确到毫秒

    import java.text.SimpleDateFormat; import java.util.Date; import java.util.Calendar; //func1 Calenda ...