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 #ifndef ARDUINO_AVR_MEGA2560
#error This program was written for an Atmega2560 #error This program was written for an Arduino Mega (Atmega2560)
#endif #endif
#include <EEPROM.h> #include <EEPROM.h>
@ -469,6 +469,9 @@ void loop() {
setParams(p); setParams(p);
} }
c.process();
d.process();
#if _MODBUS == 1 #if _MODBUS == 1
mb.process(); mb.process();
checkModbusParams(); checkModbusParams();
@ -482,6 +485,8 @@ void loop() {
bitClear(modbusData[1], 14); bitClear(modbusData[1], 14);
// Nachden die 'ReferenzZeit' erstmalig gesetzt wurde, wird dieses Bit gelöscht // Nachden die 'ReferenzZeit' erstmalig gesetzt wurde, wird dieses Bit gelöscht
bitClear(modbusData[1], 15); bitClear(modbusData[1], 15);
// Setze die Durchschnittswerte für die Messwerte zurück
c.resetAverageCounters();
_println("Der 12 Bit Timer wurde zurückgesetzt"); _println("Der 12 Bit Timer wurde zurückgesetzt");
} }
if (!timeStampOverflow && (millis() - timeStamp) / 100 > 0xFFF) { if (!timeStampOverflow && (millis() - timeStamp) / 100 > 0xFFF) {
@ -495,15 +500,13 @@ void loop() {
} }
modbusData[5] = (millis() - timeStamp) / 100; modbusData[5] = (millis() - timeStamp) / 100;
#endif // _MODBUS == #endif // _MODBUS ==
c.process();
d.process();
#if 0 #if 1
static unsigned long counter = 0; static unsigned long counter = 0;
static unsigned long tl = millis(); static unsigned long tl = millis();
if (millis() - tl > 1000) { if (millis() - tl > 1000) {
tl = millis(); tl = millis();
_print("Loops: "); _println(counter); _print("Loops / Sekunde: "); _println(counter);
counter = 0; counter = 0;
} else { } else {
counter++; 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. 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 # Modbus
## Coils - FC 1, 5, 15 ## Coils - FC 1, 5, 15
@ -78,7 +85,7 @@ Sollwerte:
Setzen der Referenzzeit: 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 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. - 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 #define _MY_STUFF_H_INCLUDED
#include "./DallasTemperature/DallasTemperature.h" #include "./DallasTemperature/DallasTemperature.h"
// #include <math.h> // NAN
#define _VERSION_MAJOR 0 #define _VERSION_MAJOR 0
#define _VERSION_MINOR 0 #define _VERSION_MINOR 0
@ -10,13 +9,26 @@
#define _VERSION_NUMBER _VERSION_MICRO | (_VERSION_MINOR << 6) | (_VERSION_MAJOR << 12) #define _VERSION_NUMBER _VERSION_MICRO | (_VERSION_MINOR << 6) | (_VERSION_MAJOR << 12)
#define _VERSION_STRING "v0.0.1" #define _VERSION_STRING "v0.0.1"
#define _DEBUG 1 #define _DEBUG 0
#define _DEBUG_SENSORS 0 #define _DEBUG_SENSORS 0
#define _MODBUS 1 #define _MODBUS 1
#if _DEBUG == 1 #if _DEBUG == 1
#define _print(x) Serial.print(x) #define _print(x) Serial.print(x)
#define _println(x) Serial.println(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 #if _DEBUG_SENSORS == 1
#define _prints(x) Serial.print(x) #define _prints(x) Serial.print(x)
#define _printsln(x) Serial.println(x) #define _printsln(x) Serial.println(x)
@ -29,6 +41,7 @@
#define _println(x) #define _println(x)
#define _prints(x) #define _prints(x)
#define _printsln(x) #define _printsln(x)
#define _printtime()
#endif #endif
#define _REGS_INFRONTOF_EVENTS 6 #define _REGS_INFRONTOF_EVENTS 6
@ -57,10 +70,10 @@ extern u16 modbusData[];
eventCounter++;\ eventCounter++;\
}\ }\
} }
#define _setModbusValue(index, val) modbusData[index] = val //#define _setModbusValue(index, val) modbusData[index] = val
#else #else
#define _setModbusValve(index, val) #define _setModbusValve(index, val)
#define _setModbusValue(index, val) //#define _setModbusValue(index, val)
#endif // _MODBUS == #endif // _MODBUS ==
#define _MODBUS_ADDR_MIN 1 #define _MODBUS_ADDR_MIN 1

View file

@ -58,7 +58,7 @@ void Controller::init(bool startup=false)
void Controller::process() void Controller::process()
{ {
if (_initOk && millis() - _lastConversion > _CONVERSION_DELAY) { if (_initOk && millis() - _lastConversion > _TEMP_CONVERSION_DELAY) {
_lastConversion = millis(); _lastConversion = millis();
_requestConversion = true; _requestConversion = true;
float temp = _dallas.getTempC(_tempAddr1); float temp = _dallas.getTempC(_tempAddr1);
@ -101,7 +101,9 @@ void Controller::process()
_setT1Valve(0, stateIdle); _setT1Valve(0, stateIdle);
_printsln(); _printsln();
} }
_setModbusValue(_MODBUS_T1_INDEX, _vals->t1); #if _MODBUS == 1
_averageTemperature1();
#endif
} else if (_requestConversion) { } else if (_requestConversion) {
_requestConversion = false; _requestConversion = false;
_dallas.requestTemperatures(); _dallas.requestTemperatures();
@ -126,7 +128,9 @@ void Controller::process()
_vals->p = (float) _rawP / 1.705f; // 1023 / 6 * 100 (0-5 1/100 bar) _vals->p = (float) _rawP / 1.705f; // 1023 / 6 * 100 (0-5 1/100 bar)
_prints(" (Gems), p: "); _prints(_vals->p); _prints(" (Gems), p: "); _prints(_vals->p);
} }
_setModbusValue(_MODBUS_P_INDEX, _vals->p); #if _MODBUS == 1
_averagePressure();
#endif
if (_vals->p != _SENSOR_FAULT && _params->cEn) { if (_vals->p != _SENSOR_FAULT && _params->cEn) {
switch (_pState) { switch (_pState) {
case stateIdle: case stateIdle:
@ -213,7 +217,81 @@ void Controller::_setPValves(States state)
} }
} }
// uint16_t Controller::_convertFloat(const float &x) #if _MODBUS == 1
// { void Controller::resetAverageCounters()
// return (uint16_t) (x * 100); {
// } _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 "../display/display.h"
#include "../common.h" #include "../common.h"
#define _CONVERSION_DELAY 800 #define _TEMP_CONVERSION_DELAY 800
#define _ANALOG_READ_DELAY 500 #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 class Controller
{ {
@ -23,13 +29,21 @@ private:
uint8_t _t1Pin; uint8_t _t1Pin;
uint8_t _t2Pin; 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; OneWire _oneWire;
DallasTemperature _dallas; DallasTemperature _dallas;
DeviceAddress _tempAddr1; DeviceAddress _tempAddr1;
enum States : uint8_t { enum States : uint8_t { stateIdle, stateRising, stateFalling };
stateIdle, stateRising, stateFalling
};
States _tState = stateIdle; States _tState = stateIdle;
States _pState = stateIdle; States _pState = stateIdle;
@ -39,11 +53,14 @@ private:
unsigned long _lastAnalogRead; unsigned long _lastAnalogRead;
uint16_t _rawP; uint16_t _rawP;
// void _setTState(States curr, States next);
// void _setPState(States curr, States next);
void _setT1Valve(uint8_t, States); void _setT1Valve(uint8_t, States);
void _setPValves(States); void _setPValves(States);
// uint16_t _convertFloat(const float &x);
#if _MODBUS == 1
void _averageTemperature1();
void _averageTemperature2();
void _averagePressure();
#endif
public: public:
Controller(const uint8_t pAnalaogPin, Controller(const uint8_t pAnalaogPin,
@ -61,6 +78,9 @@ private:
void init(bool startup=false); void init(bool startup=false);
void process(); void process();
#if _MODBUS == 1
void resetAverageCounters();
#endif
}; };
#endif // MY_CONTROLLER_H_INCLUDED #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() void Display::_select()
{ {
// _printtime("select screen");
setFont(_SEL_FONT); setFont(_SEL_FONT);
setFontRefHeightAll(); setFontRefHeightAll();
_inputValueActive = false; _inputValueActive = false;
@ -386,6 +387,7 @@ void Display::_home()
bool tState = _vStates->t1; bool tState = _vStates->t1;
// %u in sprintf() geht nur bis uint16_t // %u in sprintf() geht nur bis uint16_t
String baudStr(_modbusParams->baudrate); String baudStr(_modbusParams->baudrate);
// _printtime("homescreen");
firstPage(); firstPage();
do { do {
setFont(u8g2_font_fub20_tf); setFont(u8g2_font_fub20_tf);