1 /*
2 * Author: Jon Trulson <jtrulson@ics.com>
3 * Copyright (c) 2015 Intel Corporation.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <iostream>
26 #include <string>
27 #include <stdexcept>
28
29 #include "otp538u.h"
30
31 #include "thermopile_vt_table.h"
32 #include "thermister_rt_table.h"
33
34 using namespace upm;
35 using namespace std;
36
OTP538U(int pinA,int pinO,float aref)37 OTP538U::OTP538U(int pinA, int pinO, float aref)
38 {
39 // this is the internal voltage reference on the Grove IR temp
40 // sensor module
41 m_vref = 2.5;
42
43 // analog reference in use
44 m_aref = aref;
45
46 // This is the value of the output resistor of the Grove IR
47 // temp sensor's SIG2 output (ambient)
48 m_vResistance = 2000000; // 2M ohms
49
50 // This was the default offset voltage in the seeedstudio code. You
51 // can adjust as neccessary depending on your calibration.
52 m_offsetVoltage = 0.014;
53
54 // We need around 1mV resolution, so use 12 bit resolution (4096)
55 // with a default aref of 5.0.
56 m_adcResolution = 4096;
57
58 if ( !(m_aioA = mraa_aio_init(pinA)) )
59 {
60 throw std::invalid_argument(std::string(__FUNCTION__) +
61 ": mraa_gpio_init(pinA) failed, invalid pin?");
62 return;
63 }
64
65 // enable 12 bit resolution
66 mraa_aio_set_bit(m_aioA, 12);
67
68 if ( !(m_aioO = mraa_aio_init(pinO)) )
69 {
70 throw std::invalid_argument(std::string(__FUNCTION__) +
71 ": mraa_gpio_init(pinO) failed, invalid pin?");
72 return;
73 }
74
75 // enable 12 bit resolution
76 mraa_aio_set_bit(m_aioO, 12);
77 }
78
~OTP538U()79 OTP538U::~OTP538U()
80 {
81 mraa_aio_close(m_aioA);
82 mraa_aio_close(m_aioO);
83 }
84
ambientTemperature()85 float OTP538U::ambientTemperature()
86 {
87 const int samples = 5;
88 int val = 0;
89 float temp = 0;
90 float res;
91
92 for (int i=0; i<samples; i++)
93 {
94 val = mraa_aio_read(m_aioA);
95 temp += val;
96 usleep(10000);
97 }
98
99 temp = temp / samples;
100 temp = temp * m_aref / m_adcResolution;
101
102 // compute the resistance of the thermistor
103 res = m_vResistance * temp / (m_vref - temp);
104
105 // look it up in the thermistor (RT) resistence/temperature table
106 int rawslot;
107 int j;
108 for (j=0; j<otp538u_rt_table_max; j++)
109 if (otp538u_rt_table[j] < res)
110 {
111 rawslot = j;
112 break;
113 }
114
115 if (j >= otp538u_rt_table_max)
116 {
117 throw std::out_of_range(std::string(__FUNCTION__) +
118 ": ambient temperature out of range.");
119 return 0;
120 }
121
122 // we need to compensate for the fact that we are supporting
123 // temperature values less than 0 (-20C), so adjust correspondingly
124 // so that we obtain the correct temperature 'slot'. This will be
125 // our base temperature.
126 int slot = rawslot - 20;
127
128 // too cold
129 if (slot < 0)
130 {
131 throw std::out_of_range(std::string(__FUNCTION__) +
132 ": ambient temperature out of range.");
133 return 0;
134 }
135
136 // now compute the ambient temperature
137 float ambientTemp = slot - 1 +
138 (otp538u_rt_table[rawslot - 1]-res) / (otp538u_rt_table[rawslot - 1] -
139 otp538u_rt_table[rawslot]);
140
141 return ambientTemp;
142 }
143
objectTemperature()144 float OTP538U::objectTemperature()
145 {
146 const int samples = 5;
147 const float reference_vol= 0.5; // what is this value? (from seeedstudio)
148 const float tempIncrement=10;
149 int val = 0;
150 float temp = 0;
151 float ambTemp = ambientTemperature();
152
153 for (int i=0; i<samples; i++)
154 {
155 val = mraa_aio_read(m_aioO);
156 temp += val;
157 usleep(10000);
158 }
159
160 temp = temp / samples;
161
162 float temp1 = temp * m_aref / m_adcResolution;
163 float sensorVolts = temp1 - (reference_vol + m_offsetVoltage);
164 // cout << "Sensor Voltage: " << sensorVolts << endl;
165
166 // search the VT (voltage/temperature) table to find the object
167 // temperature.
168 int slot;
169 // add +2 to compensate for the -20C and -10C slots below zero
170 int voltOffset = int(ambTemp / 10) + 1 + 2;
171 float voltage = sensorVolts * 10.0;
172 for (slot=0; slot<(otp538u_vt_table_max - 1); slot++)
173 {
174 if ( (voltage > otp538u_vt_table[slot][voltOffset]) &&
175 (voltage < otp538u_vt_table[slot+1][voltOffset]) )
176 {
177 break;
178 }
179 }
180
181 if (slot >= (otp538u_vt_table_max - 1))
182 {
183 throw std::out_of_range(std::string(__FUNCTION__) +
184 ": object temperature out of range.");
185 return 0;
186 }
187
188 float objTemp = (float(tempIncrement) * voltage) /
189 ( otp538u_vt_table[slot + 1][voltOffset] -
190 otp538u_vt_table[slot][voltOffset] );
191
192 // cout << "TABLE VALUE [" << slot << "][" <<
193 // voltOffset << "] = " << otp538u_vt_table[slot][voltOffset] << endl;
194
195 return (ambTemp + objTemp);
196 }
197