private:Ui::Widget *ui;QTcpServer *tcpServer;QTcpSocket *clientConnection ;QByteArray sendBuf;QByteArray receBuf;qint64 bytesRead ;//接收到的字节数
public:/*****for modbus function*******/void checkComm0Modbus(void);void readCoil(void) ;void forceSingleCoil(void);void readRegisters();void presetSingleRegister(void);uint16 getCoilVal(uint16 addr,uint16 *tempData);uint16 setCoilVal(uint16 addr,uint16 tempData);uint16 getRegisterVal(uint16 addr,uint16 *tempData);uint16 setRegisterVal(uint16 addr,uint16 tempData)    ;/******************************/
Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);tcpServer = new QTcpServer(this);//if(!tcpServer->listen(QHostAddress::LocalHost,6666))if(!tcpServer->listen(QHostAddress("192.168.1.230"),502)){  //监听本地主机的6666端口,如果出错就输出错误信息,并关闭qDebug() << tcpServer->errorString();close();}connect(tcpServer,SIGNAL(newConnection()),this,SLOT(acceptConnection()));
}Widget::~Widget()
{delete ui;
}
void Widget::acceptConnection()//response the sever's connection request--
{clientConnection = tcpServer->nextPendingConnection();//我们获取已经建立的连接的子套接字connect(clientConnection,SIGNAL(disconnected()),clientConnection,SLOT(deleteLater()));connect(clientConnection,SIGNAL(readyRead()),this,SLOT(readData()));connect(clientConnection,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));ui->statusLabel->setText("already constuct clientConnection");}void Widget::readData(void)//when the readyRead signal is emit,this slots function is excuted
{bytesRead=clientConnection->bytesAvailable();if(bytesRead>=8){DEBUG_BYSONG<<bytesRead;receBuf = clientConnection->readAll();DEBUG_BYSONG<<receBuf.toHex().toUpper();checkComm0Modbus();//to parse mbclientConnection->write(sendBuf);bytesRead=0;}
}

说明:
1.micro2440监听本地502端口。modbus之于502就像ftp之于21一样。当有客户端连接请求时激发newConnection()信号从而执行slots acceptConnection()。
2.在acceptConnection()里面应答连接,并建立readyRead()信号与 readData()槽函数的连接。readyRead信号在端口有数据到达时发射。
3.在readData ()函数里面读取数据(一个modbus frame)。调用checkComm0Modbus()分析此帧。
4.modbus tcp的帧结构相比串口modbus rtu的前面多了6个字节modbus协议头即mbap header,后面少了2个字节的crc,中间部分除了第一字节的node其余字节完全相同,都遵守modbus帧规范。

/***************************************************implement modbus function**************************/void Widget::checkComm0Modbus(void)
{uint16 tempData=0;sendBuf.resize(0);sendBuf[0]=receBuf[0];sendBuf[1]=receBuf[1];sendBuf[2]=receBuf[2];sendBuf[3]=receBuf[3];//receBuf[0];////receBuf[1];////receBuf[2];//00//receBuf[3];//00//receBuf[4];//length mb hi byte//receBuf[5];//length mb lo byte  6//receBuf[6];//ff//receBuf[7];//function code//receBuf[8];//address hi byte//receBuf[9];//address lo byte//receBuf[10];//length hi byte//receBuf[11];//length lo byte//sendBuf[0];//**//sendBuf[1];//**//sendBuf[2];//**//sendBuf[3];//**//sendBuf[4];//length mb hi byte//sendBuf[5];//length mb lo byte  11//sendBuf[6];//**//sendBuf[7];//**//sendBuf[8];//length below  8//sendBuf[9];//data1 hi byte//sendBuf[10];//data1 lo byte//sendBuf[11];//data2 hi byte//sendBuf[12];//data2 lo byte//sendBuf[13];//data3 hi byte//sendBuf[14];//data3 lo byte//sendBuf[15];//data4 hi byte//sendBuf[16];//data4 lo byteif(bytesRead >= 12){if(receBuf[0]==receBuf[0]){//if(crcData == receBuf[7]+(receBuf[6]<<8)){if(receBuf[7] == (char)1){readCoil();}else if(receBuf[7] == (char)2){readCoil();}else if(receBuf[7] == (char)3){readRegisters();}else if(receBuf[7] == (char)4){readRegisters();}else if(receBuf[7] == (char)5){forceSingleCoil();}else if(receBuf[7] == (char)6){presetSingleRegister();}}}}}void Widget::readCoil(void)
{DEBUG_BYSONG<<"readCoil";
/*
10 00 00 00 00 06 ff 02 00 00 00 03    //客户端(pc)请求帧。
10 00 00 00 00 04 FF 02 01 01          //服务器端(micro2440)回复帧10 00 00 00 00 06 ff 02 00 00 00 03
10 00 00 00 00 06 mbap header
ff 地址
02 功能号
00 00 start address
00 03 length10 00 00 00 00 04 FF 02 01 01
10 00 00 00 00 04 mbap header
ff 地址
02 功能号
01 length of the follows
01 data即0000 0001b.所以adress0:1  address1:0  address2:0
*/uint8 addr;uint8 tempAddr;uint16 byteCount;uint16 bitCount;uint16 crcData;uint8 position;uint8 i,k;//uint8  result;uint16 tempData;uint8 temp;uint8  exit = 0;addr = (receBuf[2+6]<<8) + receBuf[3+6];tempAddr = addr & 0xff;bitCount = (receBuf[4+6]<<8) + receBuf[5+6];bitCount &= 0xff;byteCount = bitCount / 8;if(bitCount%8 != 0)byteCount++;for(k=0;k<byteCount;k++){position = k + 3 + 6;sendBuf[position] = 0;temp=0;for(i=0;i<8;i++){getCoilVal(tempAddr,&tempData);temp|=tempData << i;sendBuf[position] =temp;tempAddr++;if(tempAddr >= addr+bitCount){exit = 1;break;}}if(exit == 1)break;}sendBuf[4]=(byteCount+(char)3)>>8;//length mb hi bytesendBuf[5]=(byteCount+(char)3) & 0xff;//length mb lo byte  11sendBuf[0+6] = receBuf[6];sendBuf[1+6] = receBuf[7];sendBuf[2+6] = byteCount;}//void readCoil(void)void Widget::readRegisters(void)
{
/*
00 06 00 00 00 06 ff 03 00 00 00 03               //客户端(pc)请求帧。
00 06 00 00 00 09 FF 03 06 00 00 00 01 00 02      //服务器端(micro2440)回复帧其中
00 06 00 00 00 06 ff 03 00 00 00 03
前6字节是mbap header:
00 事务处理标识符hi
06 事务处理标识符lo。一般主机每发送一个modbus帧,事务处理标识符+1
00 00 modbus协议标识符 必须为 00 00
00 信文长度hi
06 信文长度lo。指后续的字节数。
后面的字节属于正文
ff modbus 节点地址,基于tcp/ip的modbus此地址无用。因为ip+port就可以唯一确定是哪个服务器
03 function code
00 start address hi
00 start address lo
00 length hi
03 length lo00 06 00 00 00 09 FF 03 06 00 00 00 01 00 02
前6字节是mbap header:
00 06 00 00 前4字节和客户端发来的一样。
00 信文长度hi
09 信文长度lo。指后续的字节数。
后面的字节属于正文
ff modbus 节点地址。和客户端发来的一样。
03 function code。和客户端发来的一样。
06 length of the follows
00 00 data1
00 01 data2
00 02 data3
*/DEBUG_BYSONG<<"readRegisters";uint8 addr;uint8 tempAddr;uint16 crcData;uint16 readCount;uint16 byteCount;uint16 i;uint16 tempData = 0;addr = (receBuf[2+6]<<8) + receBuf[3+6];tempAddr = addr & 0xff;readCount = (receBuf[4+6]<<8) + receBuf[5+6];if (readCount>166) readCount=166;/constraint the quantitiesbyteCount = readCount * 2;for(i=0;i<byteCount;i+=2,tempAddr++){getRegisterVal(tempAddr,&tempData);sendBuf[i+3+6] = tempData >> 8;sendBuf[i+4+6] = tempData & 0xff;}sendBuf[4]=(byteCount+(char)3)>>8;//length mb hi bytesendBuf[5]=(byteCount+(char)3) & 0xff;//length mb lo byte  11sendBuf[0+6] = receBuf[6];sendBuf[1+6] = receBuf[7];sendBuf[2+6] = byteCount;//  sendBuf[byteCount+6]='\0';}//void readRegisters(void)void Widget::forceSingleCoil(void)
{
/*
00 06 00 00 00 06 ff 05 00 03 FF 00 //client send mb frame。server response with the same
00 06 00 00 00 06 smap header
ff modbus node address.useless
05 function code
00 03 start address
ff 00 stand for 1。if clr 0,will be 00 00*/uint8 addr;uint8 tempAddr;uint16 tempData=0xabcd;uint8  onOff;uint8 i;addr = (receBuf[2+6]<<8) + receBuf[3+6];tempAddr = addr & 0xff;//°????è????±????·onOff = (receBuf[4+6]<<8) + receBuf[5+6];if(onOff == 0xff00){  //?è??ONtempData = 1;}else if(onOff == 0x0000){  //?è??OFFtempData = 0;}if (tempData==1 || tempData==0){setCoilVal(tempAddr,tempData);for(i=0;i<bytesRead;i++){sendBuf[i] = receBuf[i];}}}//void forceSingleCoil(void)void Widget::presetSingleRegister(void)
{
/*
00 06 00 00 00 06 ff 06 00 03 FF 00 //client send mb frame。server response with the same
00 06 00 00 00 06 smap header
ff modbus node address.useless
06 function code
00 03 start address
12 66 the data to write into the address above
*/uint8 addr;uint8 tempAddr;uint16 crcData;uint16 tempData;int i;addr = (receBuf[2+6]<<8) + receBuf[3+6];tempAddr = addr & 0xff;//°????è????±????·tempData = (receBuf[4+6]<<8) + receBuf[5+6];setRegisterVal(tempAddr,tempData);for(i=0;i<bytesRead;i++){sendBuf[i] = receBuf[i];}}

5.this is  the most  simple demo which implements the modbus tcp protocol.还需要根据mosbus规范完善异常情况的控制。同一时间仅支持一个客户连接请求。另一客户请求时,会把请一个踢掉,而服务最新的这个客户,可以使用多线程完善一下,使每个线程服务一个客户连接。。

6.使用UartAssist测试
function code 01

function code 03

7.使用modscan32测试,

8.使用dasserver测试
安装dasmbtcp,添加主题名 tcp2

在intouch中添加访问名access_tcp2

建立io整型点,test1.注意item是400003.不是40003.


可以看到在为地址400003采集数据时,dasmbtcp发出的请求帧是 00 B3 00 00 00 06 FF 03 00 02 00 01 。最后6个字节中,03功能号。符合mb规范。

当更改这个变量例如改成9,如图,的时候

dasmbtcp会发出请求帧,如下图,

即01 42 00 00 00 09 FF 10 00 00 02 00 01 02 00 09 .最后9个字节中,0x10功能号。00 02 starting address。00 01 寄存器个数。02 后续字节数2个。00 09写入值。
16 (10 Hex) Preset Multiple Registers
下面是0x10号功能请求帧的格式

服务器需要响应帧类似如下:

再实验一个地址000006


很明显,function code 01。

当我们试图去置test2为off,如图,的时候,

dasmbtcp会发出请求帧,如下图,

是功能号0x0F
15 (0F Hex) Force Multiple Coils

由此确定:开发一个在支持wonderware dasmb 读和写的modbus设备,需要该设备实现01 02 03 04 0F 10功能号。而05 06置单线圈和单寄存器功能可以不要。因为wonderware dasmb置线圈和寄存器都是使用的0F 和10功能号,没有用到05 06。
10不必开放,在intouch里面修改4xxxx的变量时(function code 03),dasmb 自动发出10请求帧。
0F不必开放,在intouch里面修改0xxxx的变量时(function code 01),dasmb 自动发出0F请求帧。

本例没实现0x10号功能,所以改不了。按照mb规范加上这个功能很简单的,自己动动脑子啦。
http://download.csdn.net/detail/songqqnew/3863154

转载于:https://www.cnblogs.com/-song/archive/2011/11/27/3331916.html

modbus-tcp qt4-socket ---------micro2440 as device相关推荐

  1. tcp转串口_PROFIBUS DP与Modbus/TCP网络转换操作指南

    >>PROFIBUS DP转Modbus/TCP网关操作指南 摘要: 本文以NT100-RE-DP网关为例,实现Modbus/TCP Client与PROFIBUS DP设备间的通讯,从而 ...

  2. modbus tcp 入门详解

    Modbus tcp 格式说明 通讯机制 附C#测试工具用于学习,测试 前言: 之前的博客介绍了如何用C#来读写modbus tcp服务器的数据,文章:http://www.cnblogs.com/d ...

  3. 通讯接口应用笔记3:使用W5500实现Modbus TCP服务器

      前面我们设计实现了W5500的驱动程序,也讲解了驱动的使用方式.在最近一次的项目应用中,正好有一个使用W5500实现TCP通讯的需求,所以我们就使用该驱动程序轻松实现.这一篇中我们就来说一说基于我 ...

  4. 基于STM32和W5500的Modbus TCP通讯

     在最近的一个项目中需要实现Modbus TCP通讯,而选用的硬件平台则是STM32F103和W5500,软件平台则选用IAR EWAR6.4来实现. 1.移植前的准备工作 为了实现Modbus ...

  5. 【.NET6+Modbus】Modbus TCP协议解析、仿真环境以及基于.NET实现基础通信

    接下来的内容,我会以从头开发一个简单的基于modbus tcp通信的案例,来实现一个基础的通信功能. 有关环境: 开发环境:VS 2022企业版 运行环境:Win 10 专业版 .NET 环境版本:. ...

  6. 八路DI八路DO,开关量远程IO模块,Modbus TCP数据采集模块 WJ90

    产品特点: ● 八路开关量输入,八路开关量输出 ●  DI状态变化自动发送状态数据,可以捕获脉冲 ● 采用Socket自由协议编程简单.轻松应用 ● 开关量毫秒级响应速度适应多种场合 ● 内置网页功能 ...

  7. 16路4-20mA转Modbus TCP网络数据采集模块 WJ89

    产品特点: ● 16路4-20mA输入Modbus TCP 通讯协议 ● 信号输入可以选型0-5V或0-10V ● 内置网页功能,可以通过网页查询数据 ● 支持socket通讯使用字符通信协议 ● 4 ...

  8. STM32cubemx_W5500_TCP和Modbus/TCP

    STM32cubemx_W5500_TCP和Modbus/TCP 以STM32f103zet6开发板为平台 使用STM32cubemx进行一些串口,spi等接口的初始化. 使用的是野火的w5500模块 ...

  9. S7-1200PLC Modbus TCP通信

    硬件:cpu 1214C 目的:测试Modbus TCP通信 软件:Portal V14SP1 1.硬件组态 插入两台cpu,并分配IP地址 PLC_1:192.168.0.20 PLC_2:192. ...

最新文章

  1. 2022-2028年中国粘胶纤维市场投资分析及前景预测报告
  2. 使用DataReader、DataSet、DataAdapter和DataView
  3. 数据库更新记录,但程序查不到新记录问题
  4. 虚拟化技术的概述及使用
  5. 再提“鸿蒙”,任正非说这是为物联网而生;硅谷公司年薪报告出炉,谷歌年薪居榜首;苹果CEO库克接班人浮出水面,苹果高层或大换血?...
  6. element ui select设置不显示不存在的项_appium—等待时间设置方法
  7. 实战:基于RabbitMQ的TTL以及死信队列,实现延迟付款,手动补偿案例
  8. 国内最大“十元店”上市!市值或超百亿美元,腾讯是股东之一
  9. OOP之C#设计及其UML(反向工程)
  10. 如何使用bat批处理命令打开WSL
  11. 分治算法实现经典归并排序java实现
  12. jade选峰之后怎么去掉_教程丨用Jade软件处理XRD数据的步骤
  13. 计算机CAD作文,CAD:电脑系统字体和CAD字体的区别
  14. ERP和进销存系统区别是什么
  15. 苹果屏蔽更新描述文件_iOS屏蔽更新描述文件以及超级详细安装方法分享
  16. 指数退避和AIMD为什么都青睐数字2
  17. eregi php7.0,关于php:已弃用:函数eregi()已弃用
  18. CSDN日报20170224——《程序员该用哪种姿势来理财》
  19. android 即时通讯技术,基于Android即时通讯系统的设计与实现
  20. centos7编写shell批处理文件和执行方法

热门文章

  1. UPLOOKING_APUE
  2. 【插件】史上最强编辑器通用ctags插件OpenCTags使用指南v1.2--开发者必备
  3. 本次案例:对于sun 服务器的故障排查
  4. Android HandlerThread 源码分析
  5. ORACLE会话数、连接数配置
  6. Linux中硬盘转速查看
  7. Java RMI远程方法调用详解
  8. (一)Mac OS安装PostgreSQL数据库
  9. JVM学习笔记之-运行时数据区概述及线程概述,程序计数器(PC寄存器),虚拟机栈(栈,局部变量表,操作数栈,动态连接,方法调用,方法返回地址等),本地方法接口,本地方法栈
  10. Asp.Net 数据分页