2014-01-28 78 views
0

我有这样的MATLAB代码:Modbus TCP和MATLAB

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对象的设置:

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 

连接成功,但我没有收到任何数据。我不知道如何收到任何日期。

编辑:

我加入这个底:

while ~s.BytesAvailable 
end 
s.BytesAvailable 
res=fread(s,s.BytesAvailable)     
fclose(s); 

现在我得到任何答复。

回答

0

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

+0

感谢您的回复。我做了一个s.BytesAvailable while循环来读取数据。我收到52个值,现在我必须找出哪个值是寄存器。 – knuppel

+0

我建议使用['BytesAvailableFcn'](http://www.mathworks.com/help/instrument/bytesavailablefcn.html)回调函数,而不是使用'while'循环来检查数据是否可用 - 这样您不必一直主动检查新数据。 –

+0

添加此底:同时〜s.BytesAvailable 端 s.BytesAvailable 解析度=的fread(S,s.BytesAvailable) FCLOSE(一个或多个);我没有回应 – knuppel

2

我知道这是一个旧帖子,所以我不愿意碰它,但我有Modbus TCP与Matlab工作,这是我试图让它工作时遇到的职位之一,所以我想我会在这里发表一个关于它的答案。

我会在前面说这是用Matlab的Instrument Control Toolbox完成的,因为这是tcpip()命令所需的。我将努力让这个工具箱在没有工具箱的情况下工作,因为让整个工具箱只用于Modbus TCP是过度杀伤性的,但为了快速开发的目的,试用版的工具箱足以让您受益匪浅。

因此,首先配置端口:

IPADDR='192.168.0.1'; 
PORT=502; 
tcpip_pipe=tcpip(IPADDR, PORT); 
set(tcpip_pipe, 'InputBufferSize', 512); 
tcpip_pipe.ByteOrder='bigEndian'; 

然后,打开端口:

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 

现在,我发现工作是准备整个消息,然后写整个事情一次。这有助于我认为,因为你在上面指定了排列顺序,所以你不必担心它是如何设置的,或者如果你按照正确的顺序编写消息等。

所以,现在,你如何构建一个Modbus TCP消息的故障:

  1. 事务ID - 这是一个可以是你想要的任意数目的2字节字段。通常,您每次发送消息时都会将此值增加1。您传输的设备会在响应时将此号码重复发送给您,以确保您正在解析特定请求的数据。如果响应中的事务ID与您发送的不匹配,则应丢弃数据。
  2. 协议 - 这是一个2字节的字段,应该全部为零以指示Modbus TCP。非常简单。
  3. 剩余字节数 - 这是一个2字节的字段,表示消息中剩余的字节数。只需添加所有字节;这就是这里的数字。
  4. 从站ID - 这是一个1字节的字段。我首先发现这个值有点令人困惑,但考虑到这一点:您正在使用Modbus TCP - 您已经直接连接到从站,因为您正在连接到上面指定的IP地址。这里的Slave ID的用途是,如果您使用Modbus TCP-RTU“路由器”,您的消息将在RTU网络上重新广播。在这种情况下,您试图在RTU网络上指定路由器后面设备的地址。如果您尝试通信的设备与您指定IP地址的设备相同,则不需要使用从站ID。如果你不使用它,你应该放下的值是255.所以,tl; dr - 如果你没有对Modbus做一些复杂的事情,那么把这个值设置为255。
  5. 函数ID - 这是一个1字节的字段。这是一个数字,对应于specific function code指示设备要执行的操作。就我而言,我只想读取寄存器,所以我的函数ID是每次4。
  6. 数据 - 这可能是您的设备配置要做的任何事情,但我会解释一些“默认”情况,因为它们应该很普遍。通常情况下,当您向设备(从设备)发送消息时,数据将是两个2字节值,其中第一个2字节值是特定寄存器的地址,第二个2字节值是寄存器读取或写入该寄存器的值。

因此,我们来尝试一个例子。我希望事务代码为3(再次,我选择一个随机数,并随着每次传输而递增,以使我能够匹配对特定传输的响应)。我希望函数代码是4(读取寄存器),我想从寄存器0开始,并且我想读取12个寄存器。对于记录来说,寄存器通常是2个字节,所以这意味着我想从寄存器0开始并准备好24个字节的信息。

该消息如下所示:

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 

现在,写这个消息到设备:

fwrite(tcpip_pipe, message,'int8'); 

然后等待回应:

while ~tcpip_pipe.BytesAvailable,end 

然后读取返回的数据:

response = fread(tcpip_pipe,tcpip_pipe.BytesAvailable); 

标题信息应该都符合预期。同样,如果交易ID与您发送的不符,那么您应该丢弃该消息。功能代码应与您发送的相同。如果不是,这可能是一个错误 - error function code与您发送的内容相同,外加128.因此,在我的示例中,我想读取输入寄存器(功能代码4),并且如果出现错误(如我的消息isn不正确的格式,指定一个无效的寄存器号码等),那么我将得到的功能代码将是4 + 128 = 132.

作为最后一点,我将补充说明第一个字节在对读命令的响应中将是寄存器的数量(不是字节!一个寄存器是两个字节),这对我来说似乎是多余的,因为Modbus TCP报头中已经有了一个有效载荷长度,但是我没有制定协议。

希望这是关于Modbus TCP工作原理的一个很好的入门知识,所有提供的代码都是直接来自我的功能脚本的Matlab代码,所以它应该适合您。如果您想了解更多关于您应该收发的信息,请查看Modbus上的Wikipedia page。一旦你理解它,这一切都很简单。