Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses

Need help with Modbus

by pashanoid (Scribe)
on Jan 24, 2012 at 12:45 UTC ( #949676=perlquestion: print w/replies, xml ) Need Help??
pashanoid has asked for the wisdom of the Perl Monks concerning the following question:

A great localtime to everyone!

Please help me figure out which (and how) of the few available Perl Modbus modules to use! I can't seem to figure out coils, registers and addresses. However, this piece of c code (when compiled with modbus libraries) works fine:

/* * sunsaver.c - This program reads all the RAM registers on a Morings +tar SunSaver MPPT and prints the results. * */ /* Compile with: cc sunsaver.c -o sunsaver -lmodbus */ #include <stdio.h> #include <stdlib.h> #include <modbus/modbus.h> #define SUNSAVERMPPT 0x01 /* MODBUS Address of the SunSaver MPPT + */ int main(void) { modbus_param_t mb_param; int ret; float adc_vb_f,adc_va_f,adc_vl_f,adc_ic_f,adc_il_f, Vb_f, Vb_r +ef, Ahc_r, Ahc_t, kWhc; float V_lvd, Ahl_r, Ahl_t, Power_out, Sweep_Vmp, Sweep_Pmax, S +weep_Voc, Vb_min_daily; float Vb_max_daily, Ahc_daily, Ahl_daily, vb_min, vb_max, V_PU +, I_PU; short T_hs, T_batt, T_amb, T_rts; unsigned short charge_state, load_state, led_state; unsigned int hourmeter; unsigned short array_fault, load_fault, dip_switch, array_faul +t_daily, load_fault_daily; unsigned int alarm, alarm_daily; uint16_t data[150]; /* Setup the serial port parameters */ // modbus_init_rtu(&mb_param, "/dev/tty.voltmeter", 9600, "none", + 8, 2); /* Add the appropriate path to your serial port */ modbus_init_tcp(&mb_param, "", 502);/* Add the app +ropriate path to your serial port */ /* Open the MODBUS connection */ if (modbus_connect(&mb_param) == -1) { printf("ERROR Connection failed\n"); exit(1); } /* Read the RAM Registers */ ret = read_input_registers(&mb_param, SUNSAVERMPPT, 0x0000, 75 +, data); /* Close the MODBUS connection */ modbus_close(&mb_param); /* Convert the results to their proper values and print them o +ut */ V_PU=((data[1] << 16) + data[0]); // printf("%.2f\n",V_PU); I_PU=((data[3] << 16) + data[2]); printf("%.2f\n%.2f\n",data[59]*V_PU*I_PU/131072,data[58]*V_PU* +I_PU/131072); //max P // printf("%.2f\n",data[60]*V_PU*I_PU/131072); //array V, batteryV printf("%.2f\n%.2f\n",data[27]*V_PU/32768,data[38]*V_PU/32768) +; printf("%d\n",data[55]); return(0); }

I've looked into: all of these, and I'm giving up. I wrote a perl program that uses the above code to get the dreaded 4 values from this solar controller, but this is not right! Anyone, with experience with Modbus, please help me use the propper module and get the abouve 4 (and hopefully more) values directly from Perl!

Replies are listed 'Best First'.
Re: Need help with Modbus
by Khen1950fx (Canon) on Jan 25, 2012 at 05:32 UTC
    Protocol::Modbus is the module that you want to use. The documentation is very sparse, but the source has the info that you need. I gave it quick look and managed to get this going. I used the generic approach.
    #!/usr/bin/perl -l use strict; use warnings; $|=1; my $proto = Protocol::Modbus->new( driver => 'TCP', transport => 'TCP +' ); my $request1 = $proto->request( function => 1, address => 1, quantity => 1, ); my $request2 = $proto->request( function => 2, address => 1, quantity => 1, ); my $request3 = $proto->request( function => 3, address => 1, uantity => 1, ); my $request4 = $proto->request( function => 4, address => 1, quantity => 1, ); print "=" x 60; print "Using unpack: \n"; print unpack ('H*', $request1->pdu()); print unpack ('H*', $request2->pdu()); print unpack ('H*', $request3->pdu()); print unpack ('H*', $request4->pdu()); print "=" x 60; print "Using Pretty-Print: \n"; print $request1; print $request2; print $request3; print $request4; print "=" x 60; print "stringify: "; print $request1->stringify(); print $request2->stringify(); print $request3->stringify(); print $request4->stringify(); print "=" x 60;

      Thank you! However, could you please elaborate: if my IP is port 502, then do I format the like this? $proto = Protocol::Modbus->new( driver => 'TCP', transport => 'TCP', ip=>'', port=>'502' );

      if in c ret = read_input_registers(&mb_param, SUNSAVERMPPT, 0x0000, 75, data); Then Which are the function, address and quantity? in my $request4 = $proto->request( function => 4, address => 1, quantity => 1, );

      Which handle/variable gets the modbus reply?

        The $req variable gets the modbus reply.

        #!/usr/bin/perl -l use strict; use warnings; use Protocol::Modbus; $|=1; my $modbus = Protocol::Modbus->new( driver => 'TCP', transport => 'TCP', ); my $trs = Protocol::Modbus::Transport->new( driver => 'TCP', address => '', port => 502, timeout => 3, ); my $req = $modbus->request( function => 4, address => 1, quantity => 75, value => 0x0000, ); print "=" x 60; print "Response: ", $req; print "=" x 60; $trs->disconnect;

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://949676]
Approved by planetscape
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (9)
As of 2017-10-17 20:38 GMT
Find Nodes?
    Voting Booth?
    My fridge is mostly full of:

    Results (236 votes). Check out past polls.