Added support for average measurements

This commit is contained in:
Bruno Hütter 2020-12-03 19:04:27 +01:00
parent 93ef495c3c
commit 86139abc42
6 changed files with 147 additions and 24 deletions

View File

@ -1,5 +1,5 @@
#ifndef ARDUINO_AVR_MEGA2560
#error This program was written for an Atmega2560
#error This program was written for an Arduino Mega (Atmega2560)
#endif
#include <EEPROM.h>
@ -469,6 +469,9 @@ void loop() {
setParams(p);
}
c.process();
d.process();
#if _MODBUS == 1
mb.process();
checkModbusParams();
@ -482,6 +485,8 @@ void loop() {
bitClear(modbusData[1], 14);
// Nachden die 'ReferenzZeit' erstmalig gesetzt wurde, wird dieses Bit gelöscht
bitClear(modbusData[1], 15);
// Setze die Durchschnittswerte für die Messwerte zurück
c.resetAverageCounters();
_println("Der 12 Bit Timer wurde zurückgesetzt");
}
if (!timeStampOverflow && (millis() - timeStamp) / 100 > 0xFFF) {
@ -495,15 +500,13 @@ void loop() {
}
modbusData[5] = (millis() - timeStamp) / 100;
#endif // _MODBUS ==
c.process();
d.process();
#if 0
#if 1
static unsigned long counter = 0;
static unsigned long tl = millis();
if (millis() - tl > 1000) {
tl = millis();
_print("Loops: "); _println(counter);
_print("Loops / Sekunde: "); _println(counter);
counter = 0;
} else {
counter++;

View File

@ -4,6 +4,13 @@ Experimentelle Firmware für einen Tankregler, der die Temperatur und den Druck
Das Programm ist für den Atmega2560 (Arduino Mega 2560) geschrieben.
## Probleme
- ***Großes Problem:*** Während des Gedrückthaltens einer Menütaste am Regler blockiert das Programm fast (nur noch ca. 10 Loops / Sekunde). In diesem Fall funktioiert Modbus nicht mehr.
***### TODO - Das liegt an der Zeit, die gebraucht wird, um das Display zu beschreiben (70 - 100+ ms). Wenn praktisch dauernd das Display neu beschrieben wird, bleibt einfach keine Zeit für was anderes -- SCHNELL LEINE LÖSUNG FINDEN***
- Solange nur ein Kühlkreis implementiert ist, lässt sich das maximale Abfrageintervall (siehe Modbus-Holding-Register 0xC0; wenn _TEMP_CONVERSION_DELAY und _ANALOG_READ_DELAY nicht reduziert werden (800 bzw. 500 ms)) auf dem Wert des internen 12 Bit Timers halten (409,6 Sekunden), da der RAM wegen den Arrays zur Messwert-Mittelung schon jetzt gerade so ausreicht (Bei einem Test waren **nur noch 874 Bytes** für lokale Variablen über).
***### Temperatur-Mittelung wieder entfernen, da die Temperaturschwankungen BEI WEITEM nicht so stark sind wie die des Drucks?*** (Da der Drucksensor in einer Leitung außerhalb des Tanks sitzt, schwankt der Druck extrem beim Schalten der Druckventile)
# Modbus
## Coils - FC 1, 5, 15
@ -78,7 +85,7 @@ Sollwerte:
Setzen der Referenzzeit:
- ***0xC0***: Es muss ein vom vorigen Wert abweichender Wert (z.B. ein Zähler oder die 16 LSBs der UNIX-Zeit in Zehntelsekunden beim ersten Mal jedenfalls NICHT *0xFFFF*, da das Register damit initialisiert ist und kein Unterschied festgestellt werden könnte) übergeben werden. Der Regler verwendet diesen Wert prinzipiell für nichts, außer dass der interne 12 Bit-Timer (1/10 Sekunden) und der Event-Counter auf 0 zurückgesetzt werden (siehe Input-Register ***0x00*** und ***0x06***), wenn sich dieser Wert ändert. Der Master kann entweder
- ***0xC0***: Es muss ein vom vorigen Wert abweichender Wert (z.B. ein Zähler beim ersten Mal jedenfalls NICHT *0xFFFF*, da das Register damit initialisiert ist und kein Unterschied festgestellt werden könnte) übergeben werden. Der Regler verwendet diesen Wert prinzipiell für nichts, außer dass der interne 12 Bit-Timer (1/10 Sekunden) und der Event-Counter auf 0 zurückgesetzt werden (siehe Input-Register ***0x00*** und ***0x06***), wenn sich dieser Wert ändert. Der Master kann entweder
- den entsprechenden Zeitstempel im speichern, und den Zeitstempel der Antwort (siehe Input-Register ***0x06***) dazu addieren, um den tatsächlichen Zeitpunkt des Ereignisses zu ermitteln, oder
- den in ***0x05*** gespeicherten Referenzzeitpunkt (Zehntelsekunden seit Reglerstart bzw. letzter Referenzierung (siehe Holding-Register ***0xC0***)) mit dem Event-Zeitpunkt und dem aktuellen Zeitstempel des Masters gegenrechnen.

View File

@ -2,7 +2,6 @@
#define _MY_STUFF_H_INCLUDED
#include "./DallasTemperature/DallasTemperature.h"
// #include <math.h> // NAN
#define _VERSION_MAJOR 0
#define _VERSION_MINOR 0
@ -10,13 +9,26 @@
#define _VERSION_NUMBER _VERSION_MICRO | (_VERSION_MINOR << 6) | (_VERSION_MAJOR << 12)
#define _VERSION_STRING "v0.0.1"
#define _DEBUG 1
#define _DEBUG 0
#define _DEBUG_SENSORS 0
#define _MODBUS 1
#if _DEBUG == 1
#define _print(x) Serial.print(x)
#define _println(x) Serial.println(x)
struct _printTimeStruct {
_printTimeStruct(const char *text) : _text(text) {
_t0 = millis();
};
~_printTimeStruct() {
_print("Vergangene Millisekunden ["); _print(_text);
_print("]: "); _println(millis() - _t0);
};
private:
u32 _t0;
const char *_text;
};
#define _printtime(text) _printTimeStruct __printt(text)
#if _DEBUG_SENSORS == 1
#define _prints(x) Serial.print(x)
#define _printsln(x) Serial.println(x)
@ -29,6 +41,7 @@
#define _println(x)
#define _prints(x)
#define _printsln(x)
#define _printtime()
#endif
#define _REGS_INFRONTOF_EVENTS 6
@ -57,10 +70,10 @@ extern u16 modbusData[];
eventCounter++;\
}\
}
#define _setModbusValue(index, val) modbusData[index] = val
//#define _setModbusValue(index, val) modbusData[index] = val
#else
#define _setModbusValve(index, val)
#define _setModbusValue(index, val)
//#define _setModbusValue(index, val)
#endif // _MODBUS ==
#define _MODBUS_ADDR_MIN 1

View File

@ -58,7 +58,7 @@ void Controller::init(bool startup=false)
void Controller::process()
{
if (_initOk && millis() - _lastConversion > _CONVERSION_DELAY) {
if (_initOk && millis() - _lastConversion > _TEMP_CONVERSION_DELAY) {
_lastConversion = millis();
_requestConversion = true;
float temp = _dallas.getTempC(_tempAddr1);
@ -101,7 +101,9 @@ void Controller::process()
_setT1Valve(0, stateIdle);
_printsln();
}
_setModbusValue(_MODBUS_T1_INDEX, _vals->t1);
#if _MODBUS == 1
_averageTemperature1();
#endif
} else if (_requestConversion) {
_requestConversion = false;
_dallas.requestTemperatures();
@ -126,7 +128,9 @@ void Controller::process()
_vals->p = (float) _rawP / 1.705f; // 1023 / 6 * 100 (0-5 1/100 bar)
_prints(" (Gems), p: "); _prints(_vals->p);
}
_setModbusValue(_MODBUS_P_INDEX, _vals->p);
#if _MODBUS == 1
_averagePressure();
#endif
if (_vals->p != _SENSOR_FAULT && _params->cEn) {
switch (_pState) {
case stateIdle:
@ -213,7 +217,81 @@ void Controller::_setPValves(States state)
}
}
// uint16_t Controller::_convertFloat(const float &x)
// {
// return (uint16_t) (x * 100);
// }
#if _MODBUS == 1
void Controller::resetAverageCounters()
{
_print("Setze Zähler zurück (_t1_c: ");
_print(_t1_c); _print(", _t2_c: ");
_print(_t2_c); _print(", _p_c: ");
_print(_p_c); _println(")");
_t1_c = 0;
_t2_c = 0;
_p_c = 0;
_t1_of = false;
_t2_of = false;
_p_of = false;
}
inline void Controller::_averageTemperature1()
{
int32_t total = 0;
int16_t result = _SENSOR_FAULT;
u8 valid = 0;
u8 invalid = 0;
if (_t1_c >= _T_ARR_LEN) {
_t1_c = 0;
_t1_of = true;
}
// Falls das Array schon voll ist, wird es wieder vom Anfang befüllt
_t1_arr[_t1_c++] = _vals->t1;
// Dabei läuft die for-Schleife dann über alle Einträge, ansonsten nur bis zum aktuellen
u16 loopTill = (_t1_of) ? _T_ARR_LEN : _t1_c;
for (u16 i=0; i<loopTill; i++) {
if (_t1_arr[i] != _SENSOR_FAULT) {
total += _t1_arr[i];
valid++;
} else {
invalid++;
}
}
if (valid >= invalid) {
result = total / valid;
}
modbusData[_MODBUS_T1_INDEX] = result;
// _setModbusValue(_MODBUS_T1_INDEX, result);
}
inline void Controller::_averageTemperature2()
{
// noch nicht implementiert
}
inline void Controller::_averagePressure()
{
int32_t total = 0;
int16_t result = _SENSOR_FAULT;
u8 valid = 0;
u8 invalid = 0;
if (_p_c >= _P_ARR_LEN) {
_p_c = 0;
_p_of = true;
}
// Falls das Array schon voll ist, wird es wieder vom Anfang befüllt
_p_arr[_p_c++] = _vals->p;
// Dabei läuft die for-Schleife dann über alle Einträge, ansonsten nur bis zum aktuellen
u16 loopTill = (_p_of) ? _P_ARR_LEN : _p_c;
for (u16 i=0; i<_p_c; i++) {
if (_p_arr[i] != _SENSOR_FAULT) {
total += _p_arr[i];
valid++;
} else {
invalid++;
}
}
if (valid >= invalid) {
result = total / valid;
}
modbusData[_MODBUS_P_INDEX] = result;
// _setModbusValue(_MODBUS_P_INDEX, result);
}
#endif // _MODBUS == 1

View File

@ -6,8 +6,14 @@
#include "../display/display.h"
#include "../common.h"
#define _CONVERSION_DELAY 800
#define _TEMP_CONVERSION_DELAY 800
#define _ANALOG_READ_DELAY 500
// Maximal nötige Anzahl an Temperatur-Einträgen, bevor der interne 12 Bit Timer überläuft
#define _T_ARR_LEN (409600 / _TEMP_CONVERSION_DELAY) + 1
// Maximal nötige Anzahl an Druck-Einträgen, bevor der interne 12 Bit Timer überläuft
#define _P_ARR_LEN (409600 / _ANALOG_READ_DELAY) + 1
// #define _T_ARR_LEN 255
// #define _P_ARR_LEN 255
class Controller
{
@ -23,13 +29,21 @@ private:
uint8_t _t1Pin;
uint8_t _t2Pin;
int16_t _t1_arr[_T_ARR_LEN]; // Array, aus dem der Durchschnittswert ermittelt wird
u16 _t1_c = 0; // Anzahl der Einträge, aus denen der Durchschnitt gebildet wird
bool _t1_of = false; // Flag, die anzeigt, ob das _t1_arr-Array schon voll ist
// int16_t _t2_arr[_T_ARR_LEN]; // Array, aus dem der Durchschnittswert ermittelt wird
u16 _t2_c = 0; // Anzahl der Einträge, aus denen der Durchschnitt gebildet wird
bool _t2_of = false; // Flag, die anzeigt, ob das _t2_arr-Array schon voll ist
int16_t _p_arr[_P_ARR_LEN]; // Array, aus dem der Durchschnittswert ermittelt wird
u16 _p_c = 0; // Anzahl der Einträge, aus denen der Durchschnitt gebildet wird
bool _p_of = false; // Flag, die anzeigt, ob das _p_arr-Array schon voll ist
OneWire _oneWire;
DallasTemperature _dallas;
DeviceAddress _tempAddr1;
enum States : uint8_t {
stateIdle, stateRising, stateFalling
};
enum States : uint8_t { stateIdle, stateRising, stateFalling };
States _tState = stateIdle;
States _pState = stateIdle;
@ -39,11 +53,14 @@ private:
unsigned long _lastAnalogRead;
uint16_t _rawP;
// void _setTState(States curr, States next);
// void _setPState(States curr, States next);
void _setT1Valve(uint8_t, States);
void _setPValves(States);
// uint16_t _convertFloat(const float &x);
#if _MODBUS == 1
void _averageTemperature1();
void _averageTemperature2();
void _averagePressure();
#endif
public:
Controller(const uint8_t pAnalaogPin,
@ -61,6 +78,9 @@ private:
void init(bool startup=false);
void process();
#if _MODBUS == 1
void resetAverageCounters();
#endif
};
#endif // MY_CONTROLLER_H_INCLUDED

View File

@ -278,6 +278,7 @@ void Display::_select(const uint8_t selection, const bool restoreCursor=false)
void Display::_select()
{
// _printtime("select screen");
setFont(_SEL_FONT);
setFontRefHeightAll();
_inputValueActive = false;
@ -386,6 +387,7 @@ void Display::_home()
bool tState = _vStates->t1;
// %u in sprintf() geht nur bis uint16_t
String baudStr(_modbusParams->baudrate);
// _printtime("homescreen");
firstPage();
do {
setFont(u8g2_font_fub20_tf);