4zap 4zap - 3 months ago 3x
Perl Question

Why is my Perl script printing incorrect values when not using hard-coded values?

I use an A/D converter to get some results of an electric conductivity probe. I use a miniEC interface from Sparky's Widgets. We run a calibration and get the slope and the intercept values. When I am testing this values with this calibration in a static script the result is correct.

See here, not a big thing but a proof that my calibration works well. The result is correct.


my $slope = "0.048684077307972626";
my $intercept = "24.831896523430906";

$ECdec = 62.5;

print "$ECdec \n";

$EC1 = ( ( $ECdec - $intercept ) / $slope );

print "Electric Conductivity $EC1 µS/m \n";

Output is:

Electric Conductivity 773.725323749752 �S/m

When I swap the static value
to the output of the A/D Converter and try to get a result it is totally wrong. Can anyone see my failure?

Here is the Perl which reads the probes value from the converter, swap the bytes, convert it to decimal and then add the linear regression. What did I do wrong?


my $dir = '/var/www/motion';

my $slope = "0.048684077307972626";
my $intercept = "24.831896523430906";

###get value
my $EC = `sudo i2cget -y 1 0x4a 0x00 w` ;

print "$EC \n";

my $ECswap = $EC;
substr $ECswap, 4, 0, substr $ECswap, 2, 2, q();

print "$ECswap \n";

###convert to decimal
$ECdec = hex($ECswap);

print "$ECdec \n";

$ECvalue = ($ECdec - $ECintercept)/$slope);

print "$ECvalue"
#$rrd = `/usr/bin/rrdtool update $dir/homeec.rrd N:$ECdec`;

####system ("clear");
print "Electric Conductivity $ECdec µS/m \n";

Output here is:

Electric Conductivity 16969.9858590372 �S/m


You are printing $ECdec in your output instead of $ECvalue

Also, please always post your real code. The program you have shown won't compile and is clearly not the one that is giving you problems

This is how your program should look

You must always use strict and use warnings 'all' at the top of even the most trivial Perl programs, and declare all of your variables with my

You should always use utf8 if your code contains non-ASCII characters like the Greek mu µ in microSiemens. Perl doesn't support source code encoded other than in 7-bit ASCII or UTF-8. I don't know whether your terminal expects UTF-8 characters, and you may need to alter the use open statement

I have commented out your call to i2cget to retrieve a real value and subsituted a constant string instead

I have also converted the hex string to binary before swapping the bytes for speed, but it's far from critical and you should retain the character swap if you find it more readable. I would use a regular expression and write it like this

die unless $EChex =~ /0x(\p{hex}{2})(\p{hex}{2})/;
my $EC = hex($2.$1);

use utf8;
use strict;
use warnings 'all';
use open qw/ :std :encoding(utf8) /;

use constant DIR       => '/var/www/motion';
use constant SLOPE     => 0.048684077307972626;
use constant INTERCEPT => 24.831896523430906;

# my $EChex = `sudo i2cget -y 1 0x4a 0x00 w` ;
my $EChex = '0x5303';
printf "\$EChex = %s\n", $EChex;

my $EC = hex $EChex;
printf "\$EC = %s\n", $EC;

$EC = (($EC & 0xFF00) >> 8) | (($EC & 0xFF) << 8); # swap bytes

my $ECvalue = ($EC - INTERCEPT) / SLOPE;

printf "Electric Conductivity %.3fµS/m \n", $ECvalue;


$EChex = 0x5303
$EC = 21251
Electric Conductivity 16969.986µS/m