2014-01-28 77 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。一旦你理解它,這一切都很簡單。