RISC-V/V203F6P6/termistor/main.cpp

78 lines
3.6 KiB
C++
Raw Normal View History

2025-01-27 16:21:54 +01:00
#include "main.h"
/*********************************************************************************
* Měření teploty s nějakou lepší přesností není zase tak jednoduché. Nakonec byl
* jako čidlo zvolen NTC termistor polské výroby, kde výrobce zaručuje přesnost
* odporu a beta parametru 1%. Ten beta parametr je celkem použitelný v malém rozsahu
* teplot (10 - 70°C), z tabulky se ale dají spočítat koeficienty Steinhart-Hartových
* vzorců, které sedí ve větším rozsahu (viz adresář compute).
* Vlastní měření je celkem jednoduché - stačí udělat odporový dělič z napájecího
* napětí na zem pomocí přesného rezistoru (zde také 1%) 10k a NTC 10k (při 25°C)
* a jeho střed připojit na vstup ADC. Pak lze spočítat závislost teploty na
* hodnotě ADC jako funkci, pro inverzní funkci udělat aproximaci pomocí kubických splajnů
* a máme fakticky hotovo. Výhoda je, že to nezávisí na napájecím (referenčním) napětí.
*
* Protože tento procesor nemá koprocesor pohyblivé řádové čárky, dodělal jsem do toho
* potřebnou aritmetiku v pevné čárce (tedy v celých číslech). Protože koeficienty
* polynomů se liší o mnoho řá, bylo potřeba udělat bitové posuny poměrně variabilní.
* A celé to otestovat, jestli to někde nepřetéká. Pak lze zobazit teplotu na RS485
* na dvě desetinná místa a protože se teplota mění pomalu a je použit plovoucí průměr,
* zobrazení je stabilní.
*
* Aniž bych to nějak kalibroval, zdá se, že teplota celkem sedí na +/- 0.5°C.
* Ve vodě s ledem to ukazuje 0.50°C, moje tělesná teplota je pak 36.6°C.
*
* NOTE : Budič RS485 je pětivoltový, takže jeho výstup Rx data jsem připojil pro jistotu
* k procesoru přes odpor 1k. S tím, že záchytné diody přepětí nějak požerou.
* Ukazuje se, že to sice funguje, ale ADC pak dost kecá - nějak mu tam to zvýšené
* napětí proniká. Stačí pak přizemnit Rx procesoru (PA3) přes odpor 1.5 2k a problém
* zmizí.
**********************************************************************************/
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 },
};
/*********************************************************************************/
static FIFO<uint32_t, FIFOLEN> termring;
static const GpioClass led (GPIOB, 8);
static Usart serial (57600);
static RealOut cout;
static AdcDma adc;
static Average avg (termring);
static const SPLINE<array_size(measured)> spline (measured, false);
int main () {
led << true;
adc.attach(avg);
cout += serial;
int passcnt = 0;
for (;;) {
uint32_t value;
if (termring.Read (value)) {
// value je de facto posunuta doleva o 7, potřebujeme o 16 - rozdíl je tedy 9
const int32_t ivalue = static_cast<int32_t>(value << 9);
const real temperature = spline.interpolate(real(ivalue));
cout << "t = " << temperature << " °C\r\n";
const bool b = passcnt & 1;
led << b;
passcnt += 1;
}
}
return 0;
}