问题
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:
- 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.
- Protocol - This is a 2-byte field that should be all zeros to indicate Modbus TCP. Pretty straightforward.
- 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.
- 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.
- 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.
- 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