mirror of
https://github.com/eclipse/upm.git
synced 2025-03-15 04:57:30 +03:00
otp538u: C implementation; FTI; C++ wraps C
Signed-off-by: Jon Trulson <jtrulson@ics.com>
This commit is contained in:
parent
1aa748e3d6
commit
1630ebfca4
@ -134,6 +134,7 @@ add_example (mma7660)
|
||||
add_example (buzzer)
|
||||
add_example (ppd42ns)
|
||||
add_example (guvas12d)
|
||||
add_example (otp538u)
|
||||
|
||||
# Custom examples
|
||||
add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps)
|
||||
|
81
examples/c/otp538u.c
Normal file
81
examples/c/otp538u.c
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Author: Jon Trulson <jtrulson@ics.com>
|
||||
* Copyright (c) 2016 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <upm_utilities.h>
|
||||
#include <otp538u.h>
|
||||
|
||||
|
||||
bool shouldRun = true;
|
||||
|
||||
// analog voltage, usually 3.3 or 5.0
|
||||
#define OTP538U_AREF 5.0
|
||||
|
||||
void sig_handler(int signo)
|
||||
{
|
||||
if (signo == SIGINT)
|
||||
shouldRun = false;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
//! [Interesting]
|
||||
|
||||
// Instantiate a OTP538U on analog pins A0 and A1
|
||||
// A0 is used for the Ambient Temperature and A1 is used for the
|
||||
// Object temperature.
|
||||
otp538u_context temps = otp538u_init(0, 1, OTP538U_AREF);
|
||||
|
||||
// enable debugging if you would like
|
||||
// otp538u_set_debug(temps, true);
|
||||
|
||||
// Output ambient and object temperatures
|
||||
while (shouldRun)
|
||||
{
|
||||
float ambient = 0, object = 0;
|
||||
|
||||
if (otp538u_get_ambient_temperature(temps, &ambient))
|
||||
printf("otp538u_get_ambient_temperature() failed\n");
|
||||
else if (otp538u_get_object_temperature(temps, &object))
|
||||
printf("otp538u_get_object_temperature() failed\n");
|
||||
else
|
||||
printf("Ambient temp: %f C, Object temp: %f C\n",
|
||||
ambient, object);
|
||||
|
||||
printf("\n");
|
||||
upm_delay(1);
|
||||
}
|
||||
|
||||
printf("Exiting\n");
|
||||
|
||||
otp538u_close(temps);
|
||||
|
||||
//! [Interesting]
|
||||
return 0;
|
||||
}
|
@ -1,5 +1,9 @@
|
||||
set (libname "otp538u")
|
||||
set (libdescription "Otp538u IR temperature sensor")
|
||||
set (module_src ${libname}.cxx)
|
||||
set (module_hpp ${libname}.hpp)
|
||||
upm_module_init()
|
||||
upm_mixed_module_init (NAME otp538u
|
||||
DESCRIPTION "OTP538U Analog IR temperature sensor"
|
||||
C_HDR otp538u.h
|
||||
C_SRC otp538u.c
|
||||
CPP_HDR otp538u.hpp
|
||||
CPP_SRC otp538u.cxx
|
||||
FTI_SRC otp538u_fti.c
|
||||
CPP_WRAPS_C
|
||||
REQUIRES mraa)
|
||||
|
374
src/otp538u/otp538u.c
Normal file
374
src/otp538u/otp538u.c
Normal file
@ -0,0 +1,374 @@
|
||||
/*
|
||||
* Author: Jon Trulson <jtrulson@ics.com>
|
||||
* Copyright (c) 2016 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <upm_utilities.h>
|
||||
#include <upm_platform.h>
|
||||
|
||||
#include <otp538u.h>
|
||||
|
||||
#include "thermopile_vt_table.h"
|
||||
#include "thermister_rt_table.h"
|
||||
|
||||
|
||||
// To save memory space, we disable debugging on non-linux platforms
|
||||
// by default (Zephyr). For other systems, enable as desired/possible.
|
||||
#if defined(UPM_PLATFORM_LINUX)
|
||||
# define OTP538U_DEBUG_ENABLED
|
||||
#endif // UPM_PLATFORM_LINUX
|
||||
|
||||
otp538u_context otp538u_init(int pinA, int pinO, float aref)
|
||||
{
|
||||
otp538u_context dev =
|
||||
(otp538u_context)malloc(sizeof(struct _otp538u_context));
|
||||
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
memset((void *)dev, 0, sizeof(struct _otp538u_context));
|
||||
|
||||
// make sure MRAA is initialized
|
||||
int mraa_rv;
|
||||
if ((mraa_rv = mraa_init()) != MRAA_SUCCESS)
|
||||
{
|
||||
printf("%s: mraa_init() failed (%d).\n", __FUNCTION__, mraa_rv);
|
||||
otp538u_close(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// initialize the MRAA contexts
|
||||
|
||||
if (!(dev->aioA = mraa_aio_init(pinA)))
|
||||
{
|
||||
printf("%s: mraa_aio_init(pinA) failed.\n", __FUNCTION__);
|
||||
otp538u_close(dev);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(dev->aioO = mraa_aio_init(pinO)))
|
||||
{
|
||||
printf("%s: mraa_aio_init(pinO) failed.\n", __FUNCTION__);
|
||||
otp538u_close(dev);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// for subplatforms like the Arduino 101 with Firmata, we need to
|
||||
// limit ADC resolution to 10b currently. For this sensor
|
||||
// unfortunately, this means readings will be less accurate. This
|
||||
// sensor really does need to measure with about 1mV accuracy.
|
||||
const int adcHighRes = 4095;
|
||||
const int adcLowRes = 1023;
|
||||
|
||||
bool isSubplatform = false;
|
||||
|
||||
dev->debug = false;
|
||||
|
||||
if (pinA >= 512 || pinO >= 512)
|
||||
isSubplatform = true;
|
||||
|
||||
// this is the internal voltage reference on the Grove IR temp
|
||||
// sensor module for the thermistor.
|
||||
|
||||
dev->internalVRef = 2.5;
|
||||
|
||||
// analog reference in use
|
||||
dev->aref = aref;
|
||||
|
||||
// This is the value of the output resistor of the Grove IR
|
||||
// temp sensor's SIG2 output (ambient)
|
||||
dev->vResistance = 2000000; // 2M ohms
|
||||
|
||||
// This was the default offset voltage in the seeedstudio code. You
|
||||
// can adjust as neccessary depending on your calibration.
|
||||
dev->offsetVoltage = 0.014;
|
||||
|
||||
// We need around 1mV resolution (preferred), so use 12 bit
|
||||
// resolution (4096) if we can.
|
||||
//
|
||||
// This logic is over complicated due to the fact that it is
|
||||
// currently difficult to determine exactly what the capabilities of
|
||||
// the platform (sub or otherwise) actually are. So for
|
||||
// subplatforms, we always limit to 1024. Otherwise, we try 12b if
|
||||
// the mraa_adc_raw_bits() says we can, though this isn't
|
||||
// particularly accurate either, as it reports that the G2 can do
|
||||
// 12b, when in reality it can not. We are just lucky that it works
|
||||
// anyway (ie: will give 12b resolution, though underneath it's just
|
||||
// scaling the real 10b value.). Sigh. But trying 12b resolution
|
||||
// on the 101 via firmata will definitely break things, so don't
|
||||
// even try until whatever the problem it has with 12b is fixed.
|
||||
if (isSubplatform)
|
||||
{
|
||||
dev->adcResolution = adcLowRes; // 10b
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mraa_adc_raw_bits() == 12)
|
||||
dev->adcResolution = adcHighRes; // 12b
|
||||
else
|
||||
dev->adcResolution = adcLowRes; // 10b
|
||||
}
|
||||
|
||||
// notify the user
|
||||
if (dev->adcResolution == adcLowRes)
|
||||
printf("Using 10 bit ADC resolution. Values will be less accurate.\n");
|
||||
|
||||
// enable 12 bit resolution, if we can
|
||||
if (dev->adcResolution == adcHighRes)
|
||||
mraa_aio_set_bit(dev->aioA, 12);
|
||||
|
||||
if (dev->adcResolution == adcHighRes)
|
||||
mraa_aio_set_bit(dev->aioO, 12);
|
||||
|
||||
if (isSubplatform)
|
||||
{
|
||||
// The first analog read always seems to return 0 on the 101
|
||||
// with firmata, so just do a couple of reads here and discard
|
||||
// them. Then sleep for half a second. THIS IS A HACK. The
|
||||
// real problem should be fixed elsewhere (Firmata?).
|
||||
mraa_aio_read(dev->aioA);
|
||||
mraa_aio_read(dev->aioO);
|
||||
|
||||
upm_delay_ms(500);
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
void otp538u_close(otp538u_context dev)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
if (dev->aioA)
|
||||
mraa_aio_close(dev->aioA);
|
||||
if (dev->aioO)
|
||||
mraa_aio_close(dev->aioO);
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
upm_result_t otp538u_get_ambient_temperature(const otp538u_context dev,
|
||||
float *temperature)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
const int samples = 5;
|
||||
int val = 0;
|
||||
float temp = 0;
|
||||
float res = 0;
|
||||
|
||||
for (int i=0; i<samples; i++)
|
||||
{
|
||||
val = mraa_aio_read(dev->aioA);
|
||||
if (val == -1)
|
||||
{
|
||||
printf("%s: mraa_aio_read() failed.\n", __FUNCTION__);
|
||||
return UPM_ERROR_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
temp += (float)val;
|
||||
upm_delay_ms(10);
|
||||
}
|
||||
temp = temp / samples;
|
||||
|
||||
float volts = temp * dev->aref / dev->adcResolution;
|
||||
|
||||
#if defined(OTP538U_DEBUG_ENABLED)
|
||||
if (dev->debug)
|
||||
{
|
||||
printf("\tAMB sample %f aref %f volts %f\n", temp, dev->aref,
|
||||
volts);
|
||||
}
|
||||
#endif // OTP538U_DEBUG_ENABLED
|
||||
|
||||
// compute the resistance of the thermistor
|
||||
res = dev->vResistance * volts / (dev->internalVRef - volts);
|
||||
|
||||
#if defined(OTP538U_DEBUG_ENABLED)
|
||||
if (dev->debug)
|
||||
{
|
||||
printf("\tAMB computed resistance: %f\n", res);
|
||||
}
|
||||
#endif // OTP538U_DEBUG_ENABLED
|
||||
|
||||
// look it up in the thermistor (RT) resistence/temperature table
|
||||
int rawslot;
|
||||
int j;
|
||||
for (j=0; j<otp538u_rt_table_max; j++)
|
||||
if (otp538u_rt_table[j] < res)
|
||||
{
|
||||
rawslot = j;
|
||||
break;
|
||||
}
|
||||
|
||||
if (j >= otp538u_rt_table_max)
|
||||
{
|
||||
printf("%s: Ambient temperature out of range (high)\n", __FUNCTION__);
|
||||
return UPM_ERROR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
// we need to compensate for the fact that we are supporting
|
||||
// temperature values less than 0 (-20C), so adjust correspondingly
|
||||
// so that we obtain the correct temperature 'slot'. This will be
|
||||
// our base temperature.
|
||||
int slot = rawslot - 20;
|
||||
|
||||
// too cold
|
||||
if (slot < 0)
|
||||
{
|
||||
printf("%s: Ambient temperature out of range (low)\n", __FUNCTION__);
|
||||
return UPM_ERROR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
// now compute the ambient temperature
|
||||
float ambientTemp = slot - 1 +
|
||||
(otp538u_rt_table[rawslot - 1]-res) / (otp538u_rt_table[rawslot - 1] -
|
||||
otp538u_rt_table[rawslot]);
|
||||
|
||||
*temperature = ambientTemp;
|
||||
return UPM_SUCCESS;
|
||||
}
|
||||
|
||||
upm_result_t otp538u_get_object_temperature(const otp538u_context dev,
|
||||
float *temperature)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
const int samples = 5;
|
||||
const float reference_vol = 0.5; // what is this value? (from seeedstudio)
|
||||
const float tempIncrement = 10.0;
|
||||
int val = 0;
|
||||
float temp = 0;
|
||||
|
||||
float ambTemp = 0.0;
|
||||
if (otp538u_get_ambient_temperature(dev, &ambTemp))
|
||||
return UPM_ERROR_OPERATION_FAILED;
|
||||
|
||||
for (int i=0; i<samples; i++)
|
||||
{
|
||||
val = mraa_aio_read(dev->aioO);
|
||||
if (val == -1)
|
||||
{
|
||||
printf("%s: mraa_aio_read() failed.\n", __FUNCTION__);
|
||||
return UPM_ERROR_OPERATION_FAILED;
|
||||
}
|
||||
temp += val;
|
||||
upm_delay_ms(10);
|
||||
}
|
||||
|
||||
temp = temp / samples;
|
||||
|
||||
#if defined(OTP538U_DEBUG_ENABLED)
|
||||
if (dev->debug)
|
||||
printf("\tOBJ sample %f ", temp);
|
||||
#endif // OTP538U_DEBUG_ENABLED
|
||||
|
||||
float volts = temp * dev->aref / dev->adcResolution;
|
||||
|
||||
#if defined(OTP538U_DEBUG_ENABLED)
|
||||
if (dev->debug)
|
||||
printf("VOLTS: %f ", volts);
|
||||
#endif // OTP538U_DEBUG_ENABLED
|
||||
|
||||
float sensorVolts = volts - (reference_vol + dev->offsetVoltage);
|
||||
|
||||
#if defined(OTP538U_DEBUG_ENABLED)
|
||||
if (dev->debug)
|
||||
printf("Sensor Voltage (computed): %f\n", sensorVolts);
|
||||
#endif // OTP538U_DEBUG_ENABLED
|
||||
|
||||
// search the VT (voltage/temperature) table to find the object
|
||||
// temperature.
|
||||
int slot;
|
||||
// add +2 to compensate for the -20C and -10C slots below zero
|
||||
int voltOffset = (int)(ambTemp / 10) + 1 + 2;
|
||||
float voltage = sensorVolts * 10.0;
|
||||
for (slot=0; slot<(otp538u_vt_table_max - 1); slot++)
|
||||
{
|
||||
if ( (voltage > otp538u_vt_table[slot][voltOffset]) &&
|
||||
(voltage < otp538u_vt_table[slot+1][voltOffset]) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (slot >= (otp538u_vt_table_max - 1))
|
||||
{
|
||||
printf("%s: Object temperature out of range (high)\n", __FUNCTION__);
|
||||
return UPM_ERROR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
float objTemp = ((float)tempIncrement * voltage) /
|
||||
( otp538u_vt_table[slot + 1][voltOffset] -
|
||||
otp538u_vt_table[slot][voltOffset] );
|
||||
|
||||
#if defined(OTP538U_DEBUG_ENABLED)
|
||||
if (dev->debug)
|
||||
{
|
||||
printf("\tVoltage (%f): TABLE VALUE [%d][%d] = %f\n", voltage,
|
||||
slot, voltOffset, otp538u_vt_table[slot][voltOffset]);
|
||||
}
|
||||
#endif // OTP538U_DEBUG_ENABLED
|
||||
|
||||
*temperature = ambTemp + objTemp;
|
||||
return UPM_SUCCESS;
|
||||
}
|
||||
|
||||
void otp538u_set_voltage_offset(const otp538u_context dev, float offset)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
dev->offsetVoltage = offset;
|
||||
}
|
||||
|
||||
void otp538u_set_output_resistence(const otp538u_context dev,
|
||||
int resistance)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
dev->vResistance = resistance;
|
||||
}
|
||||
|
||||
void otp538u_set_ivref(const otp538u_context dev, float vref)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
dev->internalVRef = vref;
|
||||
}
|
||||
|
||||
void otp538u_set_debug(const otp538u_context dev, bool enable)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
dev->debug = enable;
|
||||
|
||||
#if !defined(UPM_PLATFORM_LINUX) && !defined(OTP538U_DEBUG_ENABLED)
|
||||
if (enable)
|
||||
printf("%s: Debugging not enabled at compilation time.\n",
|
||||
__FUNCTION__);
|
||||
#endif // !UPM_PLATFORM_LINUX && !OTP538U_DEBUG_ENABLED
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Author: Jon Trulson <jtrulson@ics.com>
|
||||
* Copyright (c) 2015 Intel Corporation.
|
||||
* Copyright (c) 2015-2016 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -28,258 +28,40 @@
|
||||
|
||||
#include "otp538u.hpp"
|
||||
|
||||
#include "thermopile_vt_table.hpp"
|
||||
#include "thermister_rt_table.hpp"
|
||||
|
||||
using namespace upm;
|
||||
using namespace std;
|
||||
|
||||
OTP538U::OTP538U(int pinA, int pinO, float aref)
|
||||
OTP538U::OTP538U(int pinA, int pinO, float aref) :
|
||||
m_otp538u(otp538u_init(pinA, pinO, aref))
|
||||
{
|
||||
const int adcHighRes = 4095;
|
||||
const int adcLowRes = 1023;
|
||||
|
||||
// for subplatforms like the Arduino 101, we need to limit ADC
|
||||
// resolution to 10b currently. For this sensor unfortunately, this
|
||||
// means readings will be less accurate. This sensor really does
|
||||
// need to measure with about 1mV accuracy.
|
||||
bool isSubplatform = false;
|
||||
|
||||
m_debug = false;
|
||||
|
||||
if (pinA >= 512 || pinO >= 512)
|
||||
isSubplatform = true;
|
||||
|
||||
// this is the internal voltage reference on the Grove IR temp
|
||||
// sensor module for the thermistor.
|
||||
|
||||
m_internalVRef = 2.5;
|
||||
|
||||
// analog reference in use
|
||||
m_aref = aref;
|
||||
|
||||
// This is the value of the output resistor of the Grove IR
|
||||
// temp sensor's SIG2 output (ambient)
|
||||
m_vResistance = 2000000; // 2M ohms
|
||||
|
||||
// This was the default offset voltage in the seeedstudio code. You
|
||||
// can adjust as neccessary depending on your calibration.
|
||||
m_offsetVoltage = 0.014;
|
||||
|
||||
// We need around 1mV resolution (preferred), so use 12 bit
|
||||
// resolution (4096) if we can.
|
||||
//
|
||||
// This logic is over complicated due to the fact that it is
|
||||
// currently difficult to determine exactly what the capabilities of
|
||||
// the platform (sub or otherwise) actually are. So for
|
||||
// subplatforms, we always limit to 1024. Otherwise, we try 12b if
|
||||
// the mraa_adc_raw_bits() says we can, though this isn't
|
||||
// particularly accurate either, as it reports that the G2 can do
|
||||
// 12b, when in reality it can not. We are just lucky that it works
|
||||
// anyway (ie: will give 12b resolution, though underneath it's just
|
||||
// scaling the real 10b value.). Sigh. But trying 12b resolution
|
||||
// on the 101 via firmata will definitely break things, so don't
|
||||
// even try until whatever the problem it has with 12b is fixed.
|
||||
if (isSubplatform)
|
||||
{
|
||||
m_adcResolution = adcLowRes; // 10b
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mraa_adc_raw_bits() == 12)
|
||||
m_adcResolution = adcHighRes; // 12b
|
||||
else
|
||||
m_adcResolution = adcLowRes; // 10b
|
||||
}
|
||||
|
||||
// notify the user
|
||||
if (m_adcResolution == adcLowRes)
|
||||
cerr << "Using 10 bit ADC resolution. Values will be less accurate."
|
||||
<< endl;
|
||||
|
||||
|
||||
if ( !(m_aioA = mraa_aio_init(pinA)) )
|
||||
{
|
||||
throw std::invalid_argument(std::string(__FUNCTION__) +
|
||||
": mraa_gpio_init(pinA) failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// enable 12 bit resolution, if we can
|
||||
if (m_adcResolution == adcHighRes)
|
||||
mraa_aio_set_bit(m_aioA, 12);
|
||||
|
||||
if ( !(m_aioO = mraa_aio_init(pinO)) )
|
||||
{
|
||||
throw std::invalid_argument(std::string(__FUNCTION__) +
|
||||
": mraa_gpio_init(pinO) failed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// enable 12 bit resolution, if we can
|
||||
if (m_adcResolution == adcHighRes)
|
||||
mraa_aio_set_bit(m_aioO, 12);
|
||||
|
||||
if (isSubplatform)
|
||||
{
|
||||
// The first analog read always seems to return 0 on the 101
|
||||
// with firmata, so just do a couple of reads here and discard
|
||||
// them. Then sleep for half a second. THIS IS A HACK. The
|
||||
// real problem should be fixed elsewhere (Firmata?).
|
||||
mraa_aio_read(m_aioA);
|
||||
mraa_aio_read(m_aioO);
|
||||
|
||||
usleep(500000);
|
||||
}
|
||||
if (!m_otp538u)
|
||||
throw std::runtime_error(std::string(__FUNCTION__) +
|
||||
": otp538u_init() failed");
|
||||
}
|
||||
|
||||
OTP538U::~OTP538U()
|
||||
{
|
||||
mraa_aio_close(m_aioA);
|
||||
mraa_aio_close(m_aioO);
|
||||
otp538u_close(m_otp538u);
|
||||
}
|
||||
|
||||
float OTP538U::ambientTemperature()
|
||||
{
|
||||
const int samples = 5;
|
||||
int val = 0;
|
||||
float temp = 0;
|
||||
float res = 0;
|
||||
|
||||
for (int i=0; i<samples; i++)
|
||||
{
|
||||
val = mraa_aio_read(m_aioA);
|
||||
if (val == -1) {
|
||||
if (otp538u_get_ambient_temperature(m_otp538u, &temp))
|
||||
throw std::runtime_error(std::string(__FUNCTION__) +
|
||||
": failed to do aio read");
|
||||
}
|
||||
temp += (float)val;
|
||||
usleep(10000);
|
||||
}
|
||||
temp = temp / samples;
|
||||
": otp538u_get_ambient_temperature() failed");
|
||||
|
||||
float volts = temp * m_aref / m_adcResolution;
|
||||
if (m_debug)
|
||||
{
|
||||
cerr << "\tAMB sample " << temp << " m_aref " << m_aref
|
||||
<< " VOLTS " << volts << endl;
|
||||
}
|
||||
|
||||
// compute the resistance of the thermistor
|
||||
res = m_vResistance * volts / (m_internalVRef - volts);
|
||||
|
||||
if (m_debug)
|
||||
{
|
||||
cerr << "\tAMB computed resistance: " << res << endl;
|
||||
}
|
||||
|
||||
// look it up in the thermistor (RT) resistence/temperature table
|
||||
int rawslot;
|
||||
int j;
|
||||
for (j=0; j<otp538u_rt_table_max; j++)
|
||||
if (otp538u_rt_table[j] < res)
|
||||
{
|
||||
rawslot = j;
|
||||
break;
|
||||
}
|
||||
|
||||
if (j >= otp538u_rt_table_max)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__) +
|
||||
": ambient temperature out of range (high).");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we need to compensate for the fact that we are supporting
|
||||
// temperature values less than 0 (-20C), so adjust correspondingly
|
||||
// so that we obtain the correct temperature 'slot'. This will be
|
||||
// our base temperature.
|
||||
int slot = rawslot - 20;
|
||||
|
||||
// too cold
|
||||
if (slot < 0)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__) +
|
||||
": ambient temperature out of range (low).");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// now compute the ambient temperature
|
||||
float ambientTemp = slot - 1 +
|
||||
(otp538u_rt_table[rawslot - 1]-res) / (otp538u_rt_table[rawslot - 1] -
|
||||
otp538u_rt_table[rawslot]);
|
||||
|
||||
return ambientTemp;
|
||||
return temp;
|
||||
}
|
||||
|
||||
float OTP538U::objectTemperature()
|
||||
{
|
||||
const int samples = 5;
|
||||
const float reference_vol= 0.5; // what is this value? (from seeedstudio)
|
||||
const float tempIncrement=10;
|
||||
int val = 0;
|
||||
float temp = 0;
|
||||
float ambTemp = ambientTemperature();
|
||||
|
||||
for (int i=0; i<samples; i++)
|
||||
{
|
||||
val = mraa_aio_read(m_aioO);
|
||||
if (val == -1) {
|
||||
if (otp538u_get_object_temperature(m_otp538u, &temp))
|
||||
throw std::runtime_error(std::string(__FUNCTION__) +
|
||||
": failed to do aio read.");
|
||||
return 0;
|
||||
}
|
||||
temp += val;
|
||||
usleep(10000);
|
||||
}
|
||||
": otp538u_get_object_temperature() failed");
|
||||
|
||||
temp = temp / samples;
|
||||
|
||||
if (m_debug)
|
||||
cerr << "\tOBJ sample " << temp << " ";
|
||||
|
||||
float volts = temp * m_aref / m_adcResolution;
|
||||
|
||||
if (m_debug)
|
||||
cerr << "VOLTS: " << volts << " ";
|
||||
|
||||
float sensorVolts = volts - (reference_vol + m_offsetVoltage);
|
||||
|
||||
if (m_debug)
|
||||
cerr << "Sensor Voltage (computed): " << sensorVolts << endl;
|
||||
|
||||
// search the VT (voltage/temperature) table to find the object
|
||||
// temperature.
|
||||
int slot;
|
||||
// add +2 to compensate for the -20C and -10C slots below zero
|
||||
int voltOffset = int(ambTemp / 10) + 1 + 2;
|
||||
float voltage = sensorVolts * 10.0;
|
||||
for (slot=0; slot<(otp538u_vt_table_max - 1); slot++)
|
||||
{
|
||||
if ( (voltage > otp538u_vt_table[slot][voltOffset]) &&
|
||||
(voltage < otp538u_vt_table[slot+1][voltOffset]) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (slot >= (otp538u_vt_table_max - 1))
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__) +
|
||||
": object temperature out of range.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
float objTemp = (float(tempIncrement) * voltage) /
|
||||
( otp538u_vt_table[slot + 1][voltOffset] -
|
||||
otp538u_vt_table[slot][voltOffset] );
|
||||
|
||||
if (m_debug)
|
||||
{
|
||||
cerr << "\tVoltage (" << voltage << "): TABLE VALUE [" << slot << "][" <<
|
||||
voltOffset << "] = " << otp538u_vt_table[slot][voltOffset] << endl;
|
||||
}
|
||||
|
||||
return (ambTemp + objTemp);
|
||||
return temp;
|
||||
}
|
||||
|
153
src/otp538u/otp538u.h
Normal file
153
src/otp538u/otp538u.h
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Author: Jon Trulson <jtrulson@ics.com>
|
||||
* Copyright (c) 2016 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <upm.h>
|
||||
#include <mraa/aio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file otp538u.h
|
||||
* @library otp538u
|
||||
* @brief C API for the OTP538U IR Temperature Sensor
|
||||
*
|
||||
* @include otp538u.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* device context
|
||||
*/
|
||||
typedef struct _otp538u_context
|
||||
{
|
||||
mraa_aio_context aioA;
|
||||
mraa_aio_context aioO;
|
||||
|
||||
bool debug;
|
||||
float internalVRef;
|
||||
float aref;
|
||||
int vResistance;
|
||||
float offsetVoltage;
|
||||
int adcResolution;
|
||||
} *otp538u_context;
|
||||
|
||||
|
||||
/**
|
||||
* OTP538U constructor
|
||||
*
|
||||
* @param pinA Analog pin to use for the ambient temperature
|
||||
* @param pinO Analog pin to use for the object temperature
|
||||
* @param aref Analog reference voltage
|
||||
* @return intialized context, or NULL if error
|
||||
*/
|
||||
otp538u_context otp538u_init(int pinA, int pinO, float aref);
|
||||
|
||||
/**
|
||||
* OTP538U destructor
|
||||
*
|
||||
* @param dev Device context
|
||||
*/
|
||||
void otp538u_close(otp538u_context dev);
|
||||
|
||||
/**
|
||||
* Gets the ambient temperature in Celsius
|
||||
*
|
||||
* @param dev Device context
|
||||
* @param temp Ambient temperature
|
||||
* @return UPM status
|
||||
*/
|
||||
upm_result_t otp538u_get_ambient_temperature(const otp538u_context dev,
|
||||
float *temperature);
|
||||
|
||||
/**
|
||||
* Gets the object temperature in Celsius
|
||||
*
|
||||
* @param dev Device context
|
||||
* @param temp Object temperature
|
||||
* @return UPM status
|
||||
*/
|
||||
upm_result_t otp538u_get_object_temperature(const otp538u_context dev,
|
||||
float *temperature);
|
||||
|
||||
/**
|
||||
* Sets the offset voltage
|
||||
*
|
||||
* The Seeed Studio wiki gives an example of calibrating the sensor
|
||||
* and calculating the offset voltage to apply. Currently, the
|
||||
* default value is set, but you can use the function to set one
|
||||
* of your own.
|
||||
*
|
||||
* @param dev Device context
|
||||
* @param vOffset Desired offset voltage
|
||||
*/
|
||||
void otp538u_set_voltage_offset(const otp538u_context dev, float offset);
|
||||
|
||||
/**
|
||||
* Sets the output resistance value
|
||||
*
|
||||
* The Seeed Studio wiki example uses a value of 2,000,000 in one of
|
||||
* the equations used to calculate voltage. The value is the
|
||||
* resistance of a resistor they use in the output stage of their
|
||||
* SIG2 output. This was 'decoded' by looking at the EAGLE* files
|
||||
* containing their schematics for this device.
|
||||
*
|
||||
* @param dev Device context
|
||||
* @param outResistance Value of the output resistor; default is 2M Ohm
|
||||
*/
|
||||
void otp538u_set_output_resistence(const otp538u_context dev,
|
||||
int resistance);
|
||||
|
||||
/**
|
||||
* Sets the reference voltage of the internal Seeed Studio voltage
|
||||
* regulator on the sensor board.
|
||||
*
|
||||
* The Seeed Studio wiki example uses a value of 2.5 in one of the
|
||||
* equations used to calculate the resistance of the ambient
|
||||
* thermistor. The value is the voltage of an internal voltage
|
||||
* regulator used on the sensor board. This was 'decoded' by
|
||||
* looking at the EAGLE files containing their schematics for this
|
||||
* device.
|
||||
*
|
||||
* @param dev Device context
|
||||
* @param vref Reference voltage of the internal sensor; default
|
||||
* is 2.5
|
||||
*/
|
||||
void otp538u_set_ivref(const otp538u_context dev, float vref);
|
||||
|
||||
/**
|
||||
* Enable debugging output (linux platforms only).
|
||||
*
|
||||
* @param dev Device context
|
||||
* @param true to enable some debug output, false otherwise
|
||||
*/
|
||||
void otp538u_set_debug(const otp538u_context dev, bool enable);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Author: Jon Trulson <jtrulson@ics.com>
|
||||
* Copyright (c) 2015 Intel Corporation.
|
||||
* Copyright (c) 2015-2016 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -24,7 +24,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <mraa/aio.h>
|
||||
#include <otp538u.h>
|
||||
|
||||
namespace upm {
|
||||
|
||||
@ -112,7 +112,10 @@ namespace upm {
|
||||
*
|
||||
* @param vOffset Desired offset voltage
|
||||
*/
|
||||
void setVoltageOffset(float vOffset) { m_offsetVoltage = vOffset; };
|
||||
void setVoltageOffset(float vOffset)
|
||||
{
|
||||
otp538u_set_voltage_offset(m_otp538u, vOffset);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the output resistance value
|
||||
@ -125,8 +128,10 @@ namespace upm {
|
||||
*
|
||||
* @param outResistance Value of the output resistor; default is 2M Ohm
|
||||
*/
|
||||
void setOutputResistence(int outResistance) {
|
||||
m_vResistance = outResistance; };
|
||||
void setOutputResistence(int outResistance)
|
||||
{
|
||||
otp538u_set_output_resistence(m_otp538u, outResistance);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the reference voltage of the internal Seeed Studio voltage
|
||||
@ -142,25 +147,24 @@ namespace upm {
|
||||
* @param vref Reference voltage of the internal sensor; default
|
||||
* is 2.5
|
||||
*/
|
||||
void setVRef(float vref) { m_internalVRef = vref; };
|
||||
void setVRef(float vref)
|
||||
{
|
||||
otp538u_set_ivref(m_otp538u, vref);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable debugging output.
|
||||
*
|
||||
* @param true to enable some debug output, false otherwise
|
||||
*/
|
||||
void setDebug(bool enable) { m_debug = enable; };
|
||||
void setDebug(bool enable)
|
||||
{
|
||||
otp538u_set_debug(m_otp538u, enable);
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
bool m_debug;
|
||||
float m_internalVRef;
|
||||
float m_aref;
|
||||
int m_vResistance;
|
||||
float m_offsetVoltage;
|
||||
int m_adcResolution;
|
||||
mraa_aio_context m_aioA;
|
||||
mraa_aio_context m_aioO;
|
||||
protected:
|
||||
otp538u_context m_otp538u;
|
||||
};
|
||||
}
|
||||
|
||||
|
116
src/otp538u/otp538u_fti.c
Normal file
116
src/otp538u/otp538u_fti.c
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Author: Jon Trulson <jtrulson@ics.com>
|
||||
* Copyright (c) 2016 Intel Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "otp538u.h"
|
||||
|
||||
#include "upm_fti.h"
|
||||
#include "upm_sensor.h"
|
||||
|
||||
/**
|
||||
* This file implements the Function Table Interface (FTI) for this sensor
|
||||
*/
|
||||
|
||||
const char upm_otp538u_name[] = "OTP538U";
|
||||
const char upm_otp538u_description[] = "IR Temperature Sensor";
|
||||
const upm_protocol_t upm_otp538u_protocol[] = {UPM_ANALOG, UPM_ANALOG};
|
||||
const upm_sensor_t upm_otp538u_category[] = {UPM_TEMPERATURE};
|
||||
|
||||
// forward declarations
|
||||
const upm_sensor_descriptor_t upm_otp538u_get_descriptor();
|
||||
const void* upm_otp538u_get_ft(upm_sensor_t sensor_type);
|
||||
upm_result_t upm_otp538u_get_value_temperature(void* dev, float* tempval,
|
||||
upm_temperature_u unit);
|
||||
void* upm_otp538u_init_name();
|
||||
void upm_otp538u_close(void* dev);
|
||||
|
||||
const upm_sensor_descriptor_t upm_otp538u_get_descriptor() {
|
||||
upm_sensor_descriptor_t usd;
|
||||
usd.name = upm_otp538u_name;
|
||||
usd.description = upm_otp538u_description;
|
||||
usd.protocol_size = 2;
|
||||
usd.protocol = upm_otp538u_protocol;
|
||||
usd.category_size = 1;
|
||||
usd.category = upm_otp538u_category;
|
||||
return usd;
|
||||
}
|
||||
|
||||
static const upm_sensor_ft ft =
|
||||
{
|
||||
.upm_sensor_init_name = &upm_otp538u_init_name,
|
||||
.upm_sensor_close = &upm_otp538u_close,
|
||||
.upm_sensor_get_descriptor = &upm_otp538u_get_descriptor
|
||||
};
|
||||
|
||||
static const upm_temperature_ft tft =
|
||||
{
|
||||
.upm_temperature_get_value = &upm_otp538u_get_value_temperature
|
||||
};
|
||||
|
||||
const void* upm_otp538u_get_ft(upm_sensor_t sensor_type) {
|
||||
if(sensor_type == UPM_SENSOR) {
|
||||
return &ft;
|
||||
}
|
||||
if(sensor_type == UPM_TEMPERATURE) {
|
||||
return &tft;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* upm_otp538u_init_name(){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void upm_otp538u_close(void* dev)
|
||||
{
|
||||
otp538u_close((otp538u_context)dev);
|
||||
}
|
||||
|
||||
upm_result_t upm_otp538u_get_value_temperature(void* dev, float* tempval,
|
||||
upm_temperature_u unit)
|
||||
{
|
||||
float temp = 0.0;
|
||||
upm_result_t rv = otp538u_get_object_temperature((otp538u_context)dev,
|
||||
&temp);
|
||||
|
||||
if (rv != UPM_SUCCESS)
|
||||
return rv;
|
||||
|
||||
switch (unit)
|
||||
{
|
||||
case CELSIUS:
|
||||
*tempval = temp;
|
||||
return UPM_SUCCESS;
|
||||
|
||||
case KELVIN:
|
||||
*tempval = temp + 273.15;
|
||||
return UPM_SUCCESS;
|
||||
|
||||
case FAHRENHEIT:
|
||||
*tempval = temp * (9.0/5.0) + 32.0;
|
||||
return UPM_SUCCESS;
|
||||
}
|
||||
|
||||
return UPM_ERROR_INVALID_PARAMETER;
|
||||
}
|
@ -28,7 +28,7 @@
|
||||
|
||||
static const int otp538u_rt_table_max = 121;
|
||||
|
||||
static int otp538u_rt_table[otp538u_rt_table_max] = {
|
||||
static int otp538u_rt_table[121] = {
|
||||
919730, 869299, 821942, 777454, 735644, 696336, 659365, 624578, 591834,
|
||||
561002, 531958, 504588, 478788, 454457, 431504, 409843, 389394, 370082,
|
||||
351839, 334598, 318300, 302903, 288329, 274533, 261471, 249100, 237381,
|
||||
@ -43,4 +43,3 @@ static int otp538u_rt_table[otp538u_rt_table_max] = {
|
||||
10926, 10587, 10260, 9945, 9641, 9347, 9063, 8789, 8525, 8270, 8023,
|
||||
7785, 7555, 7333, 7118, 6911
|
||||
};
|
||||
|
@ -30,7 +30,7 @@ static const int otp538u_vt_table_max = 23;
|
||||
// Thermistor temperature (C)
|
||||
// { -20 -10 0 10 20 30 40 50 60 70 80 90 100 }
|
||||
|
||||
static float otp538u_vt_table[otp538u_vt_table_max][13] = {
|
||||
static float otp538u_vt_table[23][13] = {
|
||||
// object temp (C)
|
||||
{0.000, -0.246, -0.523, -0.832, -1.177, -1.559, // -20C
|
||||
-1.981, -2.446, -2.957, -3.516, -4.126, -4.791, -5.513},
|
||||
@ -101,4 +101,3 @@ static float otp538u_vt_table[otp538u_vt_table_max][13] = {
|
||||
{13.284, 13.191, 13.068, 12.913, 12.722, 12.494, // 200
|
||||
12.225, 11.914, 11.557, 11.152, 10.695, 10.184, 9.616}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user