RISC-V/V203F6P6/thermometer/main.cpp
2025-02-01 10:40:34 +01:00

102 lines
3.5 KiB
C++

#include "pwmclass.h"
#include "fifo.h"
#include "player.h"
#include "GsmDecoder.h"
#include "oneway.h"
#include "gpio.h"
#include "adc.h"
#include "spline.h"
////////////////////////////////////////////////////////
/* Skutečně měří teplotu NTC termistorem. Výstup je PWM
* na pinu PA2 24kHz, enable PB1. Odvozeno z teploměru na
* https://github.com/Kizarm/TTSCP_Client/tree/main/kecal/stm
*/
////////////////////////////////////////////////////////
static constexpr Pair measured [] = { // pár hodnota ADC, teplota ve °C
{ +133.9, 125.000 },
{ +152.2, 120.000 },
{ +198.3, 110.000 },
{ +260.0, 100.000 },
{ +343.6, 90.000 },
{ +456.9, 80.000 },
{ +609.9, 70.000 },
{ +814.5, 60.000 },
{ +1082.6, 50.000 },
{ +1421.2, 40.000 },
{ +2047.5, 25.000 },
{ +2729.0, 10.000 },
{ +3139.8, 0.000 },
{ +3472.7, -10.000 },
{ +3715.6, -20.000 },
{ +3876.9, -30.000 },
{ +3960.2, -38.000 },
{ +3976.0, -40.000 },
};
class Average : public OneWay<uint16_t> {
FIFO<uint32_t, FIFOLEN> & ring;
uint32_t y, w;
public:
explicit Average (FIFO<uint32_t, FIFOLEN> & r) : OneWay(), ring(r), y(0u), w(0u) {}
unsigned int Send(uint16_t * const ptr, const unsigned int len) override {
unsigned suma = 0u;
for (unsigned n=0u; n<len; n++) {
suma += ptr [n];
}
y += suma - w; // ustálení teploty trvá dost dlouho, takže lze posílat klouzavý
w = y >> 4; // průměr s postupným zapomínáním. Hodnota je násobena délkou
// bufferu, t.j. 128 (posun doleva o 7)
if (w < (134 * 128)) return len; // skip limits - nezobrazuj mimo rozsah -40 až 120
if (w > (3976 * 128)) return len;
ring.Write (w);
return len;
}
};
static unsigned abs_diff (const int a, const int b) {
const int d = a - b;
return d > 0 ? +d : -d;
}
/////////////////////////// GSM kecátko /////////////////////////////
static GpioClass led (GPIOB, 8u);
static PwmClass pwm;
static FIFO<uint32_t, FIFOLEN> fifo;
static TextPlayer player (fifo, led);
static GsmDecoder decoder(fifo);
/////////////////////////// NTC teploměr /////////////////////////////
static GpioClass button (GPIOA, 0u, (GPIO_Speed_In | GPIO_UPDI_MPPO));
static AdcDma adc;
static FIFO<uint32_t, FIFOLEN> avgring;
static Average avg (avgring);
static const SPLINE<array_size(measured)> spline (measured, false);
int main () {
led << true;
pwm.attach (decoder);
adc.attach (avg);
int old_value = 0;
uint32_t average;
bool flush = true;
for (;;) {
if (flush) { // flush FIFO
led << true;
for (unsigned n=0u; n<FIFOLEN;) {
if (avgring.Read(average)) n += 1u;
}
flush = false;
led << false;
}
if (avgring.Read(average)) {
// average je de facto posunuta doleva o 7, potřebujeme o 16 - rozdíl je tedy 9
const int32_t ivalue = static_cast<int32_t>(average << 9);
const real rt = spline.interpolate(real(ivalue));
const int temperature = 100 * rt.x >> 16;
const unsigned delta = abs_diff (temperature, old_value);
if (delta >= 50u or !button) {
old_value = temperature;
player.say(old_value, 2); // s rozlišením na setiny
player.say(sayed_texts.units);
flush = true;
}
}
}
return 0;
}