Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

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!

Comment on Need help with Modbus
Download Code
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 the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (4)
As of 2016-05-30 01:36 GMT
Find Nodes?
    Voting Booth?