首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Modbus TCP和MATLAB

Modbus TCP和MATLAB
EN

Stack Overflow用户
提问于 2014-01-28 20:34:17
回答 2查看 4.2K关注 0票数 1

我有一个MATLAB代码:

代码语言:javascript
复制
function [s] = serialstart(opt) 
% Function for initializing a serial interface in matlab for interfacing 

% Functions using the serial port must be passed the serial port object 
% s in order for the serial port to be accessible.   

port = 502;   

s = tcpip('192.168.2.177',port);   
%?????   
set(s, 'InputBufferSize', 3000000); 

% Initialize serial port on specified com port 
  date_addr   = 40001; 
date_num=1; 
 date_addr_high = floor(date_addr/100);   
date_addr_low = mod(date_addr,100);   
date_num_high = floor(date_num/100);   
date_num_low = mod(date_num,100); 
%Open serial connection 
fopen(s); 

% Specify Terminator 
s.terminator='CR/LF'; 

fwrite(s,0,'char')                      %Transactio identifier        0x00   
fwrite(s,0,'char')                      %  Transactio identifier        0x00   
fwrite(s,0,'char')                      %    Protokol identifier      0x00   
fwrite(s,0,'char')                      %    Protokol identifier        0x00   
fwrite(s,0,'char')                      %     Data Bytes  0x00   
fwrite(s,1,'char')                      %         Data Bytes      0x06   
fwrite(s,255,'char')                     %     unit identifier    0xff   
fwrite(s,3,'uint8')                       %  Function           0x03   
fwrite(s,date_addr_high,'uint8')         %Register High Byte   
fwrite(s,date_addr_low,'uint8')            %Register Low Byte 
fwrite(s,date_num_high,'uint8')           %How many Register Low Byte 
fwrite(s,date_num_low,'uint8')     %How many Register High Byte 

out = fread(s,1,'char');                 

fclose(s); 

但我得到了以下答复:

警告:未成功读取:指定的数据量在超时期间内未返回。

下面是TCPIP对象的设置:

代码语言:javascript
复制
TCPIP Object : TCPIP-192.168.2.177 

Communication Settings 
RemotePort: 502 
RemoteHost: 192.168.2.177 
Terminator: 'CR/LF' 
NetworkRole: client 

Communication State 
Status: closed 
RecordStatus: off 

Read/Write State 
TransferStatus: idle 
BytesAvailable: 0 
ValuesReceived: 0 
ValuesSent: 12

连接是成功的,但我没有收到任何数据。我不知道怎么接受约会。

编辑:

我在结尾加了这个:

代码语言:javascript
复制
while ~s.BytesAvailable
end
s.BytesAvailable
res=fread(s,s.BytesAvailable)                 
fclose(s);

现在我没有得到任何回应。

EN

回答 2

Stack Overflow用户

发布于 2016-04-19 13:55:30

我知道这是一个旧的帖子,所以我不愿意撞它,但是我让Modbus TCP与Matlab一起工作,这是我尝试让它工作时遇到的帖子之一,所以我想在这里发布一个关于它的答案。

首先,我要说,这是通过Matlab的this Toolbox完成的,因为这是tcpip()命令所必需的。稍后,我将在没有工具箱的情况下努力使它工作,因为只为Modbus TCP获取整个工具箱是过分的,但为了快速开发的目的,工具箱的试用版已经足够让您通过一段时间了。

因此,首先配置端口:

代码语言:javascript
复制
IPADDR='192.168.0.1';
PORT=502;
tcpip_pipe=tcpip(IPADDR, PORT);
set(tcpip_pipe, 'InputBufferSize', 512); 
tcpip_pipe.ByteOrder='bigEndian';

然后,打开港口:

代码语言:javascript
复制
try 
    if ~strcmp(tcpip_pipe.Status,'open') 
        fopen(tcpip_pipe); 
    end
    disp('TCP/IP Open'); 
catch err 
    disp('Error: Can''t open TCP/IP');
    return;
end

现在,我发现起作用的是准备好整个消息,然后立即写完整个消息。我认为这很有帮助,因为您在上面用te .ByteOrder指定了endianness,所以您不需要真正担心它是如何设置的,或者您是否按照正确的顺序编写消息,等等。

现在,详细介绍如何构造Modbus TCP消息:

  1. 事务ID --这是一个2字节的字段,可以是任意数字。通常,每次发送消息时,都会将此值增加1。您所发送的设备将在响应时将此数字返回给您,这样您就可以确定您正在解析特定请求的数据。如果响应上的事务ID与您发送的不匹配,则应该丢弃数据。
  2. 协议--这是一个2字节的字段,应该全部为零以指示Modbus .相当直截了当。
  3. 字节保持--这是一个2字节的字段,它声明消息中仍然保留了多少字节。只要把所有的字节加起来,这就是这里的数字。
  4. 从ID -这是一个1字节的字段.起初,我发现这个值有点让人困惑,但是请考虑一下:您使用的是Modbus TCP --您已经有了到从服务器的直接连接,因为您正在连接到上面指定的IP地址。从ID在这里的目的是,如果您正在使用Modbus TCP-RTU“路由器”,您的消息将在RTU网络上重新广播。在这种情况下,您试图在RTU网络上指定路由器后面设备的地址。如果您试图通信的设备与您指定IP地址的设备相同,则不需要使用“奴隶ID”。如果不使用该设备,则应将其设置为255。所以,tl;dr -如果你没有用Modbus做一些复杂的事情,就把255作为这个值。
  5. 函数ID -这是一个1字节的字段.这是一个对应于指示设备如何执行的特定功能代码的数字。在我的例子中,我想要做的就是读取寄存器,所以我的函数ID每次都是4。
  6. Data --这可能是您的设备配置要做的任何事情,但是有几种“默认”情况,我将解释,因为它们应该是相当通用的。通常,当您向设备(从)发送消息时,数据将是两个2字节值,其中第一个2字节值是特定寄存器的地址,第二个2字节值是要读取的寄存器数量或要写入该寄存器的值。

那么,让我们来举一个例子。我希望事务代码为3(同样,我选择的任意数字,并在每次传输中递增,以使我能够匹配对特定传输的响应)。我希望函数代码是4(读寄存器),我想从寄存器0开始,我想读取12个寄存器。对于记录,一个寄存器通常是2个字节,所以这意味着我想从寄存器0开始,准备24个字节的信息。

该消息如下所示:

代码语言:javascript
复制
message = [...
    %*** TRANSACTION ID ***%
    uint8(0); ... % 
    uint8(3); ... % Two byte transaction ID
    %*** PROTOCOL ***%
    uint8(0); ... % 
    uint8(0); ... % Two byte protocol ID - all zeros means Modbus TCP
    %*** BYTES REMAINING ***%
    uint8(0); ... % 
    uint8(6); ... % Two byte number of bytes for everything after this
    %*** SLAVE ID ***%
    uint8(255); ... % Slave ID - use if end device is after a modbus tcp/rtu router, otherwise use 255
    %*** FUNCTION ID ***%
    uint8(4); ... % 4 - read input registers
    %*** DATA ***%
    %***** Starting Register *****%
    uint8(0); ... % 
    uint8(0); ... % Two byte number that gives the starting register to read
    %***** Number of Registers to Read *****%
    uint8(0); ... %
    uint8(12)];   % Two byte number that gives how many registers to read

现在,将此消息写入设备:

代码语言:javascript
复制
fwrite(tcpip_pipe, message,'int8');

然后,等待回复:

代码语言:javascript
复制
while ~tcpip_pipe.BytesAvailable,end

然后读取返回的数据:

代码语言:javascript
复制
response = fread(tcpip_pipe,tcpip_pipe.BytesAvailable);

头信息应该与预期的一样。同样,如果事务ID与您发送的不匹配,则应该丢弃该消息。函数代码应该与您发送的代码相同。如果不是,这可能是一个错误- 错误函数码与您发送的内容相同,加上128个。因此,在我的示例中,我希望读取输入寄存器(函数代码4),如果有错误(比如我的消息格式不正确,请指定无效的寄存器号,等等)。然后,我在响应中得到的函数代码将是4+128 = 132。

最后,我要补充的是,对read命令的响应中的第一个字节是寄存器的数量(而不是字节)!寄存器是响应中跟随的两个字节,对我来说这似乎是多余的,因为Modbus TCP头中已经有一个有效负载长度,但我没有制定协议。

希望这是关于Modbus TCP如何工作的一个很好的入门,所有提供的代码都是我的功能脚本中的Matlab代码,所以它应该适用于您。如果您想要更多关于您应该发送和接收的确切消息的信息,请查看Modbus上的维基百科页面。一旦你明白了这一切就很简单了。

票数 3
EN

Stack Overflow用户

发布于 2014-01-28 21:39:26

看起来,在收到来自s的任何数据之前,您已经执行了fread操作。在尝试读取数据之前,请检查s.BytesAvailable,以确保确实收到了某些内容。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21416239

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档