Modbus TCP and MATLAB

北城余情 提交于 2019-12-13 04:08:14

问题


I have this MATLAB Code:

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); 

but I get the following response:

Warning: Unsuccessful read: The specified amount of data was not returned within the Timeout period.

Here are the settings for the TCPIP object:

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

The connection was successful, but I don't receive any data. I don't know how to receive any Date.

EDIT:

I added this at the end:

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

Now i get no response.


回答1:


I know this is an old post, so I'm reluctant to bump it, but I've got Modbus TCP working with Matlab and this is one of the posts I came across when I was trying to get it to work, so I figured I'd post an answer here about it.

I'll preface this by saying that this is done with the Instrument Control Toolbox for Matlab, as that's required for the tcpip() command. I'll work on getting this to work without the toolbox later, as getting the whole toolbox just for Modbus TCP is overkill, but for rapid development purposes a trial version of the toolbox is enough to get you by for a bit.

So, first configure the port:

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

Then, open the port:

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

Now, what I've found to work is to prepare the entire message and then write the entire thing at once. This helps, I think, because you specify the endianness with te .ByteOrder above, so you don't really need to worry about how it's setup beyond that or if you're writing the messages in the correct order, etc.

So now, a breakdown of how you structure a Modbus TCP message:

  1. Transaction ID - This is a 2-byte field that can be any arbitrary number you want. Typically you would increment this value by 1 every time you send a message. The device you transmit to will repeat this number back to you when it responds so you can be sure that you're parsing the data for a particular request. If the transaction ID on the response doesn't match what you sent then you should discard the data.
  2. Protocol - This is a 2-byte field that should be all zeros to indicate Modbus TCP. Pretty straightforward.
  3. Bytes Remaining - This is a 2-byte field that states how many bytes remain in the message. Just add all the bytes; that's the number that goes here.
  4. Slave ID - This is a 1-byte field. I found this value to be a little confusing at first, but consider this: You are using Modbus TCP - you already have a direct connection to the slave because you are connecting to the IP address that you specify above. The purpose of Slave ID here is if you're using a Modbus TCP-RTU "router" where your message will get re-broadcast on an RTU network. In that case, you're trying to specify the address of the device behind the router, on the RTU network. If the device you're trying to communicate is the same as the one that you've specified the IP address for, then you don't need to use the Slave ID. The value you should put down if you're not using it is 255. So, tl;dr - if you're not doing something complex with Modbus, put 255 for this value.
  5. Function ID - This is a 1-byte field. This is a number that corresponds to a specific function code that instructs the device what to do. In my case, all I wanted to do was read registers, so my function ID was 4 every time.
  6. Data - This could be anything that your device is configured to do, but there's a couple "default" cases that I'll explain as they should be pretty universal. Typically, when you send a message to the device (slave), the data will be two 2-byte values, where the first 2-byte value is the address of a particular register and the second 2-byte value is either the number of registers to read or the value to be written to that register.

So, let's try an example. I want the transaction code to be 3 (again, an arbitrary number I choose and increment with every transmission to allow me to match a response to a particular transmission). I want the function code to be 4 (read registers), I want to start at register 0, and I want to read 12 registers. For the record, a register is typically 2 bytes, so this means that I want to start at register 0 and ready 24 bytes of information.

That message looks like the following:

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

Now, write this message to the device:

fwrite(tcpip_pipe, message,'int8');

Then, wait for a response:

while ~tcpip_pipe.BytesAvailable,end

And then read the returned data:

response = fread(tcpip_pipe,tcpip_pipe.BytesAvailable);

The header information should all be as expected. Again, if the transaction ID doesn't match what you sent then you should discard the message. The function code should be the same as what you sent. If it's not, it's probably an error - the error function code is the same as what you sent, plus 128. So, in my example, I wanted to read input registers (function code 4), and if there's an error (like my message isn't formatted correctly, specify an invalid register number, etc.) then the function code I'll get in the response will be 4+128 = 132.

As a final note, I'll add that the first byte in the response to a read command would be the number of registers (not bytes! a register is two bytes) that follow in the response, which seems superfluous to me because there's already a payload length in the Modbus TCP header, but I didn't make the protocol.

Hopefully this is a pretty good primer on how Modbus TCP works, and all the code provided is Matlab code straight from my functioning script, so it should work for you. If you would like more information on the exact messages you should be sending and receiving, check out the Wikipedia page on Modbus. It's all pretty straightforward once you understand it.




回答2:


It looks like you've done an fread operation before you received any data from s. Check s.BytesAvailable to make sure you've actually received something before attempting to read it.



来源:https://stackoverflow.com/questions/21416239/modbus-tcp-and-matlab

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!