Jump to content

Recommended Posts

Posted (edited)

Hallo zusammen,


ich möchte über das "RS485-Bricklet" vier Schlauchwaagengefäße ansteuern und den Hydrostatischen Druck über die Funktion "Read Holding Registers" mit einer Frequenz von 2 Hz auslesen.
Für einen ersten Test habe ich Anfragen über den "Brick Viewer" geschickt und die gewünschte Antwort bekommen.

Nun ist es aber erforderlich, dass ich diese Anfragen automatisiert über Matlab stelle.
Es ist mir möglich auf Grundlage des Beispielcodes "Loopback" eine Verbindung herzustellen, allerdings ist es mir nicht möglich über den "write"-Befehl eine einzelne oder sich wiederholende Anfrage zu stellen.
Bei aktiver Verbindung zwischen Matlab und dem RS485-Bricklet kann ich parallel über den Brickviewer einen Input geben, dessen Output mir dann sowohl im Brickviewer, als auch in Matlab angezeigt wird.

Was mache ich momentan noch falsch? Wäre Super, wenn mir da jemand weiterhelfen könnte. :)

Beste Grüße
Leonhard

 

clc
clear all

global data

    
    import com.tinkerforge.IPConnection;
    import com.tinkerforge.BrickletRS485;
    import java.lang.String;

    % For this example connect the RX+/- pins to TX+/- pins on the same Bricklet
    % and configure the DIP switch on the Bricklet to full-duplex mode

    HOST = 'localhost';
    PORT = 4223;
    UID = 'DKf'; % Change XYZ to the UID of your RS485 Bricklet

    input('Press key to start\n', 's');
    
    ipcon = IPConnection(); % Create IP connection
    rs485 = handle(BrickletRS485(UID, ipcon), 'CallbackProperties'); % Create device object

    ipcon.connect(HOST, PORT); % Connect to brickd
    % Don't use device before ipcon is connected

     % Set Mode to RS485
    rs485.setMode(BrickletRS485.MODE_RS485);
    
    % Enable full-duplex mode
    rs485.setRS485Configuration(9600, BrickletRS485.PARITY_EVEN, ...
                                BrickletRS485.STOPBITS_1, BrickletRS485.WORDLENGTH_7, ...
                                BrickletRS485.DUPLEX_HALF);                        
                     
    % Register read callback to function cb_read
    set(rs485, 'ReadCallback', @(h, e)cb_read(e));
    
    % Enable read callback
    rs485.enableReadCallback();
    
    
   % Write "ASCII" string (Adresse und Befehl)
   rs485.write(String(':9003015E00020C\r\n').toCharArray()); %SWA 144
   
   rs485.write(String(':8E03015E00020E\r\n').toCharArray()); %SWB 142
   
   rs485.write(String(':8D03015E00020F\r\n').toCharArray()); %SWC 141
    
   rs485.write(String(':8F03015E00020D\r\n').toCharArray()); %SWD 143

    input('Press key to exit\n', 's'); %Alternative für input
    ipcon.disconnect();

   
% Callback function for read callback
function cb_read(e)
    global data

    tmp_t = now;
    % fprintf('Message: "%s"\n', e.message);
    fprintf(e.frameCount);
    
    B = convertCharsToStrings(e.message);
    C = [tmp_t; B];
    data = [data, C];
end

 

Edited by leonhard.pleuger
Posted

Was mich auf den ersten Blick stutzig macht ist die Wordlength von 7 Bit, üblich wären 8 Bit. Auf den zweiten Blick kommt die Frage warum du in deinem Programm das Bricklet im RS485 Modus verwendest und händisch Modbus versuchst zu sprechen, wenn du im Brick Viewer erfolgreich das Bricklet mit Modbus Master Modus verwendest mit der Read Holding Registers Funktion.

Du solltest nicht auf das Loopback Beispiel aufsetzten, sondern auf das Modbus Master Besipiel:

https://www.tinkerforge.com/de/doc/Software/Bricklets/RS485_Bricklet_MATLAB.html#modbus-master-matlab

Und dieses von modbusMasterWriteSingleRegister auf modbusMasterReadHoldingRegisters umstellen.

Posted (edited)

Hallo, 

vielen Dank für die schnelle Antwort. Die 7 Bit Wordlength ist schon richtig, da vom Schlauchwaagenherrsteller so vorgegeben. (bei 8 Bit kommt nur Kauderwelsch raus). 

Bis jetzt habe ich ausschließlich im RS485 Modus gearbeitet, sowohl im Brickviewer, als auch in Matlab. Im Modbus Master Modus bekomme ich bis jetzt einen "Request Timeout". 

Wenn ich jetzt deine Hinweise umsetze, bekomme ich ein Exception Code: -1, also einen Timeout und keinerlei Daten für "e.holdingRegisters".

 

clc
clear all


    global expected_request_id;
    global counter;
    global data;

    import com.tinkerforge.IPConnection;
    import com.tinkerforge.BrickletRS485;

    HOST = 'localhost';
    PORT = 4223;
    UID = 'DKf'; % Change XYZ to the UID of your RS485 Bricklet

    input('Press key to start\n', 's');
    
    counter = 0;
    
    ipcon = IPConnection(); % Create IP connection
    rs485 = handle(BrickletRS485(UID, ipcon), 'CallbackProperties'); % Create device object

    ipcon.connect(HOST, PORT); % Connect to brickd
    % Don't use device before ipcon is connected

    % Set operating mode to Modbus RTU master
    rs485.setMode(BrickletRS485.MODE_MODBUS_MASTER_RTU);

    % Modbus specific configuration:
    % - slave address = 1 (unused in master mode)
    % - master request timeout = 1000ms
    rs485.setModbusConfiguration(144, 3000)
    
     % Configuration
    rs485.setRS485Configuration(9600, BrickletRS485.PARITY_EVEN, ...
                                BrickletRS485.STOPBITS_1, BrickletRS485.WORDLENGTH_7, ...
                                BrickletRS485.DUPLEX_HALF);
    
    % Register Modbus master write single register response callback to function
    % cb_modbus_master_write_single_register_response
    set(rs485, 'ModbusMasterReadHoldingRegistersResponseCallback', ...
            @(h, e) cb_modbus_master_read_holding_register_response(e));
        
   % Write 65535 to register 42 of slave 17                    17,42,65535
    expected_request_id = rs485.modbusMasterReadHoldingRegisters(144, 350, 2);  %SW144 register 350;351

    
    input('Press key to exit\n', 's');
    ipcon.disconnect();
    

% Callback function for Modbus master write single register response callback
function cb_modbus_master_read_holding_register_response(e)
    global expected_request_id;
    global counter;
    global data
    
    tmp_t = now;
   % counter = counter + 1;
    fprintf('Request ID: %i\n', e.requestID);
    fprintf('Expected Request ID: %i\n', expected_request_id);
    fprintf('Exception Code: %i\n', e.exceptionCode);
    fprintf('Holding Registers: %i\n', e.holdingRegisters);

    B = convertCharsToStrings(e.holdingRegisters);
    C = [tmp_t; B];
    data = [data, C];
    
    if e.requestID ~= expected_request_id
        fprintf('Error: Unexpected request ID\n');
    end
end

 

Demo_Modbus_PC_HS_Serie.pdf

Edited by leonhard.pleuger
Posted

Ich fürchte der Modbus Modus des Bricklets für 7 Bit ist ungetestet. Daher jetzt eine Rolle rückwärts 😜. Da es mit Brick Viewer funktioniert müssen wir jetzt nur finden was in deinem initialen Programm nicht passt.

Was genau hast du in Brick Viewer als Anfrage eingeben? Und hast du dabei das Encoding auf "ASCII" oder "Raw (Hex Bytes)" gestellt?

Posted

Okay, um einmal meine Verwirrung zu klären. Der Sensor den du da verwendest sprichst Modbus ASCII und das was du da schickst sieht auch nach korrektem Modbus ASCII aus, daher auch die 7 Bit. Die Modbus Funktionen des Bricklets sind für Modbus RTU, meinen Ratschlag das zu nutzen kannst du ignorieren, das funktioniert nicht.

Es sieht auf den ersten Blick so aus als hättest du dein Vorgehen von Brick Viewer korrekt in dein Programm übertragen. Eine Unterschied könnte noch sein, dass du in Brick Viewer zwischen den 4 Anfragen die du schickst etwas Zeit vergeht, weil du händisch die Anfrage wechseln musst. In deinem Programm schickst du die 4 Anfragen aber direkt nacheinander raus. Du lässt also dem ersten Sensor gar keine Zeit zu antworten, sondern quatscht ihm sofort mit der Anfrage für den zweiten Sensor dazwischen.

Versuch also mal in deinem Programm nur die erste Anfrage zu schicken, oder zwischen den Anfragen eine kurze Pause einzubauen, damit die Sensoren auch eine Chance haben zu antworten.

Posted

Hallo,

besten Dank für die Hinweise.

Die Anfrage können wir auch alleine also nur an einen Sensor stellen (aus kommentieren der anderen Zeilen) und lange warten, es zeigt sich leider das gleich Verhalten. Wir erhalten auch auf recht kurze Klickabfolgen auf das „WriteLine“ im BrickViewer die  oben genannte Rückmeldung über das CallBack in Matlab. Das schnelle “zu quatschten” kann also nicht die Ursache sein.

Was steckt denn hinter dem “WriteLine” Button im BrickViewer für ein Befehl. Wie wird der umgesetzt und gesendet? An der Stelle muss es ja einen Unterschied geben. Die Matlab write Funktion gibt auch die Anzahl an geschriebene Zeichen zurück, auch eine Kontrolle mit einem Oszillograph hat gezeigt, dass Daten rausgehen... nur scheinen Sie nicht korrekt anzukommen mittels der Matlab write Funktion. Da die Daten ja auch im Callback zurückkommen, sollten die Schnittstellen-Parameter ja grundsätzlich stimmen.

 

Posted

Sehr komisch. Da habe ich keine gute Idee zu. Das initiale Programm sollte einfach funktionieren, abgesehen von den 4 Writes direkt nacheinander.

Für mein Verständnis:

Aus Brick Viewer heraus funktioniert alles wie erwartet. Wenn die Anfrage gesendet wird kommt eine passenden Antwort darauf. Wenn ihr das aber aus eurem Programm heraus macht kommt keine Antwort. Wenn aber euer Programm läuft und ihr parallel dazu in Brick Viewer die Anfrage sendet, dann kommt eine passenden Antwort in eurem Programm und in Brick Viewer an. Habe ich das so richtig verstanden?

Was passiert wenn Brick Viewer bereits läuft und ihr euer Programm startet? Dann kommt weder in Brick Viewer noch in eurem Programm eine Antwort an. Sprich das Problem scheint zu sein, dass der Sensor die Anfrage nicht versteht/empfängt wenn sie von eurem Programm gesendet wird und deswegen gar nicht antwortet. Das Problem ist nicht, dass die Antwort zwar kommt, aber euer Programm sie nicht erhält, wenn die Anfrage auch durch euer Programm gesendet wurde?

Hier ein paar schlechte Ideen 😜

1) Es gibt eine sehr kleine Chance, dass sich Brick Viewer und euer Programm über den Zustand des Read Callbacks in die Quere kommen. Wenn in Brick Viewer der Tab des RS485 Bricklets ausgewählt wird, dann merkt dich Brick Viewer ob der Read Callback bereits aktiv war. Falls nicht, dann wird der Callback aktiviert und beim Verlassen des Tabs wieder deaktiviert. Daher testet bitte mal Brick Viewer zu beenden und dann euer Programm auszuführen. Ich erwarte allerdings nicht, dass das hilft, denn damit das ein Problem sein könnte müsstet ihr in Brick Viewer den Tab verlassen genau zwischen euer Programm sendet die Anfrage und die Antwort kommt an. Unwahrscheinlich.

2) Startet mal alle Hardware neu. Also den ganzen Tinkerforge Aufbau und die Sensoren einmal vom Strom trennen, kurz Warten und wieder anschließen. Nur um sicherzustellen, dass die Hardware nicht einfach in einem verwirrten Zustand ist. Auch Unwahrscheinlich.

3) Brick Viewer ruft auch nur die Write Funktion auf. Habt ihr mit dem Oszilloskop mal die Anfrage von Brick Viewer und eurem Programm verglichen? Dort sollte keine Unterschied bestehen. Per Oszilloskop solltet ihr auch sehen können, ob vom Sensor einfach keine Antwort kommt oder ob eine Antwort kommt, dass Bricklet sie aber nicht versteht, wenn die auslösende Anfrage von eurem Programm gesendet wurde.

  • Like 1
Posted

Hi, 

das fasst die Situation gut zusammen. Es macht allerdings keinen Unterschied, in welcher Reihenfolge Brickviewer und Matlab gestartet werden. es kommt immer das gleiche Ergebnis raus.

Versuche, die Hardware neu zu starten, den BrickViewer zu beenden oder Pausen in das Programm einzubauen, haben nicht zum gewünschten Ergebnis geführt.

Wir haben mal ein Oszilloskop angeschlossen und dann Anfragen gestellt. Es erscheint dasselbe Signal, unabhängig davon, ob Matlab oder der Brickviewer anfragt. Allerdings konnten wir nur die Anfragen und nicht die Antworten sehen.  

Ich würde sagen, dass das das Problem darauf einschränkt, dass Matlab die Antwort des Sensors nicht auslesen kann.  

Posted

Die Anfrage sieht also auf dem Oszilloskop identisch aus, egal ob aus Matlab oder aus Brick Viewer gesendet, sprich der Sensor kann das nicht unterscheiden. Aber es kommt in Brick Viewer und Matlab nur eine Antwort an, wenn Brick Viewer die Anfrage gestellt hat, aber nicht wenn Matlab die Anfrage stellt. Das verwirrt mich weiterhin sehr.

Interessant wäre jetzt noch zu sehen, was mit der Antwort laut Oszilloskop ist. Ob der Sensor sie wirklich nicht sendet.

Ich nehme an auf dem RS485 Bricklet ist die aktuelle Firmware 2.0.5 drauf. Falls nicht, updated bitte mal über Brick Viewer.

Okay, mal ganz zurück zum Anfang. Funktioniert das unveränderte Loopback Beispiel in Matlab, unter der Annahme das Bricklet ist entsprechend der Angaben im Beispiel verkabelt und der DIP Schalter passend eingestellt?

Funktioniert das Loopback Beispiel mit eurer 9600 7E1 Konfiguration? Wobei ihr hier für Loopback auf Full-Duplex stellen müsst, statt auf Half-Duplex wie beim Sensoraufbau.

    rs485.setRS485Configuration(9600, BrickletRS485.PARITY_EVEN, ...
                                BrickletRS485.STOPBITS_1, BrickletRS485.WORDLENGTH_7, ...
                                BrickletRS485.DUPLEX_FULL);
Posted

Hallo, 

wir haben den Fehler gefunden. Schuld waren die letzten vier Zeichen "\r\n", die Matlab im ASCII Befehl falsch interpretiert hat. 

Die Nachricht darf also nicht die folgende Form haben: ':9003015E00020C\r\n'

Wenn der write Befehl folgendermaßen aussieht, wird das gewünschte Ergebnis ausgegeben. 

cr = sprintf('\r'); %carriage return
lf = newline; %line feed
rs485.write([':9003015E00020C', cr, lf]);

Der Terminatior muss also extra angehängt werden. 

Sehr vielen Dank für die Hilfe. :-) 

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...