package Device::USB::PCSensor::HidTEMPer::NTC::External;
use strict;
use warnings;
use Carp;
use Time::HiRes qw / sleep /;
use Device::USB::PCSensor::HidTEMPer::Sensor;
our @ISA = 'Device::USB::PCSensor::HidTEMPer::Sensor';
=head1
Device::USB::PCSensor::HidTEMPer::NTC::Internal - The HidTEMPerNTC external sensor
=head1 VERSION
Version 0.02
=cut
our $VERSION = 0.02;
=head1 SYNOPSIS
None
=head1 DESCRIPTION
This is the implementation of the HidTEMPerNTC external sensor.
=head2 CONSTANTS
=over 3
=item * MAX_TEMPERATURE
The highest temperature(150 degrees celsius) this sensor can detect.
=cut
use constant MAX_TEMPERATURE => 150;
=item * MIN_TEMPERATURE
The lowest temperature(-50 degrees celsius) this sensor can detect.
=cut
use constant MIN_TEMPERATURE => -50;
=item * INITIAL_GAIN
The initial gain value used to calculate voltage returned
=cut
use constant INITIAL_GAIN => 1;
=item * CALIBRATION_VALUES
Values used to calculate Volt7705Calibration
=cut
use constant CALIBRATION_VALUES => [
[ 0.0010888, 0.0012803, 0.000754167, 0.0009208333 ],
[ 0.0012803, 0.0017002, 0.0009208333, 0.0012541667 ],
[ 0.0017002, 0.002666, 0.0012541667, 0.0021125 ],
[ 0.002666, 0.00522, 0.0021125, 0.0041666667 ],
[ 0.00522, 0.0149, 0.0041666667, 0.012625 ],
[ 0.0149, 0.04683, 0.012625, 0.0413333333 ],
[ 0.04683, 0.21342, 0.0413333333, 0.2115416667 ],
[ 0.21342, 0.36914, 0.2115416667, 0.346166667 ],
[ 0.36914, 0.44121, 0.346166667, 0.4215416667 ],
[ 0.44121, 0.65351, 0.4215416667, 0.6208333333 ],
[ 0.65351, 0.92445, 0.6208333333, 0.91625 ],
[ 0.92445, 1.08022, 0.91625, 1.1375 ],
[ 1.08022, 1.8745, 1.1375, 1.91375 ],
[ 1.8745, 1.9943, 1.91375, 2.07125 ],
[ 1.9943, 2.4589, 2.07125, 2.72125 ],
];
=back
=head2 METHODS
=over 3
=item * new()
Returns a new External sensor object.
=cut
sub new
{
my $class = shift;
# All devices are required to spesify the temperature range
my $self = $class->SUPER::new( @_ );
# Initialize the gain, this will be automatically adjusted later on.
$self->{gain} = INITIAL_GAIN;
$self->_write_gain( $self->{gain} );
bless $self, $class;
return $self;
}
=item * celsius()
Returns the current temperature from the device in celsius degrees.
=cut
sub celsius
{
my $self = shift;
my @data = ();
my $counter = 0;
my $volt = 0;
my $key = 0;
my $temperature = 0;
# Command 0x41 will return the following 8 byte result, repeated 4 times.
# Position 0: Part one of the float number
# Position 1: Part two of the float number
# Position 2: Part three of the float number
# Position 3: unused
# Position 4: unused
# Position 5: unused
# Position 6: unused
# Position 7: unused
# This device may return 255*8 until it is ready for use.
@data = $self->{unit}->_read( 0x41 );
$counter = 0;
READ: until ( $counter > 20 ){
next READ if $data[0] == 0xFF
&& $data[1] == 0xFF
&& $data[2] == 0xFF;
# Caluculate returned reading
$volt = ( ( ( $data[0]-128 ) + ( $data[1] / 256 ) ) / 52.032520325203252 ) / $self->{gain};
last READ if $self->_new_reading_needed( $volt ) == 0;
}continue{
$counter++;
sleep 0.2;
@data = $self->{unit}->_read( 0x41 );
}
croak 'Invalid readings returned' if $counter >= 21;
# Calculate key
$key = $self->_volt_7705_calibration( $volt );
=pod
The formula used to calculate value based on a calibrated key value is
created using the Eureqa tool from Cornell Computational Synthesis Lab,
http://ccsl.mae.cornell.edu/eureqa.
Resulting in the use of this formula instead of the provided number list:
f(y)=66.7348/(66.7275/(67.8088 - 9.70353*log(0.000251309 + y*y)) - 0.21651)
If you find another formula that is more accurate please drop me a line.
The data used can be found in the source code of this file.
=cut
$temperature = 66.7348
/ ( 66.7275
/ ( 67.8088
-
9.70353
*
log( 0.000251309
+ ( $key
* $key )
)
)
-
0.21651
);
return $temperature;
}
# Calculate Volt7705Calibration
sub _volt_7705_calibration
{
my $self = shift;
my ( $volt ) = @_;
my $reference = undef;
# Select the correct values needed
if( $volt <= 0.0010888 ){
return -0.000334633;
}elsif( $volt <= 0.0012803 ){
$reference = CALIBRATION_VALUES->[0];
}elsif( $volt <= 0.0017002 ){
$reference = CALIBRATION_VALUES->[1];
}elsif( $volt <= 0.002666 ){
$reference = CALIBRATION_VALUES->[2];
}elsif( $volt <= 0.00522 ){
$reference = CALIBRATION_VALUES->[3];
}elsif( $volt <= 0.0149 ){
$reference = CALIBRATION_VALUES->[4];
}elsif( $volt <= 0.04683 ){
$reference = CALIBRATION_VALUES->[5];
}elsif( $volt <= 0.21342 ){
$reference = CALIBRATION_VALUES->[6];
}elsif( $volt <= 0.36914 ){
$reference = CALIBRATION_VALUES->[7];
}elsif( $volt <= 0.44121 ){
$reference = CALIBRATION_VALUES->[8];
}elsif( $volt <= 0.65351 ){
$reference = CALIBRATION_VALUES->[9];
}elsif( $volt <= 0.92445 ){
$reference = CALIBRATION_VALUES->[10];
}elsif( $volt <= 1.08022 ){
$reference = CALIBRATION_VALUES->[11];
}elsif( $volt <= 1.8745 ){
$reference = CALIBRATION_VALUES->[12];
}elsif( $volt <= 1.9943 ){
$reference = CALIBRATION_VALUES->[13];
}elsif( $volt <= 2.4589 ){
$reference = CALIBRATION_VALUES->[14];
}else{
return 0.26235000000000008;
}
return (
(
$volt
+
(
(
( ( $reference->[2] * $volt ) / $reference->[0] )
+
(
(
( ( $reference->[3] * $volt ) / $reference->[1] )
-
( ( $reference->[2] * $volt ) / $reference->[0] )
)
*
(
( $volt - $reference->[0] )
/
( $reference->[1] - $reference->[0] )
)
)
)
-
$volt
)
) / 0.0000041666666666666669
) / 1000;
}
# Returns 0 if the gain has not changed and a new reading is not needed.
sub _new_reading_needed
{
my $self = shift;
my ( $volt ) = @_;
# Safety filters
return 0 if ( $self->{gain} > 128 ) || ( $self->{gain} < 1 );
return 0 if $self->{gain} % 2 != 0;
# Adjust gain
if( !defined $volt ){
carp 'Undefined voltage';
}elsif( $volt > ( 2.214 / $self->{gain} ) ) {
$self->{gain} = $self->{gain}*0.5;
$self->_write_gain();
return -1;
}elsif( $volt < ( 0.984 / $self->{gain} ) ) {
$self->{gain} = $self->{gain}*2;
$self->_write_gain();
return 1;
}else{
return 0;
}
croak 'Could not recalculate gain';
}
# Write gain value to device
sub _write_gain
{
$_[0]->{unit}->_write( 0x61 + ( log( $_[0]->{gain} ) / log(2) ) );
sleep 0.2;
$_[0]->{unit}->_write( 0x61 + ( log( $_[0]->{gain} ) / log(2) ) );
}
=back
=head1 INHERIT METHODS FROM
Device::USB::PCSensor::HidTEMPer::Sensor
=head1 DEPENDENCIES
This module internally includes and takes use of the following packages:
use Carp;
use Time::HiRes qw / sleep /;
use Device::USB::PCSensor::HidTEMPer::Sensor;
This module uses the strict and warning pragmas.
=head1 BUGS
Please report any bugs or missing features using the CPAN RT tool.
=head1 FOR MORE INFORMATION
None
=head1 AUTHOR
Magnus Sulland < msulland@cpan.org >
=head1 ACKNOWLEDGEMENTS
This code includes findings done by Robin B. Jensen,
http://www.drunkardswalk.dk, when converting the received hex values into
volt.
=head1 COPYRIGHT & LICENSE
Copyright (c) 2010 Magnus Sulland
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=cut
1;
__END__
Temperature, Calibrated key
-50,712.066
-49,661.926
-48,615.656
-47,572.934
-46,533.466
-45,496.983
-44,463.24
-43,432.015
-42,403.104
-41,376.32
-40,351.495
-39,328.472
-38,307.11
-37,287.279
-36,268.859
-35,251.741
-34,235.826
-33,221.021
-32,207.242
-31,194.412
-30,182.46
-29,171.32
-28,160.932
-27,151.241
-26,142.196
-25,133.75
-24,125.859
-23,118.485
-22,111.589
-21,105.139
-20,99.102
-19,93.45
-18,88.156
-17,83.195
-16,78.544
-15,74.183
-14,70.091
-13,66.25
-12,62.643
-11,59.255
-10,56.071
-9,53.078
-8,50.263
-7,47.614
-6,45.121
-5,42.774
-4,40.563
-3,38.48
-2,36.517,
-1,34.665,
0,32.919,
1,31.27,
2,29.715,
3,28.246,
4,26.858,
5,25.547,
6,24.307,
7,23.135,
8,22.026,
9,20.977,
10,19.987,
11,19.044,
12,18.154,
13,17.31,
14,16.51
15,15.752
16,15.034
17,14.352
18,13.705
19,13.09
20,12.507
21,11.953
22,11.427
23,10.927
24,10.452
25,10
26,9.57
27,9.161
28,8.771
29,8.401
30,8.048
31,7.712
32,7.391
33,7.086
34,6.795
35,6.518
36,6.254
37,6.001
38,5.761
39,5.531
40,5.311
41,5.102
42,4.902
43,4.71
44,4.528
45,4.353
46,4.186
47,4.026
48,3.874
49,3.728
50,3.588
51,3.454
52,3.326
53,3.203
54,3.085
55,2.973
56,2.865
57,2.761
58,2.662
59,2.567
60,2.476
61,2.388
62,2.304
63,2.223
64,2.146
65,2.072
66,2
67,1.932
68,1.866
69,1.803
70,1.742
71,1.684
72,1.627
73,1.573
74,1.521
75,1.471
76,1.423
77,1.377
78,1.332
79,1.289
80,1.248
81,1.208
82,1.17
83,1.133
84,1.097
85,1.063
86,1.03
87,0.998
88,0.968
89,0.938
90,0.909
91,0.882
92,0.855
93,0.829
94,0.805
95,0.781
96,0.758
97,0.735
98,0.714
99,0.693
100,0.673
101,0.653
102,0.635
103,0.616
104,0.599
105,0.582
106,0.565
107,0.55
108,0.534
109,0.519
110,0.505
111,0.491
112,0.478
113,0.465
114,0.452
115,0.44
116,0.428
117,0.416
118,0.405
119,0.395
120,0.384
121,0.374
122,0.364
123,0.355
124,0.345
125,0.337
126,0.328
127,0.319
128,0.311
129,0.303
130,0.296
131,0.288
132,0.281
133,0.274
134,0.267
135,0.261
136,0.254
137,0.248
138,0.242
139,0.236
140,0.23
141,0.225
142,0.219
143,0.214
144,0.209
145,0.204
146,0.199
147,0.195
148,0.19
149,0.186
150,0.181