Browse Source

sns: ntc temperature returned as kelvin

also rework internals of the analog and ntc sensor classes to use
explicit delays and update it's comments
pull/2508/head
Maxim Prokhorov 2 years ago
parent
commit
c22b369c86
4 changed files with 105 additions and 82 deletions
  1. +53
    -44
      code/espurna/sensors/AnalogSensor.h
  2. +35
    -34
      code/espurna/sensors/NTCSensor.h
  3. +1
    -1
      code/espurna/system.cpp
  4. +16
    -3
      code/espurna/system.h

+ 53
- 44
code/espurna/sensors/AnalogSensor.h View File

@ -1,54 +1,63 @@
// -----------------------------------------------------------------------------
// Analog Sensor (maps to an analogRead)
// Analog Sensor
// Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
//
// Scaling support by Carlos Iván Conde Martín <ivan dot conde at gmail dot com>
// (original sensor was just the analogRead output)
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && (ANALOG_SUPPORT || NTC_SUPPORT || LDR_SUPPORT)
#pragma once
#include <algorithm>
#include "../espurna.h"
#include "../sensor.h"
#include "BaseSensor.h"
#include "BaseAnalogSensor.h"
class AnalogSensor : public BaseAnalogSensor {
public:
// ---------------------------------------------------------------------
// Public
// ---------------------------------------------------------------------
using Delay = espurna::duration::critical::Microseconds;
AnalogSensor() {
_count = 1;
_sensor_id = SENSOR_ANALOG_ID;
}
void setSamples(unsigned int samples) {
if (_samples > 0) _samples = samples;
void setSamples(size_t samples) {
_samples = std::clamp(samples, SamplesMin, SamplesMax);
}
void setDelay(Delay delay) {
_delay = std::clamp(delay, DelayMin, DelayMax);
}
void setDelay(unsigned long micros) {
_micros = micros;
void setDelay(uint16_t delay) {
setDelay(Delay{delay});
}
void setFactor(double factor) {
//DEBUG_MSG(("[ANALOG_SENSOR] Factor set to: %s \n"), String(factor,6).c_str());
_factor = factor;
}
void setOffset(double offset) {
//DEBUG_MSG(("[ANALOG_SENSOR] Factor set to: %s \n"), String(offset,6).c_str());
_offset = offset;
}
// ---------------------------------------------------------------------
unsigned int getSamples() {
size_t getSamples() {
return _samples;
}
unsigned long getDelay() {
return _micros;
espurna::duration::Microseconds getDelay() {
return _delay;
}
double getFactor() {
@ -90,7 +99,6 @@ class AnalogSensor : public BaseAnalogSensor {
}
// Current value for slot # index
// Changed return type as moving to scaled value
double value(unsigned char index) {
if (index == 0) return _read();
return 0;
@ -98,41 +106,42 @@ class AnalogSensor : public BaseAnalogSensor {
protected:
//CICM: this should be for raw values
// renaming protected function "_read" to "_rawRead"
unsigned int _rawRead() {
if (1 == _samples) return analogRead(0);
unsigned long sum = 0;
for (unsigned int i=0; i<_samples; i++) {
if (i>0) delayMicroseconds(_micros);
sum += analogRead(0);
static unsigned int _rawRead(size_t samples, Delay delay) {
unsigned int last { 0 };
unsigned int result { 0 };
for (size_t sample = 0; sample < samples; ++sample) {
const auto value = analogRead(0);
result = result + value - last;
last = value;
if (sample > 0) {
espurna::time::critical::delay(delay);
yield();
}
}
return sum / _samples;
return result;
}
unsigned int _rawRead() const {
return _rawRead(_samples, _delay);
}
//CICM: and proper read should be scalable and thus needs sign
//and decimal part
double _read() {
//Raw measure could also be a class variable with getter so that can
//be reported through MQTT, ...
unsigned int rawValue;
double scaledValue;
// Debugging doubles to string
//DEBUG_MSG(("[ANALOG_SENSOR] Started standard read, factor: %s , offset: %s, decimals: %d \n"), String(_factor).c_str(), String(_offset).c_str(), ANALOG_DECIMALS);
rawValue = _rawRead();
//DEBUG_MSG(("[ANALOG_SENSOR] Raw read received: %d \n"), rawValue);
scaledValue = _factor*rawValue + _offset;
//DEBUG_MSG(("[ANALOG_SENSOR] Scaled value result: %s \n"), String(scaledValue).c_str());
return scaledValue;
double _read() const {
return _withFactor(_rawRead());
}
double _withFactor(double value) const {
return _factor * value + _offset;
}
unsigned int _samples = 1;
unsigned long _micros = 0;
//CICM: for scaling and offset, also with getters and setters
double _factor = 1.0;
double _offset = 0.0;
static constexpr Delay DelayMin { 200 };
static constexpr Delay DelayMax { Delay::max() };
Delay _delay { DelayMin };
};
static constexpr size_t SamplesMin { 1 };
static constexpr size_t SamplesMax { 16 };
size_t _samples { SamplesMin };
#endif // SENSOR_SUPPORT && ANALOG_SUPPORT
double _factor { 1.0 };
double _offset { 0.0 };
};

+ 35
- 34
code/espurna/sensors/NTCSensor.h View File

@ -3,14 +3,14 @@
// Copyright (C) 2019 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && NTC_SUPPORT
#pragma once
#include "../espurna.h"
#include "../sensor.h"
#include "AnalogSensor.h"
extern "C" {
#include "../libs/fs_math.h"
#include "../libs/fs_math.h"
}
class NTCSensor : public AnalogSensor {
@ -32,15 +32,13 @@ class NTCSensor : public AnalogSensor {
void setUpstreamResistor(unsigned long resistance) {
_resistance_up = resistance;
if (_resistance_up > 0) _resistance_down = 0;
}
void setDownstreamResistor(unsigned long resistance) {
_resistance_down = resistance;
if (_resistance_down > 0) _resistance_up = 0;
}
void setR0(unsigned long resistance) {
void setR0(unsigned long resistance) override {
if (resistance > 0) _R0 = resistance;
}
@ -55,59 +53,64 @@ class NTCSensor : public AnalogSensor {
// ---------------------------------------------------------------------
// Descriptive name of the sensor
String description() {
String description() override {
return String("NTC @ TOUT");
}
// Descriptive name of the slot # index
String description(unsigned char index) {
String description(unsigned char) override {
return description();
}
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
String address(unsigned char index) override {
return String("0");
}
// Type for slot # index
unsigned char type(unsigned char index) {
unsigned char type(unsigned char index) override {
if (index == 0) return MAGNITUDE_TEMPERATURE;
return MAGNITUDE_NONE;
}
// Current value for slot # index
double value(unsigned char index) {
// Always in kelvins, adjust to C or F later
sensor::Unit units(unsigned char index) override {
if (index == 0) {
return sensor::Unit::Kelvin;
}
double temperature = 0;
return BaseSensor::units(index);
}
if (index == 0) {
// Previous version happened to use AnalogSensor readings with factor and offset applied
// In case it was useful, this should also support the scaling in calculations for T
void pre() override {
_last = _rawRead();
}
// sampled reading
double read = _read();
// Current value for slot # index
double value(unsigned char index) override {
if (index == 0) {
// Ru = (AnalogMax/c - 1) * Rd
static constexpr double AnalogMin { 0.0 };
static constexpr double AnalogMax { 1023.0 };
const double alpha { (AnalogMax / std::clamp(_last, AnalogMin, AnalogMax)) - 1.0 };
// Ru = (1023/c - 1) * Rd
double resistance;
double alpha = (1023.0 / read) - 1;
if (_resistance_down > 0) {
resistance = _resistance_down * alpha;
} else if (0 == alpha) {
resistance = _R0;
} else {
resistance = _resistance_up / alpha;
}
const double resistance = (_resistance_down > 0)
? (_resistance_down * alpha)
: ((_resistance_up > 0) && (alpha > 0.0))
? (_resistance_up / alpha)
: (_R0);
// 1/T = 1/T0 + 1/B * ln(R/R0)
temperature = fs_log(resistance / _R0);
temperature = (1.0 / _T0) + (temperature / _beta);
temperature = 1.0 / temperature - 273.15;
return 1.0 / ((1.0 / _T0) + (fs_log(resistance / _R0) / _beta));
}
return temperature;
return 0.0;
}
protected:
double _last = 0;
unsigned long _beta = NTC_BETA;
unsigned long _resistance_up = NTC_R_UP;
@ -116,5 +119,3 @@ class NTCSensor : public AnalogSensor {
double _T0 = NTC_T0;
};
#endif // SENSOR_SUPPORT && NTC_SUPPORT

+ 1
- 1
code/espurna/system.cpp View File

@ -142,7 +142,7 @@ uint32_t RandomDevice::operator()() const {
namespace time {
void blockingDelay(CoreClock::duration timeout, CoreClock::duration interval) {
auto start = CoreClock::now();
const auto start = CoreClock::now();
while (CoreClock::now() - start < timeout) {
delay(interval);
}


+ 16
- 3
code/espurna/system.h View File

@ -70,9 +70,24 @@ using Minutes = std::chrono::duration<uint32_t, std::ratio<60>>;
using Hours = std::chrono::duration<uint32_t, std::ratio<Minutes::period::num * 60>>;
using Days = std::chrono::duration<uint32_t, std::ratio<Hours::period::num * 24>>;
namespace critical {
using Microseconds = std::chrono::duration<uint16_t, std::micro>;
} // namespace critical
} // namespace duration
namespace time {
namespace critical {
// Wait for the specified amount of time *without* using SDK or Core timers.
// Supposedly, should be the same as a simple do-while loop.
inline void delay(duration::critical::Microseconds) __attribute__((always_inline));
inline void delay(duration::critical::Microseconds duration) {
::ets_delay_us(duration.count());
}
} // namespace critical
struct CpuClock {
using duration = espurna::duration::ClockCycles;
@ -161,8 +176,7 @@ inline CoreClock::time_point millis() {
return CoreClock::now();
}
// Attempt to sleep for N milliseconds, but this is allowed to be woken up at any point
// Attempt to sleep for N milliseconds, but this is allowed to be woken up at any point by the SDK
inline void delay(CoreClock::duration value) {
::delay(value.count());
}
@ -170,7 +184,6 @@ inline void delay(CoreClock::duration value) {
// Local implementation of 'delay' that will make sure that we wait for the specified
// time, even after being woken up. Allows to service Core tasks that are scheduled
// in-between context switches, where the interval controls the minimum sleep time.
void blockingDelay(CoreClock::duration timeout, CoreClock::duration interval);
void blockingDelay(CoreClock::duration timeout);


Loading…
Cancel
Save