codebase heavily refactored
This commit is contained in:
parent
636ec4df53
commit
cbb96f3015
|
@ -2,514 +2,163 @@
|
|||
#error This program was written for an Arduino Mega (Atmega2560)
|
||||
#endif
|
||||
|
||||
#include "src/common.h"
|
||||
#include "src/modbus/ModbusRTUSlave.h"
|
||||
#include <EEPROM.h>
|
||||
#include "src/OneWire/OneWire.h"
|
||||
#include "src/DallasTemperature/DallasTemperature.h"
|
||||
#include "src/display/display.h"
|
||||
#include "src/controller/controller.h"
|
||||
|
||||
const uint8_t BTN_PWR = 7;
|
||||
|
||||
modbusParameters modbusParams;
|
||||
parameters params; // Prozessparameter
|
||||
values vals; // aktuelle Messwerte
|
||||
ModbusParameters modbusParams;
|
||||
Parameters params; // Prozessparameter
|
||||
Values vals; // aktuelle Messwerte
|
||||
PSensor pSensor; // verwendeter Drucksensor
|
||||
valveStates vStates; // Zustände der Ausgänge
|
||||
bool paramsChangedByUI; // true, außer ein Wert wurde über Modbus geändert
|
||||
ValveStates vStates; // Zustände der Ausgänge
|
||||
|
||||
bool timeStampOverflow = false; // true, wenn mehr als 0xFFF Zehntelsekunden vergangen sind
|
||||
unsigned long timeStamp;
|
||||
u16 lastRefTime = 0xFFFF;
|
||||
|
||||
void checkParamINT16(int16_t *source, int16_t *target, const int &std, const int &min, const int &max) {
|
||||
_print("source: "); _print(*source);
|
||||
if (*source == _SENSOR_FAULT) {
|
||||
*source = *target = std;
|
||||
} else if (*source > max) {
|
||||
*source = *target = max;
|
||||
} else if (*source < min) {
|
||||
*source = *target = min;
|
||||
} else if (*source == min || *source == max) {
|
||||
*target = *source;
|
||||
} else {
|
||||
u8 mod = *source % 5;
|
||||
_print(", modulo: "); _print(mod);
|
||||
if (mod == 0)
|
||||
*target = *source;
|
||||
else {
|
||||
int tempVal = *source - mod;
|
||||
_print(", tempVal: "); _print(tempVal);
|
||||
if (mod > 2) { // runde auf den nächsten 5er Schritt bzw. setze auf max
|
||||
if ((tempVal + 5) > max) {
|
||||
*source = *target = max;
|
||||
_print(" ... auf max setzen");
|
||||
} else {
|
||||
*source = *target = tempVal + 5;
|
||||
_print(" ... aufrunden");
|
||||
}
|
||||
} else { // runde auf den vorigen 5er Schritt bzw. setze auf min
|
||||
if (tempVal < min) {
|
||||
*source = *target = min;
|
||||
_print(" ... auf min setzen");
|
||||
} else {
|
||||
*source = *target = tempVal;
|
||||
_print(" ... abrunden");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_print(", target: "); _print(*target); _print(", source: "); _println(*source);
|
||||
}
|
||||
|
||||
void checkParamUINT8(u8 *source, u8 *target, const u8 &std) {
|
||||
_print("checkParamUINT8 source vorher: "); _print(*source);
|
||||
if (*source > 1) {
|
||||
*source = *target = std;
|
||||
} else {
|
||||
*target = *source;
|
||||
}
|
||||
_print(", target: "); _print(*target); _print(", source: "); _println(*source);
|
||||
}
|
||||
u16 zones = 1; // Aktuell ist nur eine Kühlzone implementiert
|
||||
u32 currMillis;
|
||||
|
||||
#if _MODBUS == 1
|
||||
#include "src/modbus/ModbusRTUSlave.h"
|
||||
|
||||
u8 modbusStates[1]; // Bit0: tEn, Bit1: pInc, Bit2: pDec, Bit3: cEn
|
||||
u8 modbusValves[1]; // Bit0: Temp1, Bit1: Temp2, Bit2: Druck
|
||||
// 0: Event-Counter, 1: high: modbusValves[0], low: modbusStates[0], 2...4: Temp 1, 2, Druck, ab5: gespeicherte Schaltvorgänge
|
||||
u16 modbusData[_REGS_INFRONTOF_EVENTS + _MODBUS_MAX_EVENTS]; // Main Input Registers
|
||||
u16 modbusMiscReadable[2]; // Version, Kühlzonen
|
||||
u16 modbusSetpoints[6]; // Temp1, 2, Druck jeweils Sollwert + Hysterese
|
||||
u16 modbusRefTime[1]; // setzt bei Änderung Event-Counter und -Timer zurück
|
||||
|
||||
u8 &states = modbusStates[0];
|
||||
u8 &valves = modbusValves[0];
|
||||
u16 &eventCounter = modbusData[0];
|
||||
u16 &refTime = modbusRefTime[0];
|
||||
|
||||
ModbusRTUSlave mb(&Serial1, 2);
|
||||
|
||||
void checkParamBool(u8 &p, const u8 &bitNr, u8 *p2=nullptr) {
|
||||
u8 *p_ = (p2) ? p2 : &p;
|
||||
if (paramsChangedByUI) {
|
||||
_print("UI -> Modbus - vorher: "); _print(bitRead(modbusStates[0], bitNr));
|
||||
bitWrite(modbusStates[0], bitNr, *p_);
|
||||
_print(", nachher: "); _println(bitRead(modbusStates[0], bitNr));
|
||||
} else {
|
||||
_print("Modbus -> UI - vorher: "); _print(*p_);
|
||||
p = bitRead(modbusStates[0], bitNr);
|
||||
_print(", nachher: "); _println(p);
|
||||
}
|
||||
bitWrite(modbusData[1], bitNr, bitRead(modbusStates[0], bitNr));
|
||||
}
|
||||
|
||||
void checkModbusParams() {
|
||||
parameters p;
|
||||
if (modbusSetpoints[0] != params.ts1) {
|
||||
if (paramsChangedByUI) {
|
||||
_print("ts1 - UI -> Modbus - ");
|
||||
checkParamINT16(¶ms.ts1, (int16_t*)&modbusSetpoints[0], _STD_TEMP_SETPOINT, _MIN_TEMP_SETPOINT, _MAX_TEMP_SETPOINT);
|
||||
} else {
|
||||
_print("ts1 - Modbus -> UI - ");
|
||||
checkParamINT16((int16_t*)&modbusSetpoints[0], ¶ms.ts1, _STD_TEMP_SETPOINT, _MIN_TEMP_SETPOINT, _MAX_TEMP_SETPOINT);
|
||||
p.ts1 = params.ts1;
|
||||
}
|
||||
}
|
||||
if (modbusSetpoints[1] != params.th1) {
|
||||
if (paramsChangedByUI) {
|
||||
_print("th1 - UI -> Modbus - ");
|
||||
checkParamINT16(¶ms.th1, (int16_t*)&modbusSetpoints[1], _STD_TEMP_HYSTERESIS, _MIN_TEMP_HYSTERESIS, _MAX_TEMP_HYSTERESIS);
|
||||
} else {
|
||||
_print("th1 - Modbus -> UI - ");
|
||||
checkParamINT16((int16_t*)&modbusSetpoints[1], ¶ms.th1, _STD_TEMP_HYSTERESIS, _MIN_TEMP_HYSTERESIS, _MAX_TEMP_HYSTERESIS);
|
||||
p.th1 = params.th1;
|
||||
}
|
||||
}
|
||||
if (modbusSetpoints[4] != params.ps) {
|
||||
if (paramsChangedByUI) {
|
||||
_print("ps - UI -> Modbus - ");
|
||||
checkParamINT16(¶ms.ps, (int16_t*)&modbusSetpoints[4], _STD_P_SETPOINT, _MIN_P_SETPOINT, _MAX_P_SETPOINT);
|
||||
} else {
|
||||
_print("ps - Modbus -> UI - ");
|
||||
checkParamINT16((int16_t*)&modbusSetpoints[4], ¶ms.ps, _STD_P_SETPOINT, _MIN_P_SETPOINT, _MAX_P_SETPOINT);
|
||||
p.ps = params.ps;
|
||||
}
|
||||
}
|
||||
if (modbusSetpoints[5] != params.ph) {
|
||||
if (paramsChangedByUI) {
|
||||
_print("ph - UI -> Modbus - ");
|
||||
checkParamINT16(¶ms.ph, (int16_t*)&modbusSetpoints[5], _STD_P_HYSTERESIS, _MIN_P_HYSTERESIS, _MAX_P_HYSTERESIS);
|
||||
} else {
|
||||
_print("ph - Modbus -> UI - ");
|
||||
checkParamINT16((int16_t*)&modbusSetpoints[5], ¶ms.ph, _STD_P_HYSTERESIS, _MIN_P_HYSTERESIS, _MAX_P_HYSTERESIS);
|
||||
p.ph = params.ph;
|
||||
}
|
||||
}
|
||||
u8 bitNr = 0;
|
||||
if (bitRead(modbusStates[0], bitNr) != params.tEn) {
|
||||
_print("tEn - ");
|
||||
checkParamBool(p.tEn, bitNr, ¶ms.tEn);
|
||||
}
|
||||
bitNr++;
|
||||
if (bitRead(modbusStates[0], bitNr) != params.pInc) {
|
||||
_print("pInc - ");
|
||||
checkParamBool(p.pInc, bitNr, ¶ms.pInc);
|
||||
}
|
||||
bitNr++;
|
||||
if (bitRead(modbusStates[0], bitNr) != params.pDec) {
|
||||
_print("pDec - ");
|
||||
checkParamBool(p.pDec, bitNr, ¶ms.pDec);
|
||||
}
|
||||
bitNr++;
|
||||
if (bitRead(modbusStates[0], bitNr) != params.cEn) {
|
||||
_print("cEn - ");
|
||||
checkParamBool(p.cEn, bitNr, ¶ms.cEn);
|
||||
}
|
||||
if (!paramsChangedByUI) {
|
||||
setParams(p);
|
||||
}
|
||||
paramsChangedByUI = false;
|
||||
}
|
||||
#endif // _MODBUS ==
|
||||
|
||||
// EEPROM Adressen:
|
||||
|
||||
#define _EEPROM_OFFSET 0 // Falls sich die Register nicht mehr beschreiben lassen
|
||||
#define _EEPROM_MODBUS_ADDRESS 0 + _EEPROM_OFFSET // 1 byte
|
||||
#define _EEPROM_MODBUS_BAUDRATE 1 + _EEPROM_OFFSET // 4 bytes
|
||||
#define _EEPROM_MODBUS_DELAY 5 + _EEPROM_OFFSET // 1 byte
|
||||
#define _EEPROM_TEMP_SETPOINT 6 + _EEPROM_OFFSET // 4 bytes
|
||||
#define _EEPROM_TEMP_HYSTERESIS 10 + _EEPROM_OFFSET // 4 bytes
|
||||
#define _EEPROM_P_SETPOINT 14 + _EEPROM_OFFSET // 4 bytes
|
||||
#define _EEPROM_P_HYSTERESIS 18 + _EEPROM_OFFSET // 4 bytes
|
||||
#define _EEPROM_P_EN_INC 22 + _EEPROM_OFFSET // 1 byte
|
||||
#define _EEPROM_P_EN_DEC 23 + _EEPROM_OFFSET // 1 byte
|
||||
#define _EEPROM_P_SENSOR 24 + _EEPROM_OFFSET // 1 byte
|
||||
#define _EEPROM_BG_LIGHT 25 + _EEPROM_OFFSET // 1 byte
|
||||
#define _EEPROM_T_EN 26 + _EEPROM_OFFSET // 1 byte
|
||||
#define _EEPROM_CONTROL_EN 27 + _EEPROM_OFFSET // 1 byte
|
||||
|
||||
// cs, btnNext, btnPrev, btnSelect, btnCancel, bgLed, Parameter, Messwerte, Modbus, Drucksensor
|
||||
Display d(10, 3, 4, 5, 6, 9, ¶ms, &vals, &modbusParams, &pSensor, &vStates);
|
||||
// Analogeingang Druck, OneWire-Pin, Parameter, Messwerte, Display, Drucksensor, Ausgangszustände
|
||||
// nach vStates: t1Pin, t2Pin, pRisePin, pFallPin
|
||||
Controller c(A0, 8, ¶ms, &vals, &d, &pSensor, &vStates, 55, 56, 57, 58);
|
||||
|
||||
#if _MODBUS == 1
|
||||
void beginModbus() {
|
||||
mb.begin(modbusParams.address, modbusParams.baudrate);
|
||||
mb.waitWithAnswerMicroS = modbusParams.delay * 100; // 1/10 ms -> us
|
||||
}
|
||||
#endif
|
||||
|
||||
void getParams() {
|
||||
parameters p;
|
||||
EEPROM.get(_EEPROM_TEMP_SETPOINT, p.ts1);
|
||||
EEPROM.get(_EEPROM_TEMP_HYSTERESIS, p.th1);
|
||||
EEPROM.get(_EEPROM_P_SETPOINT, p.ps);
|
||||
EEPROM.get(_EEPROM_P_HYSTERESIS, p.ph);
|
||||
EEPROM.get(_EEPROM_P_EN_INC, p.pInc);
|
||||
EEPROM.get(_EEPROM_P_EN_DEC, p.pDec);
|
||||
EEPROM.get(_EEPROM_T_EN, p.tEn);
|
||||
EEPROM.get(_EEPROM_CONTROL_EN, p.cEn);
|
||||
_println("getParams() vor Validierung:");
|
||||
_print(" Temperatur Sollwert: "); _println(p.ts1);
|
||||
_print(" Temperatur Hysterese: "); _println(p.th1);
|
||||
_print(" Druck Sollwert: "); _println(p.ps);
|
||||
_print(" Druck Hysterese: "); _println(p.ph);
|
||||
_print(" Temp-Regelung aktiv: "); _println(p.tEn);
|
||||
_print(" Drucksteigerung aktiv: "); _println(p.pInc);
|
||||
_print(" Druckabfall aktiv: "); _println(p.pDec);
|
||||
_print(" Regler aktiv: "); _println(p.cEn);
|
||||
_print("ts1 - UI -> Modbus - ");
|
||||
checkParamINT16(&p.ts1, ¶ms.ts1, _STD_TEMP_SETPOINT, _MIN_TEMP_SETPOINT, _MAX_TEMP_SETPOINT);
|
||||
_print("th1 - UI -> Modbus - ");
|
||||
checkParamINT16(&p.th1, ¶ms.th1, _STD_TEMP_HYSTERESIS, _MIN_TEMP_HYSTERESIS, _MAX_TEMP_HYSTERESIS);
|
||||
_print("ps - UI -> Modbus - ");
|
||||
checkParamINT16(&p.ps, ¶ms.ps, _STD_P_SETPOINT, _MIN_P_SETPOINT, _MAX_P_SETPOINT);
|
||||
_print("ph - UI -> Modbus - ");
|
||||
checkParamINT16(&p.ph, ¶ms.ph, _STD_P_HYSTERESIS, _MIN_P_HYSTERESIS, _MAX_P_HYSTERESIS);
|
||||
_print("tEn - ");
|
||||
checkParamUINT8(&p.tEn, ¶ms.tEn, _STD_T_EN);
|
||||
_print("pInc - ");
|
||||
checkParamUINT8(&p.pInc, ¶ms.pInc, _STD_P_EN_INC);
|
||||
_print("pDec - ");
|
||||
checkParamUINT8(&p.pDec, ¶ms.pDec, _STD_P_EN_DEC);
|
||||
_print("cEn - ");
|
||||
checkParamUINT8(&p.cEn, ¶ms.cEn, _STD_C_EN);
|
||||
_println("getParams() nach Validierung:");
|
||||
_print(" Temperatur Sollwert: "); _println(params.ts1);
|
||||
_print(" Temperatur Hysterese: "); _println(params.th1);
|
||||
_print(" Druck Sollwert: "); _println(params.ps);
|
||||
_print(" Druck Hysterese: "); _println(params.ph);
|
||||
_print(" Temp-Regelung aktiv: "); _println(params.tEn);
|
||||
_print(" Drucksteigerung aktiv: "); _println(params.pInc);
|
||||
_print(" Druckabfall aktiv: "); _println(params.pDec);
|
||||
_print(" Regler aktiv: "); _println(params.cEn);
|
||||
}
|
||||
// cs, btnNext, btnPrev, btnSelect, btnCancel, bgLed
|
||||
Display display(10, 3, 4, 5, 6, 9);
|
||||
// Analogeingang Druck, OneWire-Pin, t1Pin, t2Pin, pRisePin, pFallPin
|
||||
Controller controller(A0, 8, 55, 56, 57, 58);
|
||||
|
||||
void setParams(parameters &p) {
|
||||
if (p.ts1 != _SENSOR_FAULT) {
|
||||
_print("ts1 alt: "); _print(params.ts1); _print(", neu: "); _println(p.ts1);
|
||||
checkParamINT16(&p.ts1, ¶ms.ts1, _STD_TEMP_SETPOINT, _MIN_TEMP_SETPOINT, _MAX_TEMP_SETPOINT);
|
||||
EEPROM.put(_EEPROM_TEMP_SETPOINT, params.ts1);
|
||||
}
|
||||
if (p.th1 != _SENSOR_FAULT) {
|
||||
_print("th1 alt: "); _print(params.th1); _print(", neu: "); _println(p.th1);
|
||||
checkParamINT16(&p.th1, ¶ms.th1, _STD_TEMP_HYSTERESIS, _MIN_TEMP_HYSTERESIS, _MAX_TEMP_HYSTERESIS);
|
||||
EEPROM.put(_EEPROM_TEMP_HYSTERESIS, params.th1);
|
||||
}
|
||||
if (p.ps != _SENSOR_FAULT) {
|
||||
_print("ps alt: "); _print(params.ps); _print(", neu: "); _println(p.ps);
|
||||
checkParamINT16(&p.ps, ¶ms.ps, _STD_P_SETPOINT, _MIN_P_SETPOINT, _MAX_P_SETPOINT);
|
||||
EEPROM.put(_EEPROM_P_SETPOINT, params.ps);
|
||||
}
|
||||
if (p.ph != _SENSOR_FAULT) {
|
||||
_print("ph alt: "); _print(params.ph); _print(", neu: "); _println(p.ph);
|
||||
checkParamINT16(&p.ph, ¶ms.ph, _STD_P_HYSTERESIS, _MIN_P_HYSTERESIS, _MAX_P_HYSTERESIS);
|
||||
EEPROM.put(_EEPROM_P_HYSTERESIS, params.ph);
|
||||
}
|
||||
if (p.pInc < 2) {
|
||||
_print("pInc alt: "); _print(params.pInc); _print(", neu: "); _println(p.pInc);
|
||||
params.pInc = p.pInc;
|
||||
EEPROM.put(_EEPROM_P_EN_INC, params.pInc);
|
||||
}
|
||||
if (p.pDec < 2) {
|
||||
_print("pDec alt: "); _print(params.pDec); _print(", neu: "); _println(p.pDec);
|
||||
params.pDec = p.pDec;
|
||||
EEPROM.put(_EEPROM_P_EN_DEC, params.pDec);
|
||||
}
|
||||
if (p.tEn < 2) {
|
||||
_print("tEn alt: "); _print(params.tEn); _print(", neu: "); _println(p.tEn);
|
||||
params.tEn = p.tEn;
|
||||
EEPROM.put(_EEPROM_T_EN, params.tEn);
|
||||
}
|
||||
if (p.cEn < 2) {
|
||||
_print("cEn alt: "); _print(params.cEn); _print(", neu: "); _println(p.cEn);
|
||||
params.cEn = p.cEn;
|
||||
EEPROM.put(_EEPROM_CONTROL_EN, params.cEn);
|
||||
}
|
||||
paramsChangedByUI = true;
|
||||
}
|
||||
|
||||
void getModbusParams() {
|
||||
uint8_t addr = EEPROM.read(_EEPROM_MODBUS_ADDRESS);
|
||||
if (addr < _MODBUS_ADDR_MIN || addr > _MODBUS_ADDR_MAX)
|
||||
modbusParams.address = _MODBUS_ADDR_MIN;
|
||||
else
|
||||
modbusParams.address = addr;
|
||||
uint32_t baudrate;
|
||||
EEPROM.get(_EEPROM_MODBUS_BAUDRATE, baudrate);
|
||||
switch (baudrate) {
|
||||
case 115200: break;
|
||||
case 57600: break;
|
||||
case 38400: break;
|
||||
case 19200: break;
|
||||
case 9600: break;
|
||||
case 4800: break;
|
||||
case 2400: break;
|
||||
case 1200: break;
|
||||
case 300: break;
|
||||
default: baudrate = 9600;
|
||||
}
|
||||
modbusParams.baudrate = baudrate;
|
||||
uint8_t delay_ = EEPROM.read(_EEPROM_MODBUS_DELAY);
|
||||
if (delay_ < _MODBUS_DELAY_MIN)
|
||||
modbusParams.delay = _MODBUS_DELAY_MIN;
|
||||
else if (delay_ > _MODBUS_DELAY_MAX)
|
||||
modbusParams.delay = _MODBUS_DELAY_MAX;
|
||||
else
|
||||
modbusParams.delay = delay_;
|
||||
}
|
||||
|
||||
void setModbusParams(const modbusParameters &p) {
|
||||
bool changed = false;
|
||||
if (p.address <= _MODBUS_ADDR_MAX) {
|
||||
EEPROM.put(_EEPROM_MODBUS_ADDRESS, p.address);
|
||||
modbusParams.address = p.address;
|
||||
changed = true;
|
||||
}
|
||||
if (p.baudrate != _MODBUS_INVALID_BAUDRATE) {
|
||||
EEPROM.put(_EEPROM_MODBUS_BAUDRATE, p.baudrate);
|
||||
modbusParams.baudrate = p.baudrate;
|
||||
changed = true;
|
||||
}
|
||||
if (p.delay <= _MODBUS_DELAY_MAX) {
|
||||
EEPROM.put(_EEPROM_MODBUS_DELAY, p.delay);
|
||||
modbusParams.delay = p.delay;
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
#if _MODBUS == 1
|
||||
beginModbus();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
PSensor getPSensor() {
|
||||
uint8_t val;
|
||||
EEPROM.get(_EEPROM_P_SENSOR, val);
|
||||
switch (val) {
|
||||
case SMC_1_5V_0_5BAR:
|
||||
pSensor = SMC_1_5V_0_5BAR;
|
||||
break;
|
||||
case GEMS_0_5V_0_6BAR:
|
||||
pSensor = GEMS_0_5V_0_6BAR;
|
||||
break;
|
||||
default:
|
||||
pSensor = SMC_1_5V_0_5BAR;
|
||||
EEPROM.put(_EEPROM_P_SENSOR, pSensor);
|
||||
}
|
||||
return pSensor;
|
||||
}
|
||||
|
||||
void setPSensor(const PSensor &sensor) {
|
||||
EEPROM.put(_EEPROM_P_SENSOR, sensor);
|
||||
pSensor = sensor;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
void setup()
|
||||
{
|
||||
#if _DEBUG == 1
|
||||
Serial.begin(115200);
|
||||
Serial.begin(115200);
|
||||
#endif
|
||||
|
||||
pinMode(53, OUTPUT); // Mega CS-Pin (um Slave-Betrieb zu vermeiden)
|
||||
pinMode(BTN_PWR, INPUT_PULLUP);
|
||||
pinMode(53, OUTPUT); // Mega CS-Pin (um Slave-Betrieb zu vermeiden)
|
||||
|
||||
paramsChangedByUI = true;
|
||||
display.init();
|
||||
display.bgLight(true);
|
||||
|
||||
d.init();
|
||||
d.bgLight(true);
|
||||
d.setModbusParams = setModbusParams;
|
||||
d.setPSensor = setPSensor;
|
||||
d.setParams = setParams;
|
||||
getModbusParams();
|
||||
_printf("ModbusAddress: ");
|
||||
_println(modbusParams.address);
|
||||
_printf("ModbusBaudrate: ");
|
||||
_println(modbusParams.baudrate);
|
||||
getPSensor();
|
||||
getParams();
|
||||
getFaultSettings();
|
||||
|
||||
getModbusParams();
|
||||
_print("ModbusAddress: ");
|
||||
_println(modbusParams.address);
|
||||
_print("ModbusBaudrate: ");
|
||||
_println(modbusParams.baudrate);
|
||||
getPSensor();
|
||||
getParams();
|
||||
|
||||
pinMode(BTN_PWR, INPUT_PULLUP);
|
||||
u16 powerOnCount;
|
||||
EEPROM.get(_EEPROM_POWERON_COUNT, powerOnCount);
|
||||
switch (powerOnCount) {
|
||||
case 0:
|
||||
case 0xFFFF:
|
||||
powerOnCount = 1;
|
||||
break;
|
||||
case 0xFFFE:
|
||||
break;
|
||||
default:
|
||||
powerOnCount++;
|
||||
}
|
||||
EEPROM.put(_EEPROM_POWERON_COUNT, powerOnCount);
|
||||
|
||||
#if _MODBUS == 1
|
||||
bool modbusFail = false;
|
||||
if (!mb.addDiscreteInputArea(0xD0, modbusValves, 1))
|
||||
modbusFail = true;
|
||||
if (!modbusFail && !mb.addHoldingRegisterArea(0xA0, modbusSetpoints, 6))
|
||||
modbusFail = true;
|
||||
if (!modbusFail && !mb.addCoilArea(0xB0, modbusStates, 1))
|
||||
modbusFail = true;
|
||||
if (!modbusFail && !mb.addHoldingRegisterArea(0xC0, modbusRefTime, 1))
|
||||
modbusFail = true;
|
||||
if (!modbusFail && !mb.addInputRegisterArea(0x00, modbusData, _REGS_INFRONTOF_EVENTS + _MODBUS_MAX_EVENTS))
|
||||
modbusFail = true;
|
||||
if (!modbusFail && !mb.addInputRegisterArea(0xF0, modbusMiscReadable, 2))
|
||||
modbusFail = true;
|
||||
if (modbusFail) {
|
||||
d.modbusProblem();
|
||||
while(1);
|
||||
}
|
||||
modbusData[0] = 0; // EventCounter
|
||||
modbusData[1] = 0x8000; // setze das MSB. Das Bit wird durch setzen von modbusRefTime[0] zurückgesetzt
|
||||
modbusData[2] = _SENSOR_FAULT; // Temp1 in 100stel-°C
|
||||
modbusData[3] = _SENSOR_FAULT; // Temp2 in 100stel-°C, noch nicht implementiert
|
||||
modbusData[4] = _SENSOR_FAULT; // Druck in 100stel bar
|
||||
modbusData[5] = 0; // Zehntelsekunden seit Reglerstart / letzter Referenzierung
|
||||
modbusMiscReadable[0] = _VERSION_NUMBER;
|
||||
modbusMiscReadable[1] = 1; // Aktuell ist nur eine Kühlzone implementiert
|
||||
modbusRefTime[0] = 0xFFFF;
|
||||
beginModbus();
|
||||
setupModbus(powerOnCount);
|
||||
mb.callbackCoil = modbusCallbackCoil;
|
||||
mb.callbackRegister = modbusCallbackRegister;
|
||||
#endif
|
||||
|
||||
d.greeting();
|
||||
display.greeting();
|
||||
|
||||
delay(1000);
|
||||
c.init(true);
|
||||
if (params.cEn)
|
||||
d.bgLight(true);
|
||||
else
|
||||
d.bgLight(100);
|
||||
|
||||
timeStamp = millis();
|
||||
}
|
||||
|
||||
bool readPwrBtn() {
|
||||
const uint8_t debounceDelay = 20;
|
||||
static unsigned long lastDebounceTime;
|
||||
static bool lastBounceState;
|
||||
static bool steadyState;
|
||||
bool currentState = !digitalRead(BTN_PWR);
|
||||
if (currentState != lastBounceState) {
|
||||
lastDebounceTime = millis();
|
||||
lastBounceState = currentState;
|
||||
}
|
||||
if ((millis() - lastDebounceTime) > debounceDelay)
|
||||
steadyState = currentState;
|
||||
if (steadyState && (millis() - lastDebounceTime) > 3000)
|
||||
d.reset();
|
||||
return steadyState;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static bool pwrBtnPressed;
|
||||
bool currentPwrBtnState = readPwrBtn();
|
||||
if (!pwrBtnPressed && currentPwrBtnState) {
|
||||
_println("pwrButton pressed");
|
||||
pwrBtnPressed = true;
|
||||
} else if(pwrBtnPressed && !currentPwrBtnState) {
|
||||
_println("pwrButton released");
|
||||
pwrBtnPressed = false;
|
||||
parameters p;
|
||||
p.cEn = !params.cEn;
|
||||
if (p.cEn)
|
||||
d.bgLight(true);
|
||||
delay(1000);
|
||||
controller.init(true);
|
||||
if (params.cEn)
|
||||
display.bgLight(true);
|
||||
else
|
||||
d.bgLight(100);
|
||||
setParams(p);
|
||||
}
|
||||
display.bgLight(100);
|
||||
|
||||
c.process();
|
||||
d.process();
|
||||
_printf("Gespeicherte Alarme: "); _println(faults.count());
|
||||
|
||||
timeStamp = millis();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
currMillis = millis();
|
||||
static bool pwrBtnPressed;
|
||||
bool currentPwrBtnState = readPwrBtn();
|
||||
if (!pwrBtnPressed && currentPwrBtnState) {
|
||||
_printlnf("pwrButton pressed");
|
||||
pwrBtnPressed = true;
|
||||
} else if(pwrBtnPressed && !currentPwrBtnState) {
|
||||
_printlnf("pwrButton released");
|
||||
pwrBtnPressed = false;
|
||||
Parameters p;
|
||||
p.cEn = !params.cEn;
|
||||
setParams(p, true);
|
||||
}
|
||||
|
||||
controller.process();
|
||||
display.process();
|
||||
|
||||
#if _MODBUS == 1
|
||||
mb.process();
|
||||
checkModbusParams();
|
||||
if (refTime != lastRefTime) {
|
||||
lastRefTime = refTime;
|
||||
timeStamp = millis();
|
||||
modbusData[5] = 0;
|
||||
eventCounter = 0;
|
||||
timeStampOverflow = false;
|
||||
// Setze das 'Timer-Überlauf'-Bit zurück (falls es gesetzt war)
|
||||
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) {
|
||||
#if _DEBUG == 1
|
||||
u16 passed = (millis() - timeStamp) / 100;
|
||||
_print("Der 12 Bit Timer ist übergelaufen. Vergangene Sekunden: ");
|
||||
_print(passed / 10); _print("."); _println(passed % 10);
|
||||
#endif // _DEBUG ==
|
||||
timeStampOverflow = true;
|
||||
bitSet(modbusData[1], 14);
|
||||
}
|
||||
modbusData[5] = (millis() - timeStamp) / 100;
|
||||
#endif // _MODBUS ==
|
||||
mb.process();
|
||||
//checkModbusParams();
|
||||
static bool firstLoop = true;
|
||||
if (refTime != lastRefTime) {
|
||||
// _printf("refTime: "); _print(refTime); _printf(", lastRefTime: ");
|
||||
// _print(lastRefTime); _printf(", new Alarm: "); _println(bitRead(modbusData[1], 12));
|
||||
lastRefTime = refTime;
|
||||
timeStamp = currMillis;
|
||||
modbusData[5] = 0;
|
||||
eventCounter = 0;
|
||||
timeStampOverflow = false;
|
||||
// Bit 12 gibt an, ob ein neuer Alarm aufgetreten ist - zurücksetzen
|
||||
bitClear(modbusData[1], 12);
|
||||
// Bit 13 gibt an, ob ein Alarm aktiv ist
|
||||
if (faults.state() == activeFault) {
|
||||
bitSet(modbusData[1], 13);
|
||||
} else {
|
||||
bitClear(modbusData[1], 13);
|
||||
}
|
||||
// Setze das 'Timer-Überlauf'-Bit zurück (falls es gesetzt war)
|
||||
bitClear(modbusData[1], 14);
|
||||
if (firstLoop) {
|
||||
// Nachden die 'ReferenzZeit' erstmalig gesetzt wurde, wird dieses Bit gelöscht
|
||||
bitClear(modbusData[1], 15);
|
||||
firstLoop = false;
|
||||
}
|
||||
// Setze die Durchschnittswerte für die Messwerte zurück
|
||||
controller.resetAverageCounters();
|
||||
_printblnf("Der 12 Bit Timer wurde zurückgesetzt");
|
||||
}
|
||||
modbusData[5] = (currMillis - timeStamp) / 100;
|
||||
if (modbusDelAlarms[0] != 0 && modbusDelAlarms[0] != 0xFFFF) {
|
||||
modbusDelAlarms[0] = (faults.removeID(modbusDelAlarms[0])) ? 0 : 0xFFFF;
|
||||
} else if (modbusDelAlarms[1] != 0 && modbusDelAlarms[1] != 0xFFFF) {
|
||||
modbusDelAlarms[1] = (faults.removeAll()) ? 0 : 0xFFFF;
|
||||
}
|
||||
if (!timeStampOverflow && modbusData[5] > 0xFFF) {
|
||||
#if _DEBUG_MODBUS == 1
|
||||
_printf("Der 12 Bit Timer ist übergelaufen. Vergangene Sekunden: ");
|
||||
_print(modbusData[5] / 10); _printf("."); _println(modbusData[5] % 10);
|
||||
#endif // _DEBUG_MODBUS == 1
|
||||
timeStampOverflow = true;
|
||||
bitSet(modbusData[1], 14);
|
||||
}
|
||||
#endif // _MODBUS == 1
|
||||
|
||||
#if 1
|
||||
static unsigned long counter = 0;
|
||||
static unsigned long tl = millis();
|
||||
if (millis() - tl > 1000) {
|
||||
tl = millis();
|
||||
_print("Loops / Sekunde: "); _println(counter);
|
||||
counter = 0;
|
||||
} else {
|
||||
counter++;
|
||||
}
|
||||
#if 0
|
||||
static unsigned long counter = 0;
|
||||
static unsigned long tl = currMillis;
|
||||
if (currMillis - tl > 1000) {
|
||||
tl = currMillis;
|
||||
_printf("Loops / Sekunde: "); _println(counter);
|
||||
counter = 0;
|
||||
} else {
|
||||
counter++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
119
README.md
119
README.md
|
@ -8,27 +8,24 @@ Das Programm ist für den Atmega2560 (Arduino Mega 2560) geschrieben.
|
|||
|
||||
Die aktuell einzige externe Abhängigkeit ist die [U8g2-Library von olikraus](https://github.com/olikraus/u8g2), da diese sehr groß ist (> 30 MB), und deshalb nicht in dieses Repository aufgenommen wird. Diese lässt sich einfach mit dem Arduino Library Manager installieren.
|
||||
|
||||
## Probleme, offene Fragen
|
||||
|
||||
- Das Macro *_FAST_STEP_MS* (Millisekunden, nach denen eine gedrückte Menütaste ein MenuEvent auslöst) darf nicht auf unter 100 gesetzt werden, da die Displayroutinen sonst zu sehr blockieren und Modbus nicht mehr funktioniert. Dabei muss jedenfalls der Konstruktor ***U8G2_ST7920_128X64_F_HW_SPI*** für das Display verwendet werden, da die Displayroutinen sonst zu langsam sind (siehe Liste unten). Eine Erhöhung der SPI-Clockrate kommt leider nicht in Frage, da im Test das Display dabei nicht mehr richtig funktionierte. Folgend die ungefähr benötigten Zeiten (abhängig vom Konstruktor) in ms, um den Displayinhalt aufzubauen (Homescreen, Startmenü):
|
||||
- *U8G2_ST7920_128X64_1_HW_SPI*: 192, 125
|
||||
- *U8G2_ST7920_128X64_2_HW_SPI*: 131, 92
|
||||
- *U8G2_ST7920_128X64_F_HW_SPI*: 87, 67
|
||||
- Der Durchschnittswert der Temperatur wird nicht mehr gebildet (außer das Macro *_MODBUS_AVERAGE_TEMPERATURES* ist 1 - dafür reicht der RAM aber eh nicht ;-) ).
|
||||
***Frage:*** Ist die Mittelung der Temperatur wirklich nicht notwendig?
|
||||
|
||||
# Modbus
|
||||
|
||||
## Coils - FC 1, 5, 15
|
||||
|
||||
Betriebszustand Regler (durch die Modbus-Implementierung sind die Register ***0xB4...0xB7*** les-/schreibbar – diese Werte werden ignoriert):
|
||||
Regler-Settings:
|
||||
|
||||
- ***0xB0***: (de)aktiviere Temperaturregelung
|
||||
- ***0xB1***: (de)aktiviere Drucksteigerung
|
||||
- ***0xB2***: (de)aktiviere Druckabfall
|
||||
- ***0xB3***: (de)aktiviere Regler (unabhängig von den vorigen Werten kann hier der Regler komplett deaktiviert werden)
|
||||
- ***0xB0***: aktiviere Temperaturregelung
|
||||
- ***0xB1***: aktiviere Drucksteigerung
|
||||
- ***0xB2***: aktiviere Druckabfall
|
||||
- ***0xB3***: aktiviere Regler (unabhängig von den vorigen Werten kann hier der Regler komplett deaktiviert werden)
|
||||
- ***0xB4***: aktiviere akustisches Warnsignal
|
||||
- ***0xB5***: aktiviere optisches Warnsignal (pulsierende Displaybeleuchtung)
|
||||
- ***0xB6***: aktiviere Temperaturregelung im Fehlerfall
|
||||
- ***0xB7***: aktiviere Druckregelung im Fehlerfall
|
||||
|
||||
---
|
||||
|
||||
## Discrete Inputs - FC 2
|
||||
|
||||
Ausgangszustände Ventile (durch die Modbus-Implementierung sind die Register ***0xD4...0xD7*** lesbar und geben immer 0 zurück):
|
||||
|
@ -39,6 +36,7 @@ Ausgangszustände Ventile (durch die Modbus-Implementierung sind die Register **
|
|||
- ***0xD3***: Ventil Druckabfall
|
||||
|
||||
---
|
||||
|
||||
## Input Register - FC 4
|
||||
|
||||
Anzahl der gespeicherten Ereignisse abfragen:
|
||||
|
@ -48,48 +46,105 @@ Anzahl der gespeicherten Ereignisse abfragen:
|
|||
Verschiedenes: Ausgangszustände Ventile, Betriebsart Regler, Flags:
|
||||
|
||||
- ***0x01***:
|
||||
- Bit 0...3: siehe Coils (Bit 0: ***0xB0***)
|
||||
- Bit 4...7: reserviert
|
||||
- Bit 0...7: siehe Coils (Bit 0: ***0xB0***)
|
||||
- Bit 8...11: siehe Discrete Inputs (Bit 8: ***0xD0***)
|
||||
- Bit 12...13: reserviert
|
||||
- Bit 14: ist gesetzt, falls der 12 Bit Timer übergelaufen ist
|
||||
- Bit 12: ist gesetzt, falls ein neuer Alarm seit der letzten Referenzierung (siehe Holding-Register ***0xC0*** - setzen der Referenzzeit) aufgetreten ist, auch wenn er nicht mehr aktiv sein sollte.
|
||||
- Bit 13: ist gesetzt, falls ein Alarm aktiv ist
|
||||
- Bit 14: ist gesetzt, falls der 12 Bit Timer übergelaufen ist (wenn das Holding-Register ***0xC0*** (setzen der Referenzzeit) vor über 409,6 Sekunden zuletzt beschrieben wurde)
|
||||
- Bit 15: ist gesetzt, bevor das Holding-Register ***0xC0*** (setzen der Referenzzeit) erstmalig beschrieben wurde
|
||||
|
||||
Messwerte:
|
||||
|
||||
- ***0x02***: Temperatur 1 - aktuelle Temperatur als INT16 in Hundertstel-°C
|
||||
- ***0x03***: Temperatur 2 - noch nicht genutzt – gibt *0xFFFF* zurück
|
||||
- ***0x04***: Druck - Durchschnittswert zwischen 2 Abfragen (der letzten 409,6 Sekunden bzw. der letzten Referenzierung - siehe Holding-Register ***0xC0***) als INT16 in Hundertstel-Bar, einzeln vorkommende Sensorfehler werden ignoriert, bei häufigeren Fehlern wird *0xFFFF* zurückgegeben
|
||||
- ***0x03***: Temperatur 2 - noch nicht genutzt – gibt *0x8000* zurück
|
||||
- ***0x04***: Druck - Durchschnittswert zwischen 2 Abfragen (der letzten 409,6 Sekunden bzw. der letzten Referenzierung - siehe Holding-Register ***0xC0***) als INT16 in Hundertstel-Bar, einzeln vorkommende Sensorfehler werden ignoriert, bei häufigeren Fehlern wird *0x8000* zurückgegeben
|
||||
|
||||
gespeicherte Ereignisse:
|
||||
|
||||
- ***0x05***: Vergangene Zehntelsekunden seit letzter Referenzierung bzw Reglerstart. Ein Überlaufen der Variable wird vom Regler nicht geprüft, da der interne 12 Bit Timer viel früher überläuft, und dabei das ‚Überlauf-Bit‘ im Input-Register ***0x01*** gesetzt wird.
|
||||
|
||||
- ab ***0x06***
|
||||
- ab ***0x06*** (bis *0xFF*)
|
||||
- Bit 0...11 geben den Zeitpunkt relativ zur gespeicherten Referenz (alles in 1/10-Sekunden – siehe Holding-Register ***0xC0***) an. Sobald dieser Offset aber den Wert *0x0FFF* erreicht, wird er nicht mehr geändert, bis die Referenzzeit aktualisiert wird.
|
||||
- Bit 12...14 bezeichnen den geschalteten Ausgang (z.B.: x011-xxxx-xxxx-xxxx für ‚Druckabfall‘)
|
||||
- Bit 15 gibt an, ob der der Ausgang ein- / ausgeschaltet wurde.
|
||||
|
||||
sonstiges:
|
||||
Alarme:
|
||||
|
||||
- ***0xF0***: Firmware-Version Regler (4 MSBs: Major, 6 Bits Minor, 6 LSBs: Micro)
|
||||
- ***0xF1***: Anzahl der Kühlzonen (aktuell nur 1 Zone implementiert)
|
||||
- ***0x0100***: Anzahl der gespeicherten Alarme (0 ... 30)
|
||||
- ab ***0x0101*** (bis *0x0160*): Ein aufgetretener Alarm wird in drei Registern abgebildet (folglich wäre der z.B. 10te Alarm in den Registern *0x0131 ... 0x0133* auszulesen)
|
||||
- **Register 1**: Die ID des Alarms. Wenn der Master die IDs speichert, kann er diese zuordnen, wenn der gleiche Alarm mehrmals ausgelesen wird (aktive Alarme bzw. nicht gelöschte deaktivierte Alarme). Unter der Annahme, dass der Regler während seiner gesamten Einsatzdauer nicht mehr als 65534 Alarme registriert (0 und 0xFFFF sind keine gültigen IDs), ist diese ID praktisch eindeutig.
|
||||
- **Register 2**:
|
||||
- Bit 0...11: Zeitpunkt als der Alarm ausgelöst wurde (siehe Input-Register ***0x06***) bzw. einen Zähler, der mit jedem Einschalten/Reset des Reglers inkrementiert wird (siehe Register 3 Bit 12). Der Wert ist auf 0xFFF gesetzt, falls Register 3 Bit 13 (Timer-Überlauf) gesetzt ist.
|
||||
- Bit 12...15 geben den Fehlercode an:
|
||||
- 0: Sollte nur aus Registern zu lesen sein, welche noch nicht mit einem Fehler belegt sind.
|
||||
- 1: Temperatur 1 zu hoch
|
||||
- 2: Temperatur 1 zu niedrig
|
||||
- 3: Temperatur 1 Sensorfehler
|
||||
- 4: Temperatur 2 zu hoch
|
||||
- 5: Temperatur 2 zu niedrig
|
||||
- 6: Temperatur 2 Sensorfehler
|
||||
- 7: Druck zu hoch
|
||||
- 8: Druck zu niedrig
|
||||
- 9: Druck-Sensorfehler (Nur für 1-5 Volt Sensor verfügbar)
|
||||
- **Register 3**:
|
||||
- Bit 0...11: Zeitpunkt, als der Alarm durch Beheben des Fehlers inaktiv wurde bzw. einen Zähler, der mit jedem Einschalten/Reset des Reglers inkrementiert wird (siehe Bit 14). Der Wert ist auf 0xFFF gesetzt, falls Bit 15 (Timer-Überlauf) gesetzt ist. Der Wert 0 besagt, dass der Alarm noch aktiv ist. Falls der Alarm nie deaktiviert wurde, aber trotzdem inaktiv ist (weil z.B. ein 'Druck zu niedrig'-Alarm direkt von einem 'Druck zu hoch'-Alarm abgelöst wird) und Bit 14 NICHT gesetzt ist, ist der Wert 1. Gültige Zeitpunkte sind somit immer > 1.
|
||||
- Bit 12: wenn gesetzt: Register 2 enthält die Anzahl der Resets seitdem der Alarm ausgelöst wurde
|
||||
- Bit 13: ist gesetzt, falls der interne 12 Bit Timer für Register 2 (Alarm wurde aktiviert) übergelaufen sein sollte (siehe Input-Register *0x01* Bit 14)
|
||||
- Bit 14: wenn gesetzt: Register 3 enthält die Anzahl der Resets seitdem der Alarm inaktiv wurde
|
||||
- Bit 15: ist gesetzt, falls der interne 12 Bit Timer für Register 3 (Alarm wurde deaktiviert) übergelaufen sein sollte (siehe Input-Register *0x01* Bit 14)
|
||||
|
||||
Regler-Info:
|
||||
|
||||
- ***0x0F00***: Firmware-Version (4 MSBs: Major, 6 Bits Minor, 6 LSBs: Micro)
|
||||
- ***0x0F01***: Anzahl der Kühlzonen (aktuell nur 1 Zone implementiert - In Zukunft wird man (z.B. bei der Inbetriebnahme) zwischen 1- und 2-Zonen-Betrieb wählen können)
|
||||
- ***0x0F02***: Wie oft der Regler bis jetzt eingeschaltet wurde (beginnend bei 1)
|
||||
- ***0x0F03***: Werkseinstellung für Coils ***0xB0...0xB7*** -> Bit0(LSB)...Bit7 - Das MSByte ist zu ignorieren
|
||||
- ***0x0F04***: Werkseinstellung Sollwert Temperatur/en (in Hundertstel-°C)
|
||||
- ***0x0F05***: Werkseinstellung Hysterese Temperatur/en (in Hundertstel-°C)
|
||||
- ***0x0F06***: Werkseinstellung Sollwert Druck (in Hundertstel-Bar)
|
||||
- ***0x0F07***: Werkseinstellung Hysterese Druck (in Hundertstel-Bar)
|
||||
- ***0x0F08***: Werkseinstellung Sollwert min. Temperatursteigerungsrate (in Hundertstel-°C - zur Alarmauslösung)
|
||||
- ***0x0F09***: Werkseinstellung Sollwert min. Temperaturabfallrate (in Hundertstel-°C - zur Alarmauslösung)
|
||||
- ***0x0F10***: Werkseinstellung Sollwert min. Druckänderungsrate (in Hundertstel-Bar - zur Alarmauslösung)
|
||||
- ***0x0F11***: Mindestwert Sollwert Temperatur/en (in Hundertstel-°C)
|
||||
- ***0x0F12***: Maximalwert Sollwert Temperatur/en (in Hundertstel-°C)
|
||||
- ***0x0F13***: Mindestwert Hysterese Temperatur/en (in Hundertstel-°C)
|
||||
- ***0x0F14***: Maximalwert Hysterese Temperatur/en (in Hundertstel-°C)
|
||||
- ***0x0F15***: Mindestwert Sollwert Druck (in Hundertstel-Bar)
|
||||
- ***0x0F16***: Maximalwert Sollwert Druck (in Hundertstel-Bar)
|
||||
- ***0x0F17***: Mindestwert Hysterese Druck (in Hundertstel-Bar)
|
||||
- ***0x0F18***: Maximalwert Hysterese Druck (in Hundertstel-Bar)
|
||||
- ***0x0F19***: Mindestwert Änderungsrate für Temperatur/en und Druck (in Hundertstel - zur Alarmauslösung)
|
||||
- ***0x0F20***: Maximalwert Änderungsrate für Temperatur/en und Druck (in Hundertstel - zur Alarmauslösung)
|
||||
---
|
||||
|
||||
## Holding Register - FC 3, 6, 16
|
||||
|
||||
Sollwerte:
|
||||
- ***0xA0***: Bit 0...7: siehe Coils (Bit 0: ***0xB0***)
|
||||
|
||||
- ***0xA0***: Temperatur 1 Sollwert
|
||||
- ***0xA1***: Temperatur 1 Hysterese
|
||||
- ***0xA2***: Temperatur 2 Sollwert (noch nicht implementiert – Wert wird ignoriert)
|
||||
- ***0xA3***: Temperatur 2 Hysterese (noch nicht implementiert – Wert wird ignoriert)
|
||||
- ***0xA4***: Druck Sollwert
|
||||
- ***0xA5***: Druck Hysterese
|
||||
Sollwerte in Hundertsel- [ °C | Bar ]:
|
||||
|
||||
- ***0xA1***: Temperatur 1 Sollwert
|
||||
- ***0xA2***: Temperatur 1 Hysterese
|
||||
- ***0xA3***: Temperatur 2 Sollwert (noch nicht implementiert – Wert wird ignoriert)
|
||||
- ***0xA4***: Temperatur 2 Hysterese (noch nicht implementiert – Wert wird ignoriert)
|
||||
- ***0xA5***: Druck Sollwert
|
||||
- ***0xA6***: Druck Hysterese
|
||||
|
||||
Werte zur Alarmauslösung (Hundertsel- [°C / 1 Stunde | Bar / 10 Sekunden) - bei Nichterreichen dieser Werte wird ein entsprechender Alarm ausgelöst:
|
||||
|
||||
- ***0xA7***: Temperatur-Steigerungsrate
|
||||
- ***0xA8***: Temperatur-Abfallrate
|
||||
- ***0xA9***: Druckrate (Steigerung und Abfall)
|
||||
|
||||
Setzen der Referenzzeit:
|
||||
|
||||
- ***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.
|
||||
- den entsprechenden Zeitstempel 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) mit dem Event-Zeitpunkt und dem aktuellen Zeitstempel des Masters gegenrechnen.
|
||||
|
||||
Löschen von Alarmen:
|
||||
|
||||
- ***0x0200***: Wird in dieses Register eine gültige Alarm-ID (siehe Input-Register ***0x0101***) geschrieben, wird der Alarm aus dem Regler gelöscht, insofern er existiert und nicht aktiv ist. Wurde der Alarm erfolgreich gelöscht, enthält das Register danach den Wert 0, ansonsten 0xFFFF (Alarm nicht vorhanden oder noch aktiv). Dieses Register ist mit 0 initialisiert.
|
||||
- ***0x0201***: Wird in dieses Register ein anderer Wert als 0 oder 0xFFFF geschrieben, werden alle nicht aktiven Alarme aus dem Regler gelöscht. War mindestens ein nicht aktiver Alarm zum Löschen vorhanden, enthält dieses Register danach den Wert 0, ansonsten 0xFFFF. Dieses Register ist mit 0 initialisiert.
|
||||
|
|
|
@ -0,0 +1,614 @@
|
|||
#include "common.h"
|
||||
#include <EEPROM.h>
|
||||
|
||||
extern Display display;
|
||||
extern u32 currMillis;
|
||||
extern u16 zones;
|
||||
|
||||
static void checkParamINT16(int16_t *source, int16_t *target, const int &std, const int &min, const int &max)
|
||||
{
|
||||
_printf("source: "); _print(*source);
|
||||
if (*source == _SENSOR_FAULT) {
|
||||
*source = *target = std;
|
||||
} else if (*source > max) {
|
||||
*source = *target = max;
|
||||
} else if (*source < min) {
|
||||
*source = *target = min;
|
||||
} else if (*source == min || *source == max) {
|
||||
*target = *source;
|
||||
} else {
|
||||
u8 mod = *source % 5;
|
||||
_printf(", modulo: "); _print(mod);
|
||||
if (mod == 0)
|
||||
*target = *source;
|
||||
else {
|
||||
int tempVal = *source - mod;
|
||||
_printf(", tempVal: "); _print(tempVal);
|
||||
if (mod > 2) { // runde auf den nächsten 5er Schritt bzw. setze auf max
|
||||
if ((tempVal + 5) > max) {
|
||||
*source = *target = max;
|
||||
_printf(" ... auf max setzen");
|
||||
} else {
|
||||
*source = *target = tempVal + 5;
|
||||
_printf(" ... aufrunden");
|
||||
}
|
||||
} else { // runde auf den vorigen 5er Schritt bzw. setze auf min
|
||||
if (tempVal < min) {
|
||||
*source = *target = min;
|
||||
_printf(" ... auf min setzen");
|
||||
} else {
|
||||
*source = *target = tempVal;
|
||||
_printf(" ... abrunden");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_printf(", target: "); _print(*target); _printf(", source: "); _println(*source);
|
||||
}
|
||||
|
||||
static void checkParamUINT8(u8 *source, u8 *target, const u8 &std)
|
||||
{
|
||||
_printf("checkParamUINT8 source vorher: "); _print(*source);
|
||||
if (*source > 1) {
|
||||
*source = *target = std;
|
||||
} else {
|
||||
*target = *source;
|
||||
}
|
||||
_printf(", target: "); _print(*target); _printf(", source: "); _println(*source);
|
||||
}
|
||||
|
||||
#if _MODBUS == 1
|
||||
#include "modbus/ModbusRTUSlave.h"
|
||||
|
||||
u8 modbusCoils[1]; // Bit0: tEn, 1: pInc, 2: pDec, 3: cEn, 4: akustisch, 5: optisch, 6: t-off-if-error, 7: p-off-if-error
|
||||
u8 modbusValves[1]; // Bit0: Temp1, Bit1: Temp2, Bit2: Druck
|
||||
// 0: Event-Counter, 1: high: modbusValves[0], low: modbusCoils[0], 2...4: Temp 1, 2, Druck, ab5: gespeicherte Schaltvorgänge
|
||||
u16 modbusData[_REGS_INFRONTOF_EVENTS + _MODBUS_MAX_EVENTS];
|
||||
u16 modbusMiscReadable[21]; // Version, Kühlzonen, Anzahl PowerOns, Konstanten
|
||||
// Anzahl der gespeicherten Alarme + gespeicherte Alarme
|
||||
u16 modbusAlarms[1 + (_MAX_FAULTS * 3)];
|
||||
// Löschen von einzelnen/allen Alarmen
|
||||
u16 modbusDelAlarms[2];
|
||||
// modbusCoils[0], Temp1, 2, Druck jeweils Sollwert + Hysterese, T+Error, T-Error, P+-Error
|
||||
u16 modbusHolding[10];
|
||||
u16 modbusRefTime[1]; // setzt bei Änderung Event-Counter und -Timer zurück
|
||||
|
||||
u16 &eventCounter = modbusData[0];
|
||||
u16 &refTime = modbusRefTime[0];
|
||||
|
||||
extern ModbusRTUSlave mb;
|
||||
|
||||
static void setBitInRegisters(u8 bitNr, u8 val)
|
||||
{
|
||||
_print("Setze Register "); _print(bitNr); _print(" auf "); _println(val);
|
||||
bitWrite(modbusCoils[0], bitNr, val);
|
||||
bitWrite(modbusData[1], bitNr, val);
|
||||
bitWrite(modbusHolding[0], bitNr, val);
|
||||
}
|
||||
|
||||
static void setBitInRegisters(u8 bitNr, u8 val, Parameters &p, FaultSettings &fs)
|
||||
{
|
||||
setBitInRegisters(bitNr, val);
|
||||
switch(bitNr) {
|
||||
case 0: // Temperaturregelung
|
||||
p.tEn = val;
|
||||
break;
|
||||
case 1: // Drucksteigerung
|
||||
p.pInc = val;
|
||||
break;
|
||||
case 2: // Druckabfall
|
||||
p.pDec = val;
|
||||
break;
|
||||
case 3: // Regler aktiv
|
||||
p.cEn = val;
|
||||
break;
|
||||
case 4: // akustisches Warnsignal
|
||||
fs.acoustic = val;
|
||||
break;
|
||||
case 5: // optisches Warnsignal
|
||||
fs.optical = val;
|
||||
break;
|
||||
case 6: // Temperaturregelung im Fehlerfall
|
||||
fs.tOnIfError = val;
|
||||
break;
|
||||
case 7: // Druckregelung im Fehlerfall
|
||||
fs.pOnIfError = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void beginModbus()
|
||||
{
|
||||
mb.begin(modbusParams.address, modbusParams.baudrate);
|
||||
mb.waitWithAnswerMicroS = modbusParams.delay * 100; // 1/10 ms -> us
|
||||
}
|
||||
|
||||
void setupModbus(const u16 &powerOnCount)
|
||||
{
|
||||
bool modbusFail = false;
|
||||
if (!mb.addDiscreteInputArea(0xD0, modbusValves, 1))
|
||||
modbusFail = true;
|
||||
if (!modbusFail && !mb.addHoldingRegisterArea(0xA0, modbusHolding, 10))
|
||||
modbusFail = true;
|
||||
if (!modbusFail && !mb.addCoilArea(0xB0, modbusCoils, 1))
|
||||
modbusFail = true;
|
||||
if (!modbusFail && !mb.addHoldingRegisterArea(0xC0, modbusRefTime, 1))
|
||||
modbusFail = true;
|
||||
if (!modbusFail && !mb.addInputRegisterArea(0x00, modbusData, _REGS_INFRONTOF_EVENTS + _MODBUS_MAX_EVENTS))
|
||||
modbusFail = true;
|
||||
if (!modbusFail && !mb.addInputRegisterArea(0x0100, modbusAlarms, 1 + (_MAX_FAULTS * 3)))
|
||||
modbusFail = true;
|
||||
if (!modbusFail && !mb.addHoldingRegisterArea(0x0200, modbusDelAlarms, 2))
|
||||
modbusFail = true;
|
||||
if (!modbusFail && !mb.addInputRegisterArea(0x0F00, modbusMiscReadable, 21))
|
||||
modbusFail = true;
|
||||
if (modbusFail) {
|
||||
display.modbusProblem();
|
||||
while(1);
|
||||
}
|
||||
modbusData[0] = 0; // EventCounter
|
||||
modbusData[1] |= 0x8000; // setze das MSB. Das Bit wird durch setzen von modbusRefTime[0] zurückgesetzt
|
||||
modbusData[2] = _SENSOR_FAULT; // Temp1 in 100stel-°C
|
||||
modbusData[3] = _SENSOR_FAULT; // Temp2 in 100stel-°C, noch nicht implementiert
|
||||
modbusData[4] = _SENSOR_FAULT; // Druck in 100stel bar
|
||||
modbusData[5] = 0; // Zehntelsekunden seit Reglerstart / letzter Referenzierung
|
||||
modbusAlarms[0] = 0; // Alarm-Counter
|
||||
modbusDelAlarms[0] = 0; // Löschen eines Alarms anhand einer ID
|
||||
modbusDelAlarms[1] = 0; // Alle inaktiven Alarme löschen
|
||||
modbusMiscReadable[0] = _VERSION_NUMBER;
|
||||
modbusMiscReadable[1] = zones;
|
||||
modbusMiscReadable[2] = powerOnCount;
|
||||
modbusMiscReadable[3] = _STD_T_EN;
|
||||
bitWrite(modbusMiscReadable[3], 1, _STD_P_EN_INC);
|
||||
bitWrite(modbusMiscReadable[3], 2, _STD_P_EN_DEC);
|
||||
bitWrite(modbusMiscReadable[3], 3, _STD_C_EN);
|
||||
bitWrite(modbusMiscReadable[3], 4, _STD_FAULTS_ACOUSTIC);
|
||||
bitWrite(modbusMiscReadable[3], 5, _STD_FAULTS_OPTICAL);
|
||||
bitWrite(modbusMiscReadable[3], 6, _STD_FAULTS_T_ON);
|
||||
bitWrite(modbusMiscReadable[3], 7, _STD_FAULTS_P_ON);
|
||||
modbusMiscReadable[4] = _STD_TEMP_SETPOINT;
|
||||
modbusMiscReadable[5] = _STD_TEMP_HYSTERESIS;
|
||||
modbusMiscReadable[6] = _STD_P_SETPOINT;
|
||||
modbusMiscReadable[7] = _STD_P_HYSTERESIS;
|
||||
modbusMiscReadable[8] = _STD_FAULTS_T_R_RATE;
|
||||
modbusMiscReadable[9] = _STD_FAULTS_T_F_RATE;
|
||||
modbusMiscReadable[10] = _STD_FAULTS_P_RATE;
|
||||
modbusMiscReadable[11] = _MIN_TEMP_SETPOINT;
|
||||
modbusMiscReadable[12] = _MAX_TEMP_SETPOINT;
|
||||
modbusMiscReadable[13] = _MIN_TEMP_HYSTERESIS;
|
||||
modbusMiscReadable[14] = _MAX_TEMP_HYSTERESIS;
|
||||
modbusMiscReadable[15] = _MIN_P_SETPOINT;
|
||||
modbusMiscReadable[16] = _MAX_P_SETPOINT;
|
||||
modbusMiscReadable[17] = _MIN_P_HYSTERESIS;
|
||||
modbusMiscReadable[18] = _MAX_P_HYSTERESIS;
|
||||
modbusMiscReadable[19] = _MIN_FAULTS_RATE;
|
||||
modbusMiscReadable[20] = _MAX_FAULTS_RATE;
|
||||
modbusRefTime[0] = 0xFFFF;
|
||||
beginModbus();
|
||||
}
|
||||
|
||||
void modbusCallbackCoil(u16 reg, bool val)
|
||||
{
|
||||
Parameters p;
|
||||
FaultSettings fs;
|
||||
if ((reg >= 0xB0) && (reg <= 0xB7)) {
|
||||
setBitInRegisters(reg - 0xB0, val, p, fs);
|
||||
}
|
||||
setParams(p, false);
|
||||
setFaultSettings(fs, false);
|
||||
}
|
||||
|
||||
u16 modbusCallbackRegister(u16 reg, u16 val)
|
||||
{
|
||||
Parameters p;
|
||||
FaultSettings fs;
|
||||
switch(reg) {
|
||||
case 0xA0: // Bit 0...7: siehe Coils (Bit 0: 0xB0)
|
||||
for (u8 i=0; i<8; i++) {
|
||||
u8 bitVal = bitRead(val, i);
|
||||
if (bitVal != bitRead(modbusHolding[0], i)) {
|
||||
setBitInRegisters(i, bitVal, p, fs);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xA1: // Temperatur 1 Sollwert
|
||||
checkParamINT16((int16_t*)&val, &p.ts1, _STD_TEMP_SETPOINT, _MIN_TEMP_SETPOINT, _MAX_TEMP_SETPOINT);
|
||||
val = p.ts1;
|
||||
break;
|
||||
case 0xA2: // Temperatur 1 Hysterese
|
||||
checkParamINT16((int16_t*)&val, &p.th1, _STD_TEMP_HYSTERESIS, _MIN_TEMP_HYSTERESIS, _MAX_TEMP_HYSTERESIS);
|
||||
val = p.th1;
|
||||
break;
|
||||
case 0xA3: // Temperatur 2 Sollwert (noch nicht implementiert – Wert wird ignoriert)
|
||||
case 0xA4: // Temperatur 2 Hysterese (noch nicht implementiert – Wert wird ignoriert)
|
||||
break;
|
||||
case 0xA5: // Druck Sollwert
|
||||
checkParamINT16((int16_t*)&val, &p.ps, _STD_P_SETPOINT, _MIN_P_SETPOINT, _MAX_P_SETPOINT);
|
||||
val = p.ps;
|
||||
break;
|
||||
case 0xA6: // Druck Hysterese
|
||||
checkParamINT16((int16_t*)&val, &p.ph, _STD_P_HYSTERESIS, _MIN_P_HYSTERESIS, _MAX_P_HYSTERESIS);
|
||||
val = p.ph;
|
||||
break;
|
||||
case 0xA7: // Temperatur-Steigerungsrate (Hundertstel-°C / 1 Stunde)
|
||||
checkParamINT16((int16_t*)&val, &fs.tMinRRate, _STD_FAULTS_T_R_RATE, _MIN_FAULTS_RATE, _MAX_FAULTS_RATE);
|
||||
val = fs.tMinRRate;
|
||||
break;
|
||||
case 0xA8: // Temperatur-Abfallrate (Hundertstel-°C / 1 Stunde)
|
||||
checkParamINT16((int16_t*)&val, &fs.tMinFRate, _STD_FAULTS_T_F_RATE, _MIN_FAULTS_RATE, _MAX_FAULTS_RATE);
|
||||
val = fs.tMinFRate;
|
||||
break;
|
||||
case 0xA9: // Druckrate (Steigerung und Abfall - Hundertstel-Bar / 10 Sekunden)
|
||||
checkParamINT16((int16_t*)&val, &fs.pMinRate, _STD_FAULTS_P_RATE, _MIN_FAULTS_RATE, _MAX_FAULTS_RATE);
|
||||
val = fs.pMinRate;
|
||||
break;
|
||||
}
|
||||
setParams(p, false);
|
||||
setFaultSettings(fs, false);
|
||||
return val;
|
||||
}
|
||||
#endif // _MODBUS == 1
|
||||
|
||||
void getParams()
|
||||
{
|
||||
Parameters p;
|
||||
EEPROM.get(_EEPROM_TEMP_SETPOINT, p.ts1);
|
||||
EEPROM.get(_EEPROM_TEMP_HYSTERESIS, p.th1);
|
||||
EEPROM.get(_EEPROM_P_SETPOINT, p.ps);
|
||||
EEPROM.get(_EEPROM_P_HYSTERESIS, p.ph);
|
||||
EEPROM.get(_EEPROM_P_EN_INC, p.pInc);
|
||||
EEPROM.get(_EEPROM_P_EN_DEC, p.pDec);
|
||||
EEPROM.get(_EEPROM_T_EN, p.tEn);
|
||||
EEPROM.get(_EEPROM_CONTROL_EN, p.cEn);
|
||||
_printlnf("getParams() vor Validierung:");
|
||||
_printf(" Temperatur Sollwert: "); _println(p.ts1);
|
||||
_printf(" Temperatur Hysterese: "); _println(p.th1);
|
||||
_printf(" Druck Sollwert: "); _println(p.ps);
|
||||
_printf(" Druck Hysterese: "); _println(p.ph);
|
||||
_printf(" Temp-Regelung aktiv: "); _println(p.tEn);
|
||||
_printf(" Drucksteigerung aktiv: "); _println(p.pInc);
|
||||
_printf(" Druckabfall aktiv: "); _println(p.pDec);
|
||||
_printf(" Regler aktiv: "); _println(p.cEn);
|
||||
_printf("ts1 - UI -> Modbus - ");
|
||||
checkParamINT16(&p.ts1, ¶ms.ts1, _STD_TEMP_SETPOINT, _MIN_TEMP_SETPOINT, _MAX_TEMP_SETPOINT);
|
||||
modbusHolding[1] = params.ts1;
|
||||
_printf("th1 - UI -> Modbus - ");
|
||||
checkParamINT16(&p.th1, ¶ms.th1, _STD_TEMP_HYSTERESIS, _MIN_TEMP_HYSTERESIS, _MAX_TEMP_HYSTERESIS);
|
||||
modbusHolding[2] = params.th1;
|
||||
_printf("ps - UI -> Modbus - ");
|
||||
checkParamINT16(&p.ps, ¶ms.ps, _STD_P_SETPOINT, _MIN_P_SETPOINT, _MAX_P_SETPOINT);
|
||||
modbusHolding[5] = params.ps;
|
||||
_printf("ph - UI -> Modbus - ");
|
||||
checkParamINT16(&p.ph, ¶ms.ph, _STD_P_HYSTERESIS, _MIN_P_HYSTERESIS, _MAX_P_HYSTERESIS);
|
||||
modbusHolding[6] = params.ph;
|
||||
_printf("tEn - ");
|
||||
checkParamUINT8(&p.tEn, ¶ms.tEn, _STD_T_EN);
|
||||
setBitInRegisters(0, params.tEn);
|
||||
_printf("pInc - ");
|
||||
checkParamUINT8(&p.pInc, ¶ms.pInc, _STD_P_EN_INC);
|
||||
setBitInRegisters(1, params.pInc);
|
||||
_printf("pDec - ");
|
||||
checkParamUINT8(&p.pDec, ¶ms.pDec, _STD_P_EN_DEC);
|
||||
setBitInRegisters(2, params.pDec);
|
||||
_printf("cEn - ");
|
||||
checkParamUINT8(&p.cEn, ¶ms.cEn, _STD_C_EN);
|
||||
setBitInRegisters(3, params.cEn);
|
||||
_printlnf("getParams() nach Validierung:");
|
||||
_printf(" Temperatur Sollwert: "); _println(params.ts1);
|
||||
_printf(" Temperatur Hysterese: "); _println(params.th1);
|
||||
_printf(" Druck Sollwert: "); _println(params.ps);
|
||||
_printf(" Druck Hysterese: "); _println(params.ph);
|
||||
_printf(" Temp-Regelung aktiv: "); _println(params.tEn);
|
||||
_printf(" Drucksteigerung aktiv: "); _println(params.pInc);
|
||||
_printf(" Druckabfall aktiv: "); _println(params.pDec);
|
||||
_printf(" Regler aktiv: "); _println(params.cEn);
|
||||
}
|
||||
|
||||
void setParams(Parameters &p, bool writeModbusRegister)
|
||||
{
|
||||
if (p.ts1 != _SENSOR_FAULT) {
|
||||
_printf("ts1 alt: "); _print(params.ts1); _printf(", neu: "); _println(p.ts1);
|
||||
checkParamINT16(&p.ts1, ¶ms.ts1, _STD_TEMP_SETPOINT, _MIN_TEMP_SETPOINT, _MAX_TEMP_SETPOINT);
|
||||
EEPROM.put(_EEPROM_TEMP_SETPOINT, params.ts1);
|
||||
if (writeModbusRegister) modbusHolding[1] = params.ts1;
|
||||
}
|
||||
if (p.th1 != _SENSOR_FAULT) {
|
||||
_printf("th1 alt: "); _print(params.th1); _printf(", neu: "); _println(p.th1);
|
||||
checkParamINT16(&p.th1, ¶ms.th1, _STD_TEMP_HYSTERESIS, _MIN_TEMP_HYSTERESIS, _MAX_TEMP_HYSTERESIS);
|
||||
EEPROM.put(_EEPROM_TEMP_HYSTERESIS, params.th1);
|
||||
if (writeModbusRegister) modbusHolding[2] = params.th1;
|
||||
}
|
||||
if (p.ps != _SENSOR_FAULT) {
|
||||
_printf("ps alt: "); _print(params.ps); _printf(", neu: "); _println(p.ps);
|
||||
checkParamINT16(&p.ps, ¶ms.ps, _STD_P_SETPOINT, _MIN_P_SETPOINT, _MAX_P_SETPOINT);
|
||||
EEPROM.put(_EEPROM_P_SETPOINT, params.ps);
|
||||
if (writeModbusRegister) modbusHolding[5] = params.ps;
|
||||
}
|
||||
if (p.ph != _SENSOR_FAULT) {
|
||||
_printf("ph alt: "); _print(params.ph); _printf(", neu: "); _println(p.ph);
|
||||
checkParamINT16(&p.ph, ¶ms.ph, _STD_P_HYSTERESIS, _MIN_P_HYSTERESIS, _MAX_P_HYSTERESIS);
|
||||
EEPROM.put(_EEPROM_P_HYSTERESIS, params.ph);
|
||||
if (writeModbusRegister) modbusHolding[6] = params.ph;
|
||||
}
|
||||
if (p.pInc < 2) {
|
||||
_printf("pInc alt: "); _print(params.pInc); _printf(", neu: "); _println(p.pInc);
|
||||
params.pInc = p.pInc;
|
||||
EEPROM.put(_EEPROM_P_EN_INC, params.pInc);
|
||||
if (writeModbusRegister) setBitInRegisters(1, params.pInc);
|
||||
}
|
||||
if (p.pDec < 2) {
|
||||
_printf("pDec alt: "); _print(params.pDec); _printf(", neu: "); _println(p.pDec);
|
||||
params.pDec = p.pDec;
|
||||
EEPROM.put(_EEPROM_P_EN_DEC, params.pDec);
|
||||
if (writeModbusRegister) setBitInRegisters(2, params.pDec);
|
||||
}
|
||||
if (p.tEn < 2) {
|
||||
_printf("tEn alt: "); _print(params.tEn); _printf(", neu: "); _println(p.tEn);
|
||||
params.tEn = p.tEn;
|
||||
EEPROM.put(_EEPROM_T_EN, params.tEn);
|
||||
if (writeModbusRegister) setBitInRegisters(0, params.tEn);
|
||||
}
|
||||
if (p.cEn < 2) {
|
||||
_printf("cEn alt: "); _print(params.cEn); _printf(", neu: "); _println(p.cEn);
|
||||
params.cEn = p.cEn;
|
||||
EEPROM.put(_EEPROM_CONTROL_EN, params.cEn);
|
||||
if (writeModbusRegister) setBitInRegisters(3, params.cEn);
|
||||
}
|
||||
}
|
||||
|
||||
void getModbusParams()
|
||||
{
|
||||
uint8_t addr = EEPROM.read(_EEPROM_MODBUS_ADDRESS);
|
||||
if (addr < _MODBUS_ADDR_MIN || addr > _MODBUS_ADDR_MAX)
|
||||
modbusParams.address = _MODBUS_ADDR_MIN;
|
||||
else
|
||||
modbusParams.address = addr;
|
||||
uint32_t baudrate;
|
||||
EEPROM.get(_EEPROM_MODBUS_BAUDRATE, baudrate);
|
||||
switch (baudrate) {
|
||||
case 115200: break;
|
||||
case 57600: break;
|
||||
case 38400: break;
|
||||
case 19200: break;
|
||||
case 9600: break;
|
||||
case 4800: break;
|
||||
case 2400: break;
|
||||
case 1200: break;
|
||||
case 300: break;
|
||||
default: baudrate = 9600;
|
||||
}
|
||||
modbusParams.baudrate = baudrate;
|
||||
uint8_t delay_ = EEPROM.read(_EEPROM_MODBUS_DELAY);
|
||||
if (delay_ < _MODBUS_DELAY_MIN)
|
||||
modbusParams.delay = _MODBUS_DELAY_MIN;
|
||||
else if (delay_ > _MODBUS_DELAY_MAX)
|
||||
modbusParams.delay = _MODBUS_DELAY_MAX;
|
||||
else
|
||||
modbusParams.delay = delay_;
|
||||
}
|
||||
|
||||
void setModbusParams(const ModbusParameters &p)
|
||||
{
|
||||
bool changed = false;
|
||||
if (p.address <= _MODBUS_ADDR_MAX) {
|
||||
EEPROM.put(_EEPROM_MODBUS_ADDRESS, p.address);
|
||||
modbusParams.address = p.address;
|
||||
changed = true;
|
||||
}
|
||||
if (p.baudrate != _MODBUS_INVALID_BAUDRATE) {
|
||||
EEPROM.put(_EEPROM_MODBUS_BAUDRATE, p.baudrate);
|
||||
modbusParams.baudrate = p.baudrate;
|
||||
changed = true;
|
||||
}
|
||||
if (p.delay <= _MODBUS_DELAY_MAX) {
|
||||
EEPROM.put(_EEPROM_MODBUS_DELAY, p.delay);
|
||||
modbusParams.delay = p.delay;
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
#if _MODBUS == 1
|
||||
beginModbus();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void getPSensor()
|
||||
{
|
||||
uint8_t val;
|
||||
EEPROM.get(_EEPROM_P_SENSOR, val);
|
||||
switch (val) {
|
||||
case SMC_1_5V_0_5BAR:
|
||||
pSensor = SMC_1_5V_0_5BAR;
|
||||
break;
|
||||
case GEMS_0_5V_0_6BAR:
|
||||
pSensor = GEMS_0_5V_0_6BAR;
|
||||
break;
|
||||
default:
|
||||
pSensor = SMC_1_5V_0_5BAR;
|
||||
EEPROM.put(_EEPROM_P_SENSOR, pSensor);
|
||||
}
|
||||
return pSensor;
|
||||
}
|
||||
|
||||
void setPSensor(const PSensor &sensor)
|
||||
{
|
||||
EEPROM.put(_EEPROM_P_SENSOR, sensor);
|
||||
pSensor = sensor;
|
||||
}
|
||||
|
||||
void getFaultSettings()
|
||||
{
|
||||
FaultSettings settings;
|
||||
EEPROM.get(_EEPROM_FAULTS_ACOUSTIC, settings.acoustic);
|
||||
EEPROM.get(_EEPROM_FAULTS_OPTICAL, settings.optical);
|
||||
EEPROM.get(_EEPROM_FAULTS_T_ON, settings.tOnIfError);
|
||||
EEPROM.get(_EEPROM_FAULTS_P_ON, settings.pOnIfError);
|
||||
EEPROM.get(_EEPROM_FAULTS_T_R_RATE, settings.tMinRRate);
|
||||
EEPROM.get(_EEPROM_FAULTS_T_F_RATE, settings.tMinFRate);
|
||||
EEPROM.get(_EEPROM_FAULTS_P_RATE, settings.pMinRate);
|
||||
_printlnf("getFaultSettings() vor Validierung:");
|
||||
_printf(" akustisches Signal: "); _println(settings.acoustic);
|
||||
_printf(" optisches Signal : "); _println(settings.optical);
|
||||
_printf(" t on if error : "); _println(settings.tOnIfError);
|
||||
_printf(" p on if error : "); _println(settings.pOnIfError);
|
||||
_printf(" t min rise rate : "); _println(settings.tMinRRate);
|
||||
_printf(" t min fall rate : "); _println(settings.tMinFRate);
|
||||
_printf(" p min r/f rate : "); _println(settings.pMinRate);
|
||||
if (settings.acoustic < 2) {
|
||||
faultSettings.acoustic = settings.acoustic;
|
||||
} else {
|
||||
faultSettings.acoustic = _STD_FAULTS_ACOUSTIC;
|
||||
}
|
||||
setBitInRegisters(4, faultSettings.acoustic);
|
||||
if (settings.optical < 2) {
|
||||
faultSettings.optical = settings.optical;
|
||||
} else {
|
||||
faultSettings.optical = _STD_FAULTS_OPTICAL;
|
||||
}
|
||||
setBitInRegisters(5, faultSettings.optical);
|
||||
if (settings.tOnIfError < 2) {
|
||||
faultSettings.tOnIfError = settings.tOnIfError;
|
||||
} else {
|
||||
faultSettings.tOnIfError = _STD_FAULTS_T_ON;
|
||||
}
|
||||
setBitInRegisters(6, faultSettings.tOnIfError);
|
||||
if (settings.pOnIfError < 2) {
|
||||
faultSettings.pOnIfError = settings.pOnIfError;
|
||||
} else {
|
||||
faultSettings.pOnIfError = _STD_FAULTS_P_ON;
|
||||
}
|
||||
setBitInRegisters(7, faultSettings.pOnIfError);
|
||||
if (settings.tMinRRate == 0x8000) {
|
||||
faultSettings.tMinRRate = _STD_FAULTS_T_R_RATE;
|
||||
} else if (settings.tMinRRate < _MIN_FAULTS_RATE) {
|
||||
faultSettings.tMinRRate = _MIN_FAULTS_RATE;
|
||||
} else if (settings.tMinRRate > _MAX_FAULTS_RATE) {
|
||||
faultSettings.tMinRRate = _MAX_FAULTS_RATE;
|
||||
} else {
|
||||
faultSettings.tMinRRate = settings.tMinRRate;
|
||||
}
|
||||
modbusHolding[7] = faultSettings.tMinRRate;
|
||||
if (settings.tMinFRate == 0x8000) {
|
||||
faultSettings.tMinFRate = _STD_FAULTS_T_F_RATE;
|
||||
} else if (settings.tMinFRate < _MIN_FAULTS_RATE) {
|
||||
faultSettings.tMinFRate = _MIN_FAULTS_RATE;
|
||||
} else if (settings.tMinFRate > _MAX_FAULTS_RATE) {
|
||||
faultSettings.tMinFRate = _MAX_FAULTS_RATE;
|
||||
} else {
|
||||
faultSettings.tMinFRate = settings.tMinFRate;
|
||||
}
|
||||
modbusHolding[8] = faultSettings.tMinFRate;
|
||||
if (settings.pMinRate == 0x8000) {
|
||||
faultSettings.pMinRate = _STD_FAULTS_P_RATE;
|
||||
} else if (settings.pMinRate < _MIN_FAULTS_RATE) {
|
||||
faultSettings.pMinRate = _MIN_FAULTS_RATE;
|
||||
} else if (settings.pMinRate > _MAX_FAULTS_RATE) {
|
||||
faultSettings.pMinRate = _MAX_FAULTS_RATE;
|
||||
} else {
|
||||
faultSettings.pMinRate = settings.pMinRate;
|
||||
}
|
||||
modbusHolding[9] = faultSettings.pMinRate;
|
||||
_printlnf("getFaultSettings() nach Validierung:");
|
||||
_printf(" akustisches Signal: "); _println(faultSettings.acoustic);
|
||||
_printf(" optisches Signal : "); _println(faultSettings.optical);
|
||||
_printf(" t on if error : "); _println(faultSettings.tOnIfError);
|
||||
_printf(" p on if error : "); _println(faultSettings.pOnIfError);
|
||||
_printf(" t min rise rate : "); _println(faultSettings.tMinRRate);
|
||||
_printf(" t min fall rate : "); _println(faultSettings.tMinFRate);
|
||||
_printf(" p min r/f rate : "); _println(faultSettings.pMinRate);
|
||||
}
|
||||
|
||||
void setFaultSettings(const FaultSettings &settings, bool writeModbusRegister)
|
||||
{
|
||||
if (settings.acoustic < 2 && settings.acoustic != faultSettings.acoustic) {
|
||||
_printf("faultSettings.acoustic alt: "); _print(faultSettings.acoustic);
|
||||
_printf(", neu: "); _println(settings.acoustic);
|
||||
faultSettings.acoustic = settings.acoustic;
|
||||
EEPROM.put(_EEPROM_FAULTS_ACOUSTIC, settings.acoustic);
|
||||
if (writeModbusRegister) setBitInRegisters(4, settings.acoustic);
|
||||
}
|
||||
if (settings.optical < 2 && settings.optical != faultSettings.optical) {
|
||||
_printf("faultSettings.optical alt: "); _print(faultSettings.optical);
|
||||
_printf(", neu: "); _println(settings.optical);
|
||||
faultSettings.optical = settings.optical;
|
||||
EEPROM.put(_EEPROM_FAULTS_OPTICAL, settings.optical);
|
||||
if (writeModbusRegister) setBitInRegisters(5, settings.optical);
|
||||
}
|
||||
if (settings.tOnIfError < 2 && settings.tOnIfError != faultSettings.tOnIfError) {
|
||||
_printf("faultSettings.tOnIfError alt: "); _print(faultSettings.tOnIfError);
|
||||
_printf(", neu: "); _println(settings.tOnIfError);
|
||||
faultSettings.tOnIfError = settings.tOnIfError;
|
||||
EEPROM.put(_EEPROM_FAULTS_T_ON, settings.tOnIfError);
|
||||
if (writeModbusRegister) setBitInRegisters(6, settings.tOnIfError);
|
||||
}
|
||||
if (settings.pOnIfError < 2 && settings.pOnIfError != faultSettings.pOnIfError) {
|
||||
_printf("faultSettings.pOnIfError alt: "); _print(faultSettings.pOnIfError);
|
||||
_printf(", neu: "); _println(settings.pOnIfError);
|
||||
faultSettings.pOnIfError = settings.pOnIfError;
|
||||
EEPROM.put(_EEPROM_FAULTS_P_ON, settings.pOnIfError);
|
||||
if (writeModbusRegister) setBitInRegisters(7, settings.pOnIfError);
|
||||
}
|
||||
if (settings.tMinRRate != 0x8000 && settings.tMinRRate != faultSettings.tMinRRate) {
|
||||
if (settings.tMinRRate < _MIN_FAULTS_RATE) {
|
||||
faultSettings.tMinRRate == _MIN_FAULTS_RATE;
|
||||
EEPROM.put(_EEPROM_FAULTS_T_R_RATE, _MIN_FAULTS_RATE);
|
||||
} else if (settings.tMinRRate > _MAX_FAULTS_RATE) {
|
||||
faultSettings.tMinRRate == _MAX_FAULTS_RATE;
|
||||
EEPROM.put(_EEPROM_FAULTS_T_R_RATE, _MAX_FAULTS_RATE);
|
||||
} else {
|
||||
faultSettings.tMinRRate == settings.tMinRRate;
|
||||
EEPROM.put(_EEPROM_FAULTS_T_R_RATE, settings.tMinRRate);
|
||||
}
|
||||
if (writeModbusRegister) modbusHolding[7] = settings.tMinRRate;
|
||||
_printf("faultSettings.tMinRRate alt: "); _print(faultSettings.tMinRRate);
|
||||
_printf(", neu: "); _println(settings.tMinRRate);
|
||||
}
|
||||
if (settings.tMinFRate != 0x8000 && settings.tMinFRate != faultSettings.tMinFRate) {
|
||||
if (settings.tMinFRate < _MIN_FAULTS_RATE) {
|
||||
faultSettings.tMinFRate == _MIN_FAULTS_RATE;
|
||||
EEPROM.put(_EEPROM_FAULTS_T_F_RATE, _MIN_FAULTS_RATE);
|
||||
} else if (settings.tMinFRate > _MAX_FAULTS_RATE) {
|
||||
faultSettings.tMinFRate == _MAX_FAULTS_RATE;
|
||||
EEPROM.put(_EEPROM_FAULTS_T_F_RATE, _MAX_FAULTS_RATE);
|
||||
} else {
|
||||
faultSettings.tMinFRate == settings.tMinFRate;
|
||||
EEPROM.put(_EEPROM_FAULTS_T_F_RATE, settings.tMinFRate);
|
||||
}
|
||||
if (writeModbusRegister) modbusHolding[8] = settings.tMinFRate;
|
||||
_printf("faultSettings.tMinFRate alt: "); _print(faultSettings.tMinFRate);
|
||||
_printf(", neu: "); _println(settings.tMinFRate);
|
||||
}
|
||||
if (settings.pMinRate != 0x8000 && settings.pMinRate != faultSettings.pMinRate) {
|
||||
if (settings.pMinRate < _MIN_FAULTS_RATE) {
|
||||
faultSettings.pMinRate == _MIN_FAULTS_RATE;
|
||||
EEPROM.put(_EEPROM_FAULTS_P_RATE, _MIN_FAULTS_RATE);
|
||||
} else if (settings.pMinRate > _MAX_FAULTS_RATE) {
|
||||
faultSettings.pMinRate == _MAX_FAULTS_RATE;
|
||||
EEPROM.put(_EEPROM_FAULTS_P_RATE, _MAX_FAULTS_RATE);
|
||||
} else {
|
||||
faultSettings.pMinRate == settings.pMinRate;
|
||||
EEPROM.put(_EEPROM_FAULTS_P_RATE, settings.pMinRate);
|
||||
}
|
||||
if (writeModbusRegister) modbusHolding[9] = settings.pMinRate;
|
||||
_printf("faultSettings.pMinRate alt: "); _print(faultSettings.pMinRate);
|
||||
_printf(", neu: "); _println(settings.pMinRate);
|
||||
}
|
||||
}
|
||||
|
||||
bool readPwrBtn()
|
||||
{
|
||||
const uint8_t debounceDelay = 20;
|
||||
static unsigned long lastDebounceTime;
|
||||
static bool lastBounceState;
|
||||
static bool steadyState;
|
||||
bool currentState = !digitalRead(BTN_PWR);
|
||||
if (currentState != lastBounceState) {
|
||||
lastDebounceTime = currMillis;
|
||||
lastBounceState = currentState;
|
||||
}
|
||||
if ((currMillis - lastDebounceTime) > debounceDelay)
|
||||
steadyState = currentState;
|
||||
if (steadyState && (currMillis - lastDebounceTime) > 3000)
|
||||
display.reset();
|
||||
return steadyState;
|
||||
}
|
172
src/common.h
172
src/common.h
|
@ -1,158 +1,38 @@
|
|||
#ifndef _MY_STUFF_H_INCLUDED
|
||||
#define _MY_STUFF_H_INCLUDED
|
||||
|
||||
#include "./DallasTemperature/DallasTemperature.h"
|
||||
#include "DallasTemperature/DallasTemperature.h"
|
||||
#include "OneWire/OneWire.h"
|
||||
#include "display/display.h"
|
||||
#include "controller/controller.h"
|
||||
#include "faults/faults.h"
|
||||
#include "types.h"
|
||||
#include "macros.h"
|
||||
|
||||
#define _VERSION_MAJOR 0
|
||||
#define _VERSION_MINOR 0
|
||||
#define _VERSION_MICRO 1
|
||||
#define _VERSION_NUMBER _VERSION_MICRO | (_VERSION_MINOR << 6) | (_VERSION_MAJOR << 12)
|
||||
#define _VERSION_STRING "v0.0.1"
|
||||
extern const uint8_t BTN_PWR;
|
||||
|
||||
#define _DEBUG 1
|
||||
#define _DEBUG_SENSORS 0
|
||||
#define _DEBUG_DISPLAY 0
|
||||
#define _MODBUS 1
|
||||
// Das Ermitteln einer Durchschnittstemperatur braucht (zu) viel RAM und ist wahrscheinlich unnötig
|
||||
#define _MODBUS_AVERAGE_TEMPERATURES 0
|
||||
|
||||
#if _DEBUG == 1
|
||||
#define _print(x) Serial.print(x)
|
||||
#define _println(x) Serial.println(x)
|
||||
#if _DEBUG_DISPLAY == 1
|
||||
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)
|
||||
#else
|
||||
#define _printtime(text)
|
||||
#endif // _DEBUG_DISPLAY
|
||||
#if _DEBUG_SENSORS == 1
|
||||
#define _prints(x) Serial.print(x)
|
||||
#define _printsln(x) Serial.println(x)
|
||||
#else
|
||||
#define _prints(x)
|
||||
#define _printsln(x)
|
||||
#endif
|
||||
#else
|
||||
#define _print(x)
|
||||
#define _println(x)
|
||||
#define _prints(x)
|
||||
#define _printsln(x)
|
||||
#define _printtime()
|
||||
#endif
|
||||
|
||||
#define _REGS_INFRONTOF_EVENTS 6
|
||||
#define _MODBUS_MAX_EVENTS 234 // Ergibt sich aus 0xF0 - 0x06
|
||||
extern void getParams();
|
||||
extern void setParams(Parameters&, bool writeModbusRegister);
|
||||
extern void getModbusParams();
|
||||
extern void setModbusParams(const ModbusParameters&);
|
||||
extern void getPSensor();
|
||||
extern void setPSensor(const PSensor&);
|
||||
extern void getFaultSettings();
|
||||
extern void setFaultSettings(const FaultSettings&, bool writeModbusRegister);
|
||||
extern bool readPwrBtn();
|
||||
|
||||
#if _MODBUS == 1
|
||||
#include "modbus/ModbusRTUSlave.h"
|
||||
extern bool timeStampOverflow;
|
||||
extern unsigned long timeStamp;
|
||||
extern u8 &valves;
|
||||
extern u16 &eventCounter;
|
||||
extern u16 modbusData[];
|
||||
#define _setModbusValve(index, val)\
|
||||
if (bitRead(valves, index) != val) {\
|
||||
bitWrite(valves, index, val);\
|
||||
bitWrite(modbusData[1], index+8, val);\
|
||||
if (eventCounter < _MODBUS_MAX_EVENTS) {\
|
||||
/* Die ersten 12 Bits beinhalten den relativen Zeitstempel in Zehntelsekunden */\
|
||||
/* Dieser Stempel ist immer 0xFFF, falls schon zuviel Zeit seit der letzten Referenzierung vergangen ist */\
|
||||
u16 result = (timeStampOverflow) ? 0xFFF : ((millis() - timeStamp) / 100) & 0xFFF;\
|
||||
/* Die Bits 12...14 beinhalten die Nr des geschalteten Ausgangs */\
|
||||
result |= index << 12;\
|
||||
/* Das MSB gibt an, ob der Ausgang ein- oder ausgeschaltet wurde */\
|
||||
result |= val << 15;\
|
||||
modbusData[_REGS_INFRONTOF_EVENTS + eventCounter] = result;\
|
||||
eventCounter++;\
|
||||
}\
|
||||
}
|
||||
//#define _setModbusValue(index, val) modbusData[index] = val
|
||||
#else
|
||||
#define _setModbusValve(index, val)
|
||||
//#define _setModbusValue(index, val)
|
||||
#endif // _MODBUS ==
|
||||
extern u16 modbusDelAlarms[];
|
||||
|
||||
#define _MODBUS_ADDR_MIN 1
|
||||
#define _MODBUS_ADDR_MAX 247 // Laut QModMaster letzte Adresse
|
||||
#define _MODBUS_DELAY_MIN 0 // 1/10 Millisekunden
|
||||
#define _MODBUS_DELAY_MAX 250 // 1/10 Millisekunden
|
||||
#define _MODBUS_INVALID_BAUDRATE 4294967295
|
||||
extern u16 &eventCounter;
|
||||
extern u16 &refTime;
|
||||
|
||||
#define _MODBUS_VALVE_T1_INDEX 0
|
||||
#define _MODBUS_VALVE_T2_INDEX 1
|
||||
#define _MODBUS_VALVE_PR_INDEX 2
|
||||
#define _MODBUS_VALVE_PF_INDEX 3
|
||||
#define _MODBUS_T1_INDEX 2
|
||||
#define _MODBUS_T2_INDEX 3
|
||||
#define _MODBUS_P_INDEX 4
|
||||
|
||||
#define _SENSOR_FAULT 0xFFFF
|
||||
|
||||
#define _STD_TEMP_SETPOINT 400 // Hundertstel
|
||||
#define _STD_TEMP_HYSTERESIS 10 // Hundertstel
|
||||
#define _STD_P_SETPOINT 100 // Hundertstel
|
||||
#define _STD_P_HYSTERESIS 5 // Hundertstel
|
||||
#define _STD_P_EN_INC 1
|
||||
#define _STD_P_EN_DEC 1
|
||||
#define _STD_T_EN 1
|
||||
#define _STD_C_EN 0
|
||||
#define _MIN_TEMP_SETPOINT 10 // Hundertstel
|
||||
#define _MAX_TEMP_SETPOINT 3000 // Hundertstel
|
||||
#define _MIN_TEMP_HYSTERESIS 1 // Hundertstel
|
||||
#define _MAX_TEMP_HYSTERESIS 100 // Hundertstel
|
||||
#define _MIN_P_SETPOINT 0 // Hundertstel
|
||||
#define _MAX_P_SETPOINT 300 // Hundertstel
|
||||
#define _MIN_P_HYSTERESIS 1 // Hundertstel
|
||||
#define _MAX_P_HYSTERESIS 50 // Hundertstel
|
||||
|
||||
#define _P_SENSOR_1_5V_0_5BAR 1
|
||||
#define _P_SENSOR_0_5V_0_6BAR 2
|
||||
|
||||
enum PSensor : uint8_t {
|
||||
SMC_1_5V_0_5BAR=1, // Sensor mit Kabel
|
||||
GEMS_0_5V_0_6BAR // Sensor mit Würfelstecker
|
||||
};
|
||||
|
||||
struct parameters { // Prozesswerte
|
||||
int16_t ts1 = _SENSOR_FAULT; // Soll-Temperatur 1 in 1/100 °C
|
||||
int16_t th1 = _SENSOR_FAULT; // Hysterese für Temperatur 1 (1/100)
|
||||
int16_t ts2 = _SENSOR_FAULT; // Soll-Temperatur 2 in 1/100 °C
|
||||
int16_t th2 = _SENSOR_FAULT; // Hysterese für Temperatur 2 (1/100)
|
||||
int16_t ps = _SENSOR_FAULT; // Druck in bar
|
||||
int16_t ph = _SENSOR_FAULT; // Hysterese für Druck
|
||||
uint8_t tEn = 255; // Kühlung (de)aktiviert
|
||||
uint8_t pInc = 255; // Drucksteigerung (de)aktiviert
|
||||
uint8_t pDec = 255; // Druckabfall (de)aktiviert
|
||||
uint8_t cEn = 255; // Controller (de)aktiviert
|
||||
};
|
||||
|
||||
struct values { // aktuelle Messwerte
|
||||
int16_t t1 = _SENSOR_FAULT; // Temperatur in 1/100 °C
|
||||
int16_t p = _SENSOR_FAULT; // Druck in 1/100 bar
|
||||
};
|
||||
|
||||
struct modbusParameters { // Parameter für Modbus
|
||||
uint32_t baudrate = _MODBUS_INVALID_BAUDRATE; // Modbus-Baudrate
|
||||
uint8_t address = 255; // Modbus-Adresse
|
||||
uint8_t delay = 255; // delay in 1/10 ms vor der Antwort
|
||||
};
|
||||
|
||||
struct valveStates {
|
||||
bool t1;
|
||||
bool t2;
|
||||
bool pInc;
|
||||
bool pDec;
|
||||
};
|
||||
extern void checkModbusParams();
|
||||
extern void setupModbus(const u16&);
|
||||
extern void beginModbus();
|
||||
extern void modbusCallbackCoil(u16 reg, bool val);
|
||||
extern u16 modbusCallbackRegister(u16 reg, u16 val);
|
||||
#endif // _MODBUS
|
||||
|
||||
#endif // _MY_STUFF_H_INCLUDED
|
||||
|
|
|
@ -1,23 +1,16 @@
|
|||
#include "controller.h"
|
||||
#include "../faults/faults.h"
|
||||
|
||||
extern u32 currMillis;
|
||||
|
||||
Controller::Controller(const uint8_t pAnalaogPin,
|
||||
const uint8_t oneWirePin,
|
||||
parameters *p,
|
||||
values *v,
|
||||
Display *d,
|
||||
PSensor *s,
|
||||
valveStates *vStates,
|
||||
const uint8_t t1Pin,
|
||||
const uint8_t t2Pin,
|
||||
const uint8_t pRisePin,
|
||||
const uint8_t pFallPin)
|
||||
: _aPin(pAnalaogPin)
|
||||
, _oneWire(oneWirePin)
|
||||
, _params(p)
|
||||
, _vals(v)
|
||||
, _display(d)
|
||||
, _pSensor(s)
|
||||
, _vStates(vStates)
|
||||
, _prPin(pRisePin)
|
||||
, _pfPin(pFallPin)
|
||||
, _t1Pin(t1Pin)
|
||||
|
@ -32,9 +25,9 @@ Controller::Controller(const uint8_t pAnalaogPin,
|
|||
digitalWrite(_pfPin, 0);
|
||||
digitalWrite(_t1Pin, 0);
|
||||
digitalWrite(_t2Pin, 0);
|
||||
_vStates->pInc = false;
|
||||
_vStates->pDec = false;
|
||||
_vStates->t1 = false;
|
||||
vStates.pInc = false;
|
||||
vStates.pDec = false;
|
||||
vStates.t1 = false;
|
||||
}
|
||||
|
||||
void Controller::init(bool startup=false)
|
||||
|
@ -44,60 +37,69 @@ void Controller::init(bool startup=false)
|
|||
const uint8_t maxDevices = 1;
|
||||
uint8_t deviceCount = _dallas.getDS18Count();
|
||||
if (deviceCount > maxDevices) {
|
||||
_display->tooMuchOneWireDevicesDetected(deviceCount, maxDevices);
|
||||
display.tooMuchOneWireDevicesDetected(deviceCount, maxDevices);
|
||||
} else if (!deviceCount) {
|
||||
_display->noOneWireDevicesDetected();
|
||||
display.noOneWireDevicesDetected();
|
||||
} else {
|
||||
_initOk = true;
|
||||
_dallas.getAddress(_tempAddr1, 0);
|
||||
_dallas.setResolution(12);
|
||||
if (!startup)
|
||||
_display->oneWireDevicesDetected(deviceCount);
|
||||
display.oneWireDevicesDetected(deviceCount);
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::process()
|
||||
{
|
||||
if (_initOk && millis() - _lastConversion > _TEMP_CONVERSION_DELAY) {
|
||||
_lastConversion = millis();
|
||||
if (_initOk && currMillis - _lastConversion > _TEMP_CONVERSION_DELAY) {
|
||||
_lastConversion = currMillis;
|
||||
_requestConversion = true;
|
||||
float temp = _dallas.getTempC(_tempAddr1);
|
||||
if (temp == DEVICE_DISCONNECTED_C)
|
||||
_vals->t1 = _SENSOR_FAULT;
|
||||
vals.t1 = _SENSOR_FAULT;
|
||||
else
|
||||
_vals->t1 = temp * 100;
|
||||
_prints("Temp: "); _prints(_vals->t1);
|
||||
if (_vals->t1 != _SENSOR_FAULT && _params->tEn && _params->cEn) {
|
||||
vals.t1 = temp * 100;
|
||||
_printsf("Temp: "); _prints(vals.t1);
|
||||
if (vals.t1 != _SENSOR_FAULT && params.tEn && params.cEn) {
|
||||
switch (_tState) {
|
||||
case stateIdle:
|
||||
_printsln(", case stateIdle");
|
||||
if (_vals->t1 < _params->ts1 - _params->th1) {
|
||||
faults.t1Idle(vals.t1);
|
||||
_printslnf(", case stateIdle");
|
||||
if (vals.t1 < params.ts1 - params.th1) {
|
||||
_setT1Valve(0, stateRising);
|
||||
_prints(" -> rising");
|
||||
} else if (_vals->t1 > _params->ts1 + _params->th1) {
|
||||
_printsf(" -> rising");
|
||||
} else if (vals.t1 > params.ts1 + params.th1) {
|
||||
_setT1Valve(1, stateFalling);
|
||||
_prints(" -> falling");
|
||||
_printsf(" -> falling");
|
||||
}
|
||||
_printsln();
|
||||
break;
|
||||
case stateRising:
|
||||
_prints(", case stateRising");
|
||||
if (_vals->t1 > _params->ts1 + _params->th1) {
|
||||
faults.check(t1TooLo);
|
||||
_printsf(", case stateRising");
|
||||
if (vals.t1 > params.ts1 + params.th1) {
|
||||
_setT1Valve(1, stateIdle);
|
||||
_prints(" -> idle");
|
||||
_printsf(" -> idle");
|
||||
}
|
||||
_printsln();
|
||||
break;
|
||||
case stateFalling:
|
||||
_prints(", case stateFalling");
|
||||
if (_vals->t1 < _params->ts1 - _params->th1) {
|
||||
faults.check(t1TooHi);
|
||||
_printsf(", case stateFalling");
|
||||
if (vals.t1 < params.ts1 - params.th1) {
|
||||
_setT1Valve(0, stateIdle);
|
||||
_prints(" -> idle");
|
||||
_printsf(" -> idle");
|
||||
} else { // um ev. abschalten (Fehler) zu können
|
||||
_setT1Valve(1, stateFalling);
|
||||
}
|
||||
_printsln();
|
||||
break;
|
||||
}
|
||||
} else if (vals.t1 == _SENSOR_FAULT && params.tEn && params.cEn) {
|
||||
faults.check(t1Invalid);
|
||||
_setT1Valve(0, stateIdle);
|
||||
} else {
|
||||
faults.t1Idle();
|
||||
_setT1Valve(0, stateIdle);
|
||||
_printsln();
|
||||
}
|
||||
|
@ -105,51 +107,51 @@ void Controller::process()
|
|||
#if _MODBUS_AVERAGE_TEMPERATURES == 1
|
||||
_averageTemperature1();
|
||||
#else
|
||||
modbusData[_MODBUS_T1_INDEX] = _vals->t1;
|
||||
modbusData[_MODBUS_T1_INDEX] = vals.t1;
|
||||
#endif
|
||||
#endif
|
||||
} else if (_requestConversion) {
|
||||
_requestConversion = false;
|
||||
_dallas.requestTemperatures();
|
||||
}
|
||||
if (millis() - _lastAnalogRead > _ANALOG_READ_DELAY) {
|
||||
_lastAnalogRead = millis();
|
||||
if (currMillis - _lastAnalogRead > _ANALOG_READ_DELAY) {
|
||||
_lastAnalogRead = currMillis;
|
||||
_rawP = analogRead(_aPin);
|
||||
_prints("_rawP: "); _prints(_rawP);
|
||||
switch (*_pSensor) {
|
||||
_printsf("_rawP: "); _prints(_rawP);
|
||||
switch (pSensor) {
|
||||
case SMC_1_5V_0_5BAR:
|
||||
float p = (float) _rawP / 2.046f; // 1023 / 5 * 100 (0-5 1/100 bar)
|
||||
p = (p - 1) * 1.25f; // 1...5 V Sensor
|
||||
_prints(" (Gems), p: "); _prints(p);
|
||||
_printsf(" (Gems), p: "); _prints(p);
|
||||
if (p < -0.5f) // Sensor ist definitiv nicht angeschlossen
|
||||
_vals->p = _SENSOR_FAULT;
|
||||
vals.p = _SENSOR_FAULT;
|
||||
else if (p < 0) // Bei kleiner Toleranz ein bisschen schwindeln ;-)
|
||||
_vals->p = 0;
|
||||
vals.p = 0;
|
||||
else
|
||||
_vals->p = p;
|
||||
vals.p = p;
|
||||
break;
|
||||
case GEMS_0_5V_0_6BAR:
|
||||
_vals->p = (float) _rawP / 1.705f; // 1023 / 6 * 100 (0-5 1/100 bar)
|
||||
_prints(" (Gems), p: "); _prints(_vals->p);
|
||||
vals.p = (float) _rawP / 1.705f; // 1023 / 6 * 100 (0-5 1/100 bar)
|
||||
_printsf(" (Gems), p: "); _prints(vals.p);
|
||||
}
|
||||
#if _MODBUS == 1
|
||||
_averagePressure();
|
||||
#endif
|
||||
if (_vals->p != _SENSOR_FAULT && _params->cEn) {
|
||||
if (vals.p != _SENSOR_FAULT && params.cEn && (params.pInc || params.pDec)) {
|
||||
switch (_pState) {
|
||||
case stateIdle:
|
||||
_prints(", case stateIdle");
|
||||
if (_vals->p < _params->ps - _params->ph) {
|
||||
if (_params->pInc) {
|
||||
_printsln(" -> stateRising");
|
||||
faults.pIdle(_buildAveragePForFaultDetection());
|
||||
_p_i_fault_start = _p_i_curr;
|
||||
_printsf(", case stateIdle");
|
||||
if (vals.p < params.ps - params.ph) {
|
||||
if (params.pInc) {
|
||||
_printslnf(" -> stateRising");
|
||||
_setPValves(stateRising);
|
||||
} else {
|
||||
_printsln();
|
||||
_setPValves(stateIdle);
|
||||
}
|
||||
} else if (_vals->p > _params->ps + _params->ph) {
|
||||
if (_params->pDec) {
|
||||
_printsln(" -> stateFalling");
|
||||
} else if (vals.p > params.ps + params.ph) {
|
||||
if (params.pDec) {
|
||||
_printslnf(" -> stateFalling");
|
||||
_setPValves(stateFalling);
|
||||
} else {
|
||||
_printsln();
|
||||
|
@ -158,65 +160,85 @@ void Controller::process()
|
|||
} else _printsln();
|
||||
break;
|
||||
case stateRising:
|
||||
_prints(", case stateRising");
|
||||
if ((_params->pInc && _vals->p > _params->ps) || !_params->pInc) {
|
||||
_prints(" -> stateIdle");
|
||||
if (params.pInc)
|
||||
faults.check(pTooLo, _buildAveragePForFaultDetection());
|
||||
_printsf(", case stateRising");
|
||||
if ((params.pInc && vals.p > params.ps) || !params.pInc) {
|
||||
_printsf(" -> stateIdle");
|
||||
_setPValves(stateIdle);
|
||||
} else { // um ev. abschalten (Fehler) zu können
|
||||
_setPValves(stateRising);
|
||||
}
|
||||
_printsln();
|
||||
break;
|
||||
case stateFalling:
|
||||
_prints(", case stateFalling");
|
||||
if ((_params->pDec && _vals->p < _params->ps) || !_params->pDec) {
|
||||
_prints(" -> stateIdle");
|
||||
if (params.pDec)
|
||||
faults.check(pTooHi, _buildAveragePForFaultDetection());
|
||||
_printsf(", case stateFalling");
|
||||
if ((params.pDec && vals.p < params.ps) || !params.pDec) {
|
||||
_printsf(" -> stateIdle");
|
||||
_setPValves(stateIdle);
|
||||
} else { // um ev. abschalten (Fehler) zu können
|
||||
_setPValves(stateFalling);
|
||||
}
|
||||
_printsln();
|
||||
break;
|
||||
}
|
||||
} else if (vals.p == _SENSOR_FAULT && params.cEn && (params.pInc || params.pDec)) {
|
||||
_printsln();
|
||||
faults.check(pInvalid, _buildAveragePForFaultDetection());
|
||||
_setPValves(stateIdle);
|
||||
} else {
|
||||
_printsln();
|
||||
faults.pIdle();
|
||||
_setPValves(stateIdle);
|
||||
// faults.checkP(_buildAveragePForFaultDetection());
|
||||
// _p_i_fault_start = _p_i_curr;
|
||||
}
|
||||
_prints("_vStates->pInc: "); _prints(_vStates->pInc);
|
||||
_prints(", _vStates->pDec: "); _printsln(_vStates->pDec);
|
||||
_printsf("vStates.pInc: "); _prints(vStates.pInc);
|
||||
_printsf(", vStates.pDec: "); _printsln(vStates.pDec);
|
||||
}
|
||||
faults.process();
|
||||
}
|
||||
|
||||
void Controller::_setT1Valve(uint8_t val, States state)
|
||||
{
|
||||
_tState = state;
|
||||
if (faults.tActive() && !faultSettings.tOnIfError)
|
||||
val = 0; // Ventile ausschalten
|
||||
digitalWrite(_t1Pin, val);
|
||||
_vStates->t1 = val;
|
||||
vStates.t1 = val;
|
||||
_setModbusValve(_MODBUS_VALVE_T1_INDEX, val);
|
||||
}
|
||||
|
||||
void Controller::_setPValves(States state)
|
||||
{
|
||||
_pState = state;
|
||||
if (faults.pActive() && !faultSettings.pOnIfError)
|
||||
state = stateIdle; // Ventile ausschalten
|
||||
switch (state) {
|
||||
case stateRising:
|
||||
digitalWrite(_prPin, 1);
|
||||
_vStates->pInc = true;
|
||||
vStates.pInc = true;
|
||||
_setModbusValve(_MODBUS_VALVE_PR_INDEX, 1);
|
||||
digitalWrite(_pfPin, 0);
|
||||
_vStates->pDec = false;
|
||||
vStates.pDec = false;
|
||||
_setModbusValve(_MODBUS_VALVE_PF_INDEX, 0);
|
||||
break;
|
||||
case stateFalling:
|
||||
digitalWrite(_pfPin, 1);
|
||||
_vStates->pDec = true;
|
||||
vStates.pDec = true;
|
||||
_setModbusValve(_MODBUS_VALVE_PF_INDEX, 1);
|
||||
digitalWrite(_prPin, 0);
|
||||
_vStates->pInc = false;
|
||||
vStates.pInc = false;
|
||||
_setModbusValve(_MODBUS_VALVE_PR_INDEX, 0);
|
||||
break;
|
||||
default: // idle valves
|
||||
digitalWrite(_pfPin, 0);
|
||||
_vStates->pDec = false;
|
||||
vStates.pDec = false;
|
||||
_setModbusValve(_MODBUS_VALVE_PF_INDEX, 0);
|
||||
digitalWrite(_prPin, 0);
|
||||
_vStates->pInc = false;
|
||||
vStates.pInc = false;
|
||||
_setModbusValve(_MODBUS_VALVE_PR_INDEX, 0);
|
||||
}
|
||||
}
|
||||
|
@ -224,19 +246,19 @@ void Controller::_setPValves(States state)
|
|||
#if _MODBUS == 1
|
||||
void Controller::resetAverageCounters()
|
||||
{
|
||||
_print("Setze Zähler zurück (");
|
||||
_printbf("Setze Zähler zurück (");
|
||||
#if _MODBUS_AVERAGE_TEMPERATURES == 1
|
||||
_print("_t1_c: "); _print(_t1_c);
|
||||
_print(", _t2_c: "); _print(_t2_c);
|
||||
_print(", ");
|
||||
_printbf("_t1_c: "); _printb(_t1_c);
|
||||
_printbf(", _t2_c: "); _printb(_t2_c);
|
||||
_printbf(", ");
|
||||
_t1_c = 0;
|
||||
_t2_c = 0;
|
||||
_t1_of = false;
|
||||
_t2_of = false;
|
||||
#endif
|
||||
_print("_p_c: "); _print(_p_c); _println(")");
|
||||
_p_c = 0;
|
||||
_p_of = false;
|
||||
_printbf("_p_i_curr: "); _printb(_p_i_curr); _printblnf(")");
|
||||
_p_i_mb_start = _p_i_curr;
|
||||
_p_mb_full = false;
|
||||
}
|
||||
|
||||
#if _MODBUS_AVERAGE_TEMPERATURES == 1
|
||||
|
@ -251,7 +273,7 @@ inline void Controller::_averageTemperature1()
|
|||
_t1_of = true;
|
||||
}
|
||||
// Falls das Array schon voll ist, wird es wieder vom Anfang befüllt
|
||||
_t1_arr[_t1_c++] = _vals->t1;
|
||||
_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++) {
|
||||
|
@ -274,33 +296,113 @@ inline void Controller::_averageTemperature2()
|
|||
// noch nicht implementiert
|
||||
}
|
||||
#endif // _MODBUS_AVERAGE_TEMPERATURES == 1
|
||||
#endif // _MODBUS == 1
|
||||
|
||||
inline void Controller::_averagePressure()
|
||||
{
|
||||
// Falls das Ende des Arrays erreicht ist, wird es wieder vom Anfang befüllt
|
||||
if (_p_i_curr > _P_ARR_LEN) {
|
||||
_p_i_curr = 0;
|
||||
_p_mb_full = true;
|
||||
}
|
||||
_p_arr[_p_i_curr] = vals.p;
|
||||
#if _MODBUS == 1
|
||||
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++;
|
||||
u16 valid = 0;
|
||||
u16 invalid = 0;
|
||||
u16 i;
|
||||
if (_p_i_curr > _p_i_mb_start && !_p_mb_full) {
|
||||
for (i=_p_i_mb_start; i<_p_i_curr; i++) {
|
||||
if (_p_arr[i] != _SENSOR_FAULT) {
|
||||
total += _p_arr[i];
|
||||
valid++;
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
} else if (_p_i_curr < _p_i_mb_start && !_p_mb_full) {
|
||||
for (i=0; i<_p_i_curr; i++) {
|
||||
if (_p_arr[i] != _SENSOR_FAULT) {
|
||||
total += _p_arr[i];
|
||||
valid++;
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
for (i=_p_i_mb_start; i<_P_ARR_LEN; i++) {
|
||||
if (_p_arr[i] != _SENSOR_FAULT) {
|
||||
total += _p_arr[i];
|
||||
valid++;
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i=0; i<_P_ARR_LEN; 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
|
||||
_p_i_curr++;
|
||||
}
|
||||
|
||||
inline int16_t Controller::_buildAveragePForFaultDetection()
|
||||
{
|
||||
int32_t total = 0;
|
||||
int16_t result = _SENSOR_FAULT;
|
||||
u16 valid = 0;
|
||||
u16 invalid = 0;
|
||||
u16 i;
|
||||
if (_p_i_curr > _p_i_fault_start) {
|
||||
for (i=_p_i_fault_start; i<_p_i_curr; i++) {
|
||||
if (_p_arr[i] != _SENSOR_FAULT) {
|
||||
total += _p_arr[i];
|
||||
valid++;
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
} else if (_p_i_curr < _p_i_fault_start) {
|
||||
for (i=0; i<_p_i_curr; i++) {
|
||||
if (_p_arr[i] != _SENSOR_FAULT) {
|
||||
total += _p_arr[i];
|
||||
valid++;
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
for (i=_p_i_fault_start; i<_P_ARR_LEN; i++) {
|
||||
if (_p_arr[i] != _SENSOR_FAULT) {
|
||||
total += _p_arr[i];
|
||||
valid++;
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i=0; i<_P_ARR_LEN; i++) {
|
||||
if (_p_arr[i] != _SENSOR_FAULT) {
|
||||
total += _p_arr[i];
|
||||
valid++;
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (valid >= invalid) {
|
||||
result = total / valid;
|
||||
}
|
||||
// _p_i_fault_start = _p_i_curr;
|
||||
// _printf("Durchschnittsdruck: "); _println(result);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -4,26 +4,26 @@
|
|||
#include "../OneWire/OneWire.h"
|
||||
#include "../DallasTemperature/DallasTemperature.h"
|
||||
#include "../display/display.h"
|
||||
#include "../common.h"
|
||||
#include "../faults/faults.h"
|
||||
#include "../macros.h"
|
||||
#include "../types.h"
|
||||
|
||||
#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 _P_ARR_LEN (409600 / _ANALOG_READ_DELAY) + 1
|
||||
#if _MODBUS_AVERAGE_TEMPERATURES == 1
|
||||
#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)
|
||||
#if _MODBUS_AVERAGE_TEMPERATURES == 1
|
||||
// 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
|
||||
#endif
|
||||
|
||||
extern u16 modbusData[];
|
||||
extern Display display;
|
||||
|
||||
class Controller
|
||||
{
|
||||
private:
|
||||
const uint8_t _aPin;
|
||||
parameters *_params;
|
||||
values *_vals;
|
||||
Display *_display;
|
||||
PSensor *_pSensor;
|
||||
valveStates *_vStates;
|
||||
uint8_t _prPin;
|
||||
uint8_t _pfPin;
|
||||
uint8_t _t1Pin;
|
||||
|
@ -38,8 +38,10 @@ private:
|
|||
bool _t2_of = false; // Flag, die anzeigt, ob das _t2_arr-Array schon voll ist
|
||||
#endif
|
||||
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
|
||||
u16 _p_i_curr = 0; // Aktueller Index des _p_arr-Arrays
|
||||
u16 _p_i_mb_start = 0;
|
||||
u16 _p_i_fault_start = 0;
|
||||
bool _p_mb_full = false; // ob das _p_arr-Array für Modbus komplett gelesen werden soll
|
||||
|
||||
OneWire _oneWire;
|
||||
DallasTemperature _dallas;
|
||||
|
@ -53,31 +55,33 @@ private:
|
|||
bool _requestConversion;
|
||||
unsigned long _lastConversion;
|
||||
unsigned long _lastAnalogRead;
|
||||
uint16_t _rawP;
|
||||
u16 _rawP;
|
||||
|
||||
// u32 _lastT1Idle;
|
||||
// u32 _lastT2Idle;
|
||||
// u32 _lastPIdle;
|
||||
// u32 _lastFaultCheck;
|
||||
// u32 _lastT2checked;
|
||||
// u32 _lastPchecked;
|
||||
|
||||
void _setT1Valve(uint8_t, States);
|
||||
void _setPValves(States);
|
||||
|
||||
#if _MODBUS == 1
|
||||
#if _MODBUS_AVERAGE_TEMPERATURES == 1
|
||||
void _averageTemperature1();
|
||||
void _averageTemperature2();
|
||||
void _averagePressure();
|
||||
#endif
|
||||
#endif // _MODBUS_AVERAGE_TEMPERATURES == 1
|
||||
inline void _averagePressure();
|
||||
inline int16_t _buildAveragePForFaultDetection();
|
||||
|
||||
public:
|
||||
Controller(const uint8_t pAnalaogPin,
|
||||
const uint8_t oneWirePin,
|
||||
parameters *p,
|
||||
values *vals,
|
||||
Display *d,
|
||||
PSensor *s,
|
||||
valveStates *vStates,
|
||||
const uint8_t pRisePin,
|
||||
const uint8_t t1Pin,
|
||||
const uint8_t t2Pin,
|
||||
const uint8_t pFallPin
|
||||
);
|
||||
|
||||
void init(bool startup=false);
|
||||
void process();
|
||||
#if _MODBUS == 1
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,9 @@
|
|||
#define MY_DISPLAY_H_INCLUDED
|
||||
|
||||
#include <U8g2lib.h>
|
||||
#include "../common.h"
|
||||
#include "../types.h"
|
||||
#include "../macros.h"
|
||||
#include "../faults/faults.h"
|
||||
|
||||
//#define _STD_FONT u8g2_font_ncenB10_te
|
||||
//#define _FIRS_LINE_Y 11
|
||||
|
@ -13,11 +15,10 @@
|
|||
#define _SEL_FONT u8g2_font_6x10_tf
|
||||
#define _FIRS_LINE_Y 12
|
||||
#define _STD_LINEHEIGHT 13
|
||||
// Mit der Schriftart u8g2_font_ncenB10_te stellt \xb0 das °-Zeichen dar
|
||||
|
||||
#define _BEGIN_FAST_STEPS_DELAY 500
|
||||
#define _BEGIN_BIG_STEPS_DELAY 3000
|
||||
#define _FAST_STEP_MS 100
|
||||
#define _FAST_STEP_MS 110
|
||||
#define _BIG_STEP 10
|
||||
|
||||
#define _BACK_TO_HOME_SCREEN 1
|
||||
|
@ -27,6 +28,10 @@
|
|||
#define _MENU_SETTINGS_MODBUS 11
|
||||
#define _MENU_TEMPERATURE 12
|
||||
#define _MENU_PRESSURE 13
|
||||
#define _MENU_FAULTS_MAIN 20
|
||||
#define _MENU_FAULTS_OPEN 21
|
||||
#define _MENU_FAULTS_SETTINGS 22
|
||||
|
||||
#define _SELECTION_TEMPERATURE_ENABLED 100
|
||||
#define _SELECTION_TEMPERATURE_SETPOINT 101
|
||||
#define _SELECTION_TEMPERATURE_HYSTERESIS 102
|
||||
|
@ -34,12 +39,22 @@
|
|||
#define _SELECTION_PRESSURE_ENABLE_DECREASE 111
|
||||
#define _SELECTION_PRESSURE_SETPOINT 115
|
||||
#define _SELECTION_PRESSURE_HYSTERESIS 116
|
||||
#define _SELECTION_FAULTS_ACOUSTIC 125
|
||||
#define _SELECTION_FAULTS_OPTICAL 126
|
||||
#define _SELECTION_FAULTS_T_OFF 127
|
||||
#define _SELECTION_FAULTS_P_OFF 128
|
||||
#define _SELECTION_FAULTS_T_R_RATE 129
|
||||
#define _SELECTION_FAULTS_T_F_RATE 130
|
||||
#define _SELECTION_FAULTS_P_RATE 131
|
||||
#define _SELECTION_MODBUS_BAUDRATE 150
|
||||
#define _SELECTION_MODBUS_ADDRESS 151
|
||||
#define _SELECTION_MODBUS_DELAY 152
|
||||
#define _SELECTION_P_SENSOR 200
|
||||
#define _SELECTION_CLEAR_FAULTS 220
|
||||
#define _SELECTION_RESET 255
|
||||
|
||||
#define _FAULT_INFO 170
|
||||
|
||||
#define _VERIFY_ADMIN 253
|
||||
#define _ADMIN_CODE 42
|
||||
|
||||
|
@ -52,7 +67,18 @@
|
|||
#define _POS_PRESSURE_ENABLE_DECREASE 1
|
||||
#define _POS_PRESSURE_SETPOINT 2
|
||||
#define _POS_PRESSURE_HYSTERESIS 3
|
||||
#define _POS_SYSTEM 2
|
||||
#define _POS_FAULTS_MAIN 2
|
||||
#define _POS_FAULTS_OPEN 0
|
||||
#define _POS_FAULTS_CLEAR 1
|
||||
#define _POS_FAULTS_SETTINGS 2
|
||||
#define _POS_FAULTS_ACOUSTIC 0
|
||||
#define _POS_FAULTS_OPTICAL 1
|
||||
#define _POS_FAULTS_T_OFF 2
|
||||
#define _POS_FAULTS_P_OFF 3
|
||||
#define _POS_FAULTS_T_R_RATE 4
|
||||
#define _POS_FAULTS_T_F_RATE 5
|
||||
#define _POS_FAULTS_P_RATE 6
|
||||
#define _POS_SYSTEM 3
|
||||
#define _POS_MODBUS_MENU 0
|
||||
#define _POS_MODBUS_ADDRESS 0
|
||||
#define _POS_MODBUS_BAUDRATE 1
|
||||
|
@ -60,7 +86,7 @@
|
|||
#define _POS_P_SENSOR_SELECTION 1
|
||||
#define _POS_P_SMC_1_5V_0_5BAR 0
|
||||
#define _POS_P_GEMS_0_5V_0_6BAR 1
|
||||
#define _POS_RESET 3
|
||||
#define _POS_RESET 4
|
||||
|
||||
#define _POS_BAUDRATE_300 0
|
||||
#define _POS_BAUDRATE_1200 1
|
||||
|
@ -110,12 +136,15 @@ private:
|
|||
unsigned long _checkFastStepTime; // letzte Zeit, zu der ein entsprechender Button NICHT gedrückt war
|
||||
unsigned long _lastFastStep; // letzte Zeit, zu der ein schneller Schritt ausgeführt wurde
|
||||
int _stepSize; // Um wieviel der entsprechende Wert auf einmal geändert werden soll
|
||||
|
||||
parameters *_params;
|
||||
values *_vals;
|
||||
modbusParameters *_modbusParams;
|
||||
PSensor *_pSensor;
|
||||
valveStates *_vStates;
|
||||
u8 _fastStepsDelay;
|
||||
bool _showFault;
|
||||
u8 _showFaultC = 0;
|
||||
FaultState _lastFaultState = noFault;
|
||||
u8 _lastCEn;
|
||||
u8 _lastOpticalState;
|
||||
u8 _currBrightness = 0;
|
||||
u32 _lastBrightnessChange;
|
||||
bool _incBrightness = false;
|
||||
|
||||
void _saveCursorPosForLevel(MenuLevel);
|
||||
uint8_t _restoreCursor();
|
||||
|
@ -127,6 +156,7 @@ private:
|
|||
void _nextEvent();
|
||||
void _prevEvent();
|
||||
void _home();
|
||||
bool _displayFaultOrPowerSymbol(const FaultState&, bool);
|
||||
void _inputValue(const uint8_t stepSize, const char *title, const char *text=nullptr, const char *val=nullptr);
|
||||
void _restrictInputValue(int min, int max, Precision p=Precision_0);
|
||||
|
||||
|
@ -143,12 +173,7 @@ public:
|
|||
uint8_t btnPrev,
|
||||
uint8_t btnSelect,
|
||||
uint8_t btnCancel,
|
||||
uint8_t bgLED,
|
||||
parameters*,
|
||||
values*,
|
||||
modbusParameters*,
|
||||
PSensor*,
|
||||
valveStates*);
|
||||
uint8_t bgLED);
|
||||
|
||||
void init();
|
||||
void process();
|
||||
|
@ -168,11 +193,6 @@ public:
|
|||
bool bgLightState();
|
||||
|
||||
void (*reset)() = 0;
|
||||
|
||||
/* Callback-Funktionen */
|
||||
void(*setParams)(parameters&);
|
||||
void(*setModbusParams)(const modbusParameters&);
|
||||
void(*setPSensor)(const PSensor&);
|
||||
};
|
||||
|
||||
#endif // MY_DISPLAY_H_INCLUDED
|
||||
|
|
|
@ -0,0 +1,683 @@
|
|||
#include "faults.h"
|
||||
#include "../types.h"
|
||||
#include "../mystrings/mystrings.h"
|
||||
#include "../macros.h"
|
||||
#include <EEPROM.h>
|
||||
|
||||
extern u32 currMillis;
|
||||
extern u16 zones;
|
||||
extern u16 modbusAlarms[];
|
||||
|
||||
const u16 EEPROM_FAULTS[] = {
|
||||
_EEPROM_FAULT_1, _EEPROM_FAULT_2, _EEPROM_FAULT_3,_EEPROM_FAULT_4, _EEPROM_FAULT_5,
|
||||
_EEPROM_FAULT_6, _EEPROM_FAULT_7, _EEPROM_FAULT_8, _EEPROM_FAULT_9, _EEPROM_FAULT_10,
|
||||
_EEPROM_FAULT_11, _EEPROM_FAULT_12, _EEPROM_FAULT_13, _EEPROM_FAULT_14, _EEPROM_FAULT_15,
|
||||
_EEPROM_FAULT_16, _EEPROM_FAULT_17, _EEPROM_FAULT_18, _EEPROM_FAULT_19, _EEPROM_FAULT_20,
|
||||
_EEPROM_FAULT_21, _EEPROM_FAULT_22, _EEPROM_FAULT_23, _EEPROM_FAULT_24, _EEPROM_FAULT_25,
|
||||
_EEPROM_FAULT_26, _EEPROM_FAULT_27, _EEPROM_FAULT_28, _EEPROM_FAULT_29, _EEPROM_FAULT_30
|
||||
};
|
||||
|
||||
Fault::Fault()
|
||||
: code(invalidCode)
|
||||
, active(false)
|
||||
{
|
||||
}
|
||||
|
||||
Fault::Fault(FaultCode fcode, const u16 id_)
|
||||
: code(fcode)
|
||||
, id(id_)
|
||||
, counterActivated(0)
|
||||
, counterDeactivated(0)
|
||||
{
|
||||
timeActivated = currMillis;
|
||||
}
|
||||
|
||||
Fault::Fault(const Fault &other)
|
||||
{
|
||||
id = other.id;
|
||||
code = other.code;
|
||||
timeActivated = other.timeActivated;
|
||||
timeDeactivated = other.timeDeactivated;
|
||||
timeActivatedOverflow = other.timeActivatedOverflow;
|
||||
timeDeactivatedOverflow = other.timeDeactivatedOverflow;
|
||||
active = other.active;
|
||||
counterActivated = other.counterActivated;
|
||||
counterDeactivated = other.counterDeactivated;
|
||||
_of1 = other._of1;
|
||||
_of2 = other._of2;
|
||||
}
|
||||
|
||||
Fault::Fault(const SavedFault &other)
|
||||
{
|
||||
id = other.id;
|
||||
code = other.code;
|
||||
active = other.active;
|
||||
counterActivated = other.counterActivated + 1;
|
||||
if (other.deactivated) {
|
||||
timeDeactivated = 0;
|
||||
counterDeactivated = other.counterDeactivated + 1;
|
||||
} else {
|
||||
counterDeactivated = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char __buff_1[30];
|
||||
|
||||
const char* Fault::title()
|
||||
{
|
||||
switch(code) {
|
||||
case t1TooHi:
|
||||
(zones > 1) ? getMyStr200(STR_T1_TOO_HI) : getMyStr200(STR_T_TOO_HI);
|
||||
break;
|
||||
case t1TooLo:
|
||||
(zones > 1) ? getMyStr200(STR_T1_TOO_LO) : getMyStr200(STR_T_TOO_LO);
|
||||
break;
|
||||
case t2TooHi:
|
||||
getMyStr200(STR_T2_TOO_HI);
|
||||
break;
|
||||
case t2TooLo:
|
||||
getMyStr200(STR_T2_TOO_LO);
|
||||
break;
|
||||
case pTooHi:
|
||||
getMyStr200(STR_P_TOO_HI);
|
||||
break;
|
||||
case pTooLo:
|
||||
getMyStr200(STR_P_TOO_LO);
|
||||
break;
|
||||
case t1Invalid:
|
||||
case t2Invalid:
|
||||
getMyStr200(STR_T_FAIL);
|
||||
break;
|
||||
case pInvalid:
|
||||
getMyStr200(STR_P_FAIL);
|
||||
break;
|
||||
default:
|
||||
getMyStr200(STR_UNKNOWN_ERROR);
|
||||
}
|
||||
if (active) {
|
||||
strcpy(__buff_1, "*");
|
||||
strcat(__buff_1, charBuffer200);
|
||||
return __buff_1;
|
||||
}
|
||||
return charBuffer200;
|
||||
}
|
||||
|
||||
const char* Fault::activatedText()
|
||||
{
|
||||
const u32 diff = currMillis - timeActivated;
|
||||
u16 result;
|
||||
if (counterActivated) {
|
||||
sprintf(__buff_1, getMyStr200(STR_UNKNOWN_ACTIVATED), counterActivated);
|
||||
} else if (timeActivatedOverflow) {
|
||||
return getMyStr200(STR_GT_7_WEEKS_1);
|
||||
} else if (diff < 100000) { // < 100 Sekunden
|
||||
result = diff / 1000;
|
||||
sprintf(__buff_1, getMyStr200(STR_F_SECONDS_1), result);
|
||||
} else if (diff < 6000000) { // < 100 Minuten
|
||||
result = diff / 60000;
|
||||
sprintf(__buff_1, getMyStr200(STR_F_MINUTES_1), result);
|
||||
} else if (diff < 172800000) { // < 48 Stunden
|
||||
result = diff / 3600000;
|
||||
sprintf(__buff_1, getMyStr200(STR_F_HOURS_1), result);
|
||||
} else { // Tage
|
||||
result = diff / 86400000;
|
||||
sprintf(__buff_1, getMyStr200(STR_F_DAYS_1), result);
|
||||
}
|
||||
return __buff_1;
|
||||
}
|
||||
|
||||
const char* Fault::deactivatedText()
|
||||
{
|
||||
const u32 diff = currMillis - timeDeactivated;
|
||||
u16 result;
|
||||
if (timeDeactivatedOverflow) {
|
||||
return getMyStr200(STR_GT_7_WEEKS_2);
|
||||
} else if (counterDeactivated) {
|
||||
sprintf(__buff_1, getMyStr200(STR_UNKNOWN_DEACTIVAED), counterDeactivated);
|
||||
} else if (timeDeactivated == 0xFFFFFFFF) { // wurde nie deaktiviert
|
||||
sprintf(__buff_1, (active) ? getMyStr200(STR_NEVER_DEACTIVATED_ACTIVE) : getMyStr200(STR_NEVER_DEACTIVATED_INACTIVE));
|
||||
} else if (diff < 100000) { // < 100 Sekunden
|
||||
result = diff / 1000;
|
||||
sprintf(__buff_1, getMyStr200(STR_F_SECONDS_2), result);
|
||||
} else if (diff < 6000000) { // < 100 Minuten
|
||||
result = diff / 60000;
|
||||
sprintf(__buff_1, getMyStr200(STR_F_MINUTES_2), result);
|
||||
} else if (diff < 172800000) { // < 48 Stunden
|
||||
result = diff / 3600000;
|
||||
sprintf(__buff_1, getMyStr200(STR_F_HOURS_2), result);
|
||||
} else { // Tage
|
||||
result = diff / 86400000;
|
||||
sprintf(__buff_1, getMyStr200(STR_F_DAYS_2), result);
|
||||
}
|
||||
return __buff_1;
|
||||
}
|
||||
|
||||
void Fault::process()
|
||||
{
|
||||
if (!counterActivated) {
|
||||
if (!_of1 && currMillis < timeActivated)
|
||||
_of1 = true;
|
||||
else if (!timeActivatedOverflow && _of1 && currMillis > timeActivated)
|
||||
timeActivatedOverflow = true;
|
||||
if (!active && !_of2 && currMillis < timeDeactivated)
|
||||
_of2 = true;
|
||||
else if (!timeDeactivatedOverflow && _of2 && currMillis > timeDeactivated)
|
||||
timeDeactivatedOverflow = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FaultSettings faultSettings;
|
||||
|
||||
FaultList::FaultList()
|
||||
{
|
||||
EEPROM.get(_EEPROM_FAULT_LAST_ID, _lastID);
|
||||
if (_lastID == 0xFFFF)
|
||||
_lastID = 0;
|
||||
uint8_t count = EEPROM.read(_EEPROM_FAULT_COUNT);
|
||||
_size = (count > _MAX_FAULTS) ? 0 : count;
|
||||
for (u8 i=0; i<_size; i++) {
|
||||
SavedFault savedFault;
|
||||
u16 id, reg_1, reg_2;
|
||||
EEPROM.get(EEPROM_FAULTS[i], id);
|
||||
EEPROM.get(EEPROM_FAULTS[i] + 2, reg_1);
|
||||
EEPROM.get(EEPROM_FAULTS[i] + 4, reg_2);
|
||||
u8 rawCode = reg_1 >> 12;
|
||||
if (reg_2 >> 14 || rawCode > 9 || id == 0 || id == 0xFFFF) {
|
||||
// unter einer dieser Bedingungen wären die Daten nicht gültig
|
||||
savedFault.id = 0;
|
||||
savedFault.code = invalidCode;
|
||||
savedFault.active = false;
|
||||
savedFault.deactivated = true;
|
||||
savedFault.counterActivated = 0;
|
||||
savedFault.counterDeactivated = 0;
|
||||
} else {
|
||||
savedFault.id = id;
|
||||
savedFault.counterActivated = reg_1 & 0xFFF;
|
||||
savedFault.counterDeactivated = reg_2 & 0xFFF;
|
||||
savedFault.active = bitRead(reg_2, 12);
|
||||
savedFault.deactivated = bitRead(reg_2, 13);
|
||||
switch (rawCode) {
|
||||
case t1TooHi:
|
||||
savedFault.code = t1TooHi;
|
||||
if (savedFault.active) {
|
||||
_lastActiveT1Fault = savedFault.code;
|
||||
_t1Active = true;
|
||||
}
|
||||
break;
|
||||
case t1TooLo:
|
||||
savedFault.code = t1TooLo;
|
||||
if (savedFault.active) {
|
||||
_lastActiveT1Fault = savedFault.code;
|
||||
_t1Active = true;
|
||||
}
|
||||
break;
|
||||
case t1Invalid:
|
||||
savedFault.code = t1Invalid;
|
||||
if (savedFault.active) {
|
||||
_lastActiveT1Fault = savedFault.code;
|
||||
_t1Active = true;
|
||||
}
|
||||
break;
|
||||
case t2TooHi:
|
||||
savedFault.code = t2TooHi;
|
||||
if (savedFault.active) {
|
||||
_lastActiveT2Fault = savedFault.code;
|
||||
_t2Active = true;
|
||||
}
|
||||
break;
|
||||
case t2TooLo:
|
||||
savedFault.code = t2TooLo;
|
||||
if (savedFault.active) {
|
||||
_lastActiveT2Fault = savedFault.code;
|
||||
_t2Active = true;
|
||||
}
|
||||
break;
|
||||
case t2Invalid:
|
||||
savedFault.code = t2Invalid;
|
||||
if (savedFault.active) {
|
||||
_lastActiveT2Fault = savedFault.code;
|
||||
_t2Active = true;
|
||||
}
|
||||
break;
|
||||
case pTooHi:
|
||||
savedFault.code = pTooHi;
|
||||
if (savedFault.active) {
|
||||
_lastActivePFault = savedFault.code;
|
||||
_pActive = true;
|
||||
}
|
||||
break;
|
||||
case pTooLo:
|
||||
savedFault.code = pTooLo;
|
||||
if (savedFault.active) {
|
||||
_lastActivePFault = savedFault.code;
|
||||
_pActive = true;
|
||||
}
|
||||
break;
|
||||
case pInvalid:
|
||||
savedFault.code = pInvalid;
|
||||
if (savedFault.active) {
|
||||
_lastActivePFault = savedFault.code;
|
||||
_pActive = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
savedFault.code = invalidCode;
|
||||
}
|
||||
}
|
||||
_list[i] = savedFault;
|
||||
_save(i);
|
||||
#if _MODBUS == 1
|
||||
_setModbusAlarm(_list[i], i, true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void FaultList::process()
|
||||
{
|
||||
FaultState s = noFault;
|
||||
for (u8 i=0; i<_size; i++) {
|
||||
Fault &f = _list[i];
|
||||
f.process();
|
||||
bool wasActive = f.active;
|
||||
switch (f.code) {
|
||||
case t1TooHi:
|
||||
case t1TooLo:
|
||||
case t1Invalid:
|
||||
_test(f, _t1Active, _lastActiveT1Fault);
|
||||
break;
|
||||
case t2TooHi:
|
||||
case t2TooLo:
|
||||
case t2Invalid:
|
||||
_test(f, _t2Active, _lastActiveT2Fault);
|
||||
break;
|
||||
case pTooHi:
|
||||
case pTooLo:
|
||||
case pInvalid:
|
||||
_test(f, _pActive, _lastActivePFault);
|
||||
}
|
||||
switch (s) {
|
||||
case inactiveFault:
|
||||
if (f.active)
|
||||
s = activeFault;
|
||||
break;
|
||||
case activeFault:
|
||||
break;
|
||||
default: // noFault
|
||||
s = (f.active) ? activeFault : inactiveFault;
|
||||
}
|
||||
if (f.active != wasActive) {
|
||||
// _printf("save in process(): ");
|
||||
_save(i);
|
||||
}
|
||||
#if _MODBUS == 1
|
||||
_setModbusAlarm(f, i, false);
|
||||
#endif
|
||||
}
|
||||
_state = s;
|
||||
}
|
||||
|
||||
bool FaultList::check(FaultCode code, int16_t val=0)
|
||||
{
|
||||
if (_size >= _MAX_FAULTS)
|
||||
return false;
|
||||
switch (code) {
|
||||
case t1TooHi:
|
||||
if (code == _lastActiveT1Fault || currMillis - _lastT1Idle < _CHECK_T_FAULT_INTERVAL
|
||||
|| faultSettings.tMinFRate < _compT1 - vals.t1)
|
||||
return false;
|
||||
_t1Active = true;
|
||||
_lastActiveT1Fault = code;
|
||||
break;
|
||||
case t1TooLo:
|
||||
if (code == _lastActiveT1Fault || currMillis - _lastT1Idle < _CHECK_T_FAULT_INTERVAL
|
||||
|| faultSettings.tMinFRate < vals.t1 - _compT1)
|
||||
return false;
|
||||
_t1Active = true;
|
||||
_lastActiveT1Fault = code;
|
||||
break;
|
||||
case t1Invalid:
|
||||
if (code == _lastActiveT1Fault || currMillis - _lastT1Idle < _CHECK_T_FAULT_INTERVAL)
|
||||
return false;
|
||||
_t1Active = true;
|
||||
_lastActiveT1Fault = code;
|
||||
break;
|
||||
case t2TooHi:
|
||||
if (code == _lastActiveT2Fault || currMillis - _lastT2Idle < _CHECK_T_FAULT_INTERVAL
|
||||
|| faultSettings.tMinFRate < _compT2 - vals.t2)
|
||||
return false;
|
||||
_t2Active = true;
|
||||
_lastActiveT2Fault = code;
|
||||
break;
|
||||
case t2TooLo:
|
||||
if (code == _lastActiveT2Fault || currMillis - _lastT2Idle < _CHECK_T_FAULT_INTERVAL
|
||||
|| faultSettings.tMinFRate < vals.t2 - _compT2)
|
||||
return false;
|
||||
_t2Active = true;
|
||||
_lastActiveT2Fault = code;
|
||||
break;
|
||||
case t2Invalid:
|
||||
if (code == _lastActiveT2Fault || currMillis - _lastT2Idle < _CHECK_T_FAULT_INTERVAL)
|
||||
return false;
|
||||
_t2Active = true;
|
||||
_lastActiveT2Fault = code;
|
||||
break;
|
||||
case pTooHi:
|
||||
if (code == _lastActivePFault || currMillis - _lastPIdle < _CHECK_P_FAULT_INTERVAL
|
||||
|| faultSettings.pMinRate < _compP - val)
|
||||
return false;
|
||||
_pActive = true;
|
||||
_lastActivePFault = code;
|
||||
break;
|
||||
case pTooLo:
|
||||
if (code == _lastActivePFault || currMillis - _lastPIdle < _CHECK_P_FAULT_INTERVAL
|
||||
|| faultSettings.pMinRate < val - _compP)
|
||||
return false;
|
||||
_pActive = true;
|
||||
_lastActivePFault = code;
|
||||
break;
|
||||
case pInvalid:
|
||||
if (code == _lastActivePFault || currMillis - _lastPIdle < _CHECK_P_FAULT_INTERVAL)
|
||||
return false;
|
||||
_pActive = true;
|
||||
_lastActivePFault = code;
|
||||
break;
|
||||
}
|
||||
_lastID++;
|
||||
if (_lastID == 0xFFFF || _lastID == 0)
|
||||
_lastID = 1;
|
||||
Fault f(code, _lastID);
|
||||
// _printf("Nächste Alarm-ID: "); _println(_lastID);
|
||||
_list[_size] = f;
|
||||
// _printf("save in check(): ");
|
||||
_save(_size);
|
||||
_saveLastID();
|
||||
_size++;
|
||||
_saveSize();
|
||||
#if _MODBUS == 1
|
||||
_setModbusAlarm(f, _size - 1, true);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
u8 FaultList::count()
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
Fault* FaultList::first()
|
||||
{
|
||||
if (_size)
|
||||
return &_list[0];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Fault* FaultList::last()
|
||||
{
|
||||
if (_size)
|
||||
return &_list[_size-1];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Fault* FaultList::at(const u8 position)
|
||||
{
|
||||
if (position < _size)
|
||||
return &_list[position];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FaultList::removeID(const u16 id)
|
||||
{
|
||||
for (u8 i=0; i<_size; i++) {
|
||||
if (_list[i].id == id) {
|
||||
return removeOne(i);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FaultList::removeOne(const u8 position)
|
||||
{
|
||||
if (position < _size) {
|
||||
if (_list[position].active)
|
||||
return false; // aktiver Fehler soll nicht gelöscht werden!
|
||||
u8 i;
|
||||
for (i=position; i<_size; i++) {
|
||||
if (i < _MAX_FAULTS - 1)
|
||||
_list[i] = _list[i + 1];
|
||||
}
|
||||
_size--;
|
||||
#if _MODBUS == 1
|
||||
if (!_size)
|
||||
// normalerweise wird der Alarm-Counter in _setModbusAlarm() gesetzt,
|
||||
// aber wenn _size == 0, muss der Counter extra zurückgesetzt werden
|
||||
modbusAlarms[0] = 0;
|
||||
#endif
|
||||
if (!_removeAllActive) {
|
||||
for (i=0; i<_size; i++)
|
||||
_save(i);
|
||||
_saveSize();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FaultList::removeAll()
|
||||
{
|
||||
bool atLeastOneRemoved = false;
|
||||
if (!_size) {
|
||||
return false;
|
||||
} else if (_state != activeFault) {
|
||||
_size = 0;
|
||||
_saveSize();
|
||||
atLeastOneRemoved = true;
|
||||
#if _MODBUS == 1
|
||||
// normalerweise wird der Alarm-Counter in _setModbusAlarm() gesetzt,
|
||||
// aber wenn _size == 0, muss der Counter extra zurückgesetzt werden
|
||||
modbusAlarms[0] = 0;
|
||||
#endif
|
||||
} else {
|
||||
_removeAllActive = true;
|
||||
bool finished = false;
|
||||
u8 i;
|
||||
while (!finished) {
|
||||
for (i=0; i<_size; i++) {
|
||||
if (!_list[i].active) { // aktiver Fehler soll nicht gelöscht werden!
|
||||
removeOne(i);
|
||||
atLeastOneRemoved = true;
|
||||
break;
|
||||
}
|
||||
if (i >= _size - 1)
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
for (i=0; i<_size; i++)
|
||||
_save(i);
|
||||
_saveSize();
|
||||
_removeAllActive = false;
|
||||
}
|
||||
return atLeastOneRemoved;
|
||||
}
|
||||
|
||||
FaultState FaultList::state()
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
|
||||
void FaultList::t1Idle() {
|
||||
static bool firstRun = true;
|
||||
if (!_t1Active) {
|
||||
return;
|
||||
}
|
||||
if (firstRun) {
|
||||
// Um beim ersten Idle einen ev. gespeicherten Code nicht zurückzusetzen
|
||||
firstRun = false;
|
||||
return;
|
||||
}
|
||||
_t1Active = false;
|
||||
_lastActiveT1Fault = invalidCode;
|
||||
}
|
||||
|
||||
void FaultList::t1Idle(const int16_t val)
|
||||
{
|
||||
_compT1 = val;
|
||||
_lastT1Idle = currMillis;
|
||||
t1Idle();
|
||||
}
|
||||
|
||||
void FaultList::t2Idle() {
|
||||
static bool firstRun = true;
|
||||
if (!_t2Active) {
|
||||
return;
|
||||
}
|
||||
if (firstRun) {
|
||||
// Um beim ersten Idle einen ev. gespeicherten Code nicht zurückzusetzen
|
||||
firstRun = false;
|
||||
return;
|
||||
}
|
||||
_t2Active = false;
|
||||
_lastActiveT2Fault = invalidCode;
|
||||
}
|
||||
|
||||
void FaultList::t2Idle(const int16_t val)
|
||||
{
|
||||
_compT2 = val;
|
||||
_lastT2Idle = currMillis;
|
||||
t2Idle();
|
||||
}
|
||||
|
||||
void FaultList::pIdle() {
|
||||
static bool firstRun = true;
|
||||
if (!_pActive) {
|
||||
return;
|
||||
}
|
||||
if (firstRun) {
|
||||
// Um beim ersten Idle einen ev. gespeicherten Code nicht zurückzusetzen
|
||||
firstRun = false;
|
||||
return;
|
||||
}
|
||||
_pActive = false;
|
||||
_lastActivePFault = invalidCode;
|
||||
}
|
||||
|
||||
void FaultList::pIdle(const int16_t val)
|
||||
{
|
||||
_compP = val;
|
||||
_lastPIdle = currMillis;
|
||||
pIdle();
|
||||
}
|
||||
|
||||
const char* FaultList::menu()
|
||||
{
|
||||
if (_size) {
|
||||
_str = "";
|
||||
for (u8 i=0; i<_size; i++) {
|
||||
_str += _list[i].title();
|
||||
if (i < _size - 1)
|
||||
_str += '\n';
|
||||
}
|
||||
return _str.c_str();
|
||||
} else {
|
||||
return getMyStr503(STR_NO_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
bool FaultList::tActive()
|
||||
{
|
||||
return _t1Active || _t2Active;
|
||||
}
|
||||
|
||||
bool FaultList::pActive()
|
||||
{
|
||||
return _pActive;
|
||||
}
|
||||
|
||||
void FaultList::_save(const u8 index)
|
||||
{
|
||||
// _printf("Speichere Index "); _print(index);
|
||||
if (index <= _size) {
|
||||
u16 reg_1 = _list[index].counterActivated;
|
||||
u16 reg_2 = _list[index].counterDeactivated;
|
||||
reg_1 |= _list[index].code << 12; // setze Bit 12...15
|
||||
if (_list[index].active)
|
||||
reg_2 |= 0x1000; // Setze Bit 12
|
||||
if (_list[index].timeDeactivated != 0xFFFFFFFF)
|
||||
reg_2 |= 0x2000; // Setze Bit 13
|
||||
EEPROM.put(EEPROM_FAULTS[index], _list[index].id);
|
||||
EEPROM.put(EEPROM_FAULTS[index] + 2, reg_1);
|
||||
EEPROM.put(EEPROM_FAULTS[index] + 4, reg_2);
|
||||
// _printf(", code = "); _print(_list[index].code);
|
||||
// _printf(", active = "); _print(_list[index].active);
|
||||
}
|
||||
// _println();
|
||||
}
|
||||
|
||||
void FaultList::_saveSize()
|
||||
{
|
||||
EEPROM.update(_EEPROM_FAULT_COUNT, _size);
|
||||
}
|
||||
|
||||
void FaultList::_saveLastID()
|
||||
{
|
||||
EEPROM.put(_EEPROM_FAULT_LAST_ID, _lastID);
|
||||
}
|
||||
|
||||
void FaultList::_test(Fault &f, const bool &groupActive, const FaultCode &lastActiveFault)
|
||||
{
|
||||
if (f.active && !groupActive) {
|
||||
f.timeDeactivated =
|
||||
(currMillis == 0xFFFFFFFF) ? 0xFFFFFFFE :
|
||||
(currMillis == 0) ? 1 : currMillis;
|
||||
f.active = false;
|
||||
} else if (f.code != lastActiveFault)
|
||||
f.active = false;
|
||||
}
|
||||
|
||||
#if _MODBUS == 1
|
||||
void FaultList::_setModbusAlarm(const Fault &fault, const u8 index, const bool new_)
|
||||
{
|
||||
u16 reg_1 = 0;
|
||||
u16 reg_2 = 0;
|
||||
u16 timestamp = modbusData[5] & 0xFFF;
|
||||
if (fault.counterActivated) {
|
||||
reg_1 = fault.counterActivated;
|
||||
reg_2 = 0x1000; // Bit 12 setzen
|
||||
} else if (fault.timeActivatedOverflow) {
|
||||
reg_1 = 0xFFF;
|
||||
reg_2 = 0x2000; // Bit 13 setzen
|
||||
} else {
|
||||
reg_1 = timestamp;
|
||||
}
|
||||
reg_1 |= fault.code << 12;
|
||||
if (fault.counterDeactivated) {
|
||||
reg_2 |= fault.counterDeactivated;
|
||||
reg_2 |= 0x4000; // Bit 14 setzen
|
||||
} else if (fault.timeDeactivatedOverflow) {
|
||||
reg_2 |= 0xFFF;
|
||||
reg_2 |= 0x8000; // Bit 15 setzen
|
||||
} else if (fault.timeDeactivated == 0xFFFFFFFF) {
|
||||
// wurde nie deaktiviert
|
||||
if (!fault.active) {
|
||||
// Der Alarm wurde nicht deaktiviert, sondern von einem neuen Alarm abgelöst
|
||||
reg_2 |= 1;
|
||||
} // else: nichts tun, die 12 MSBs von reg_2 bleiben 0
|
||||
} else {
|
||||
// Die Werte 0 und 1 sind reserviert, also muss der Wert hier min. 2 sein
|
||||
reg_2 |= (timestamp > 1) ? timestamp : 2;
|
||||
}
|
||||
modbusAlarms[0] = _size;
|
||||
modbusAlarms[index * 3 + 1] = fault.id;
|
||||
modbusAlarms[index * 3 + 2] = reg_1;
|
||||
modbusAlarms[index * 3 + 3] = reg_2;
|
||||
if (new_) {
|
||||
// Bit 12 gibt an, ob ein neuer Fehler aufgetreten ist - setzen
|
||||
bitSet(modbusData[1], 12);
|
||||
}
|
||||
// _printf("alarm reg 1 (index "); _print(index*3+1); _printf("): "); _println(fault.id);
|
||||
// _printf("alarm reg 2 (index "); _print(index*3+2); _printf("): "); _println(reg_1);
|
||||
// _printf("alarm reg 3 (index "); _print(index*3+3); _printf("): "); _println(reg_2);
|
||||
}
|
||||
#endif
|
||||
|
||||
FaultList faults;
|
|
@ -0,0 +1,124 @@
|
|||
#ifndef FAULTS_H_INCLUDED
|
||||
#define FAULTS_H_INCLUDED
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "../macros.h"
|
||||
|
||||
enum FaultCode : u8
|
||||
{
|
||||
invalidCode = 0,
|
||||
t1TooHi, t1TooLo, t1Invalid,
|
||||
t2TooHi, t2TooLo, t2Invalid,
|
||||
pTooHi, pTooLo, pInvalid
|
||||
};
|
||||
|
||||
enum FaultState : u8
|
||||
{
|
||||
noFault, activeFault, inactiveFault
|
||||
};
|
||||
|
||||
struct SavedFault
|
||||
{
|
||||
FaultCode code; // Fehlercode
|
||||
u16 id; // ID, mit der der Master den Alarm identifizieren kann
|
||||
u16 counterActivated; // Wie oft der Regler seit dem Alarm gestartet/resetted wurde
|
||||
u16 counterDeactivated; // Wie oft der Regler seit der Alarm-Deaktivierung gestartet/resetted wurde
|
||||
bool active; // Ob der Fehler beim Ausschalten noch vorhanden war
|
||||
bool deactivated; // Ob der Fehler vor dem Ausschalten noch behoben wurde
|
||||
};
|
||||
|
||||
class Fault
|
||||
{
|
||||
public:
|
||||
Fault();
|
||||
Fault(FaultCode, const u16);
|
||||
Fault(const Fault&);
|
||||
Fault(const SavedFault&);
|
||||
void process();
|
||||
const char* title();
|
||||
const char* activatedText();
|
||||
const char* deactivatedText();
|
||||
FaultCode code; // Fehlercode
|
||||
u16 id; // ID, mit der der Master den Alarm identifizieren kann
|
||||
u16 counterActivated; // Wie oft der Regler seit der Alarm-Aktivierung gestartet/resetted wurde
|
||||
u16 counterDeactivated; // Wie oft der Regler seit der Alarm-Deaktivierung gestartet/resetted wurde
|
||||
u32 timeActivated; // millis() zum Zeitpunkt des Fehlers
|
||||
u32 timeDeactivated = 0xFFFFFFFF; // millis(), als die Fehlerursache nicht mehr vorhanden war
|
||||
bool timeActivatedOverflow = false; // Ob schon mehr als 0xFFFFFFFF (u32) ms vergangen sind
|
||||
bool timeDeactivatedOverflow = false; // Ob schon mehr als 0xFFFFFFFF (u32) ms vergangen sind
|
||||
bool active = true; // Ob der Fehler noch vorhanden ist
|
||||
private:
|
||||
bool _of1 = false;
|
||||
bool _of2 = false;
|
||||
};
|
||||
|
||||
struct FaultSettings
|
||||
{
|
||||
uint8_t acoustic = 0xFF;
|
||||
uint8_t optical = 0xFF;
|
||||
uint8_t tOnIfError = 0xFF;
|
||||
uint8_t pOnIfError = 0xFF;
|
||||
int16_t tMinRRate = 0x8000; // Hundertstel-°C / 5 Minuten
|
||||
int16_t tMinFRate = 0x8000; // Hundertstel-°C / 5 Minuten
|
||||
int16_t pMinRate = 0x8000; // Hundertstel-Bar / 5 Minuten
|
||||
};
|
||||
|
||||
class FaultList
|
||||
{
|
||||
public:
|
||||
FaultList();
|
||||
void process();
|
||||
bool check(FaultCode, int16_t val=0);
|
||||
u8 count();
|
||||
Fault* first();
|
||||
Fault* last();
|
||||
Fault* at(const u8);
|
||||
bool removeID(const u16);
|
||||
bool removeOne(const u8);
|
||||
bool removeAll();
|
||||
FaultState state();
|
||||
void t1Idle();
|
||||
void t1Idle(const int16_t);
|
||||
void t2Idle();
|
||||
void t2Idle(const int16_t);
|
||||
void pIdle();
|
||||
void pIdle(const int16_t);
|
||||
const char* menu();
|
||||
bool tActive();
|
||||
bool pActive();
|
||||
|
||||
private:
|
||||
Fault _list[_MAX_FAULTS];
|
||||
u8 _size = 0;
|
||||
u16 _lastID;
|
||||
FaultState _state = noFault;
|
||||
FaultCode _lastActiveT1Fault = invalidCode;
|
||||
FaultCode _lastActiveT2Fault = invalidCode;
|
||||
FaultCode _lastActivePFault = invalidCode;
|
||||
bool _t1Active = false;
|
||||
bool _t2Active = false;
|
||||
bool _pActive = false;
|
||||
u32 _lastT1Idle;
|
||||
u32 _lastT2Idle;
|
||||
u32 _lastPIdle;
|
||||
int16_t _compT1;
|
||||
int16_t _compT2;
|
||||
int16_t _compP;
|
||||
String _str;
|
||||
bool _removeAllActive = false;
|
||||
bool _tStateBefore;
|
||||
bool _pIncBefore;
|
||||
bool _pDecBefore;
|
||||
|
||||
void _save(const u8);
|
||||
void _saveSize();
|
||||
void _saveLastID();
|
||||
void _test(Fault&, const bool&, const FaultCode&);
|
||||
void _setModbusAlarm(const Fault&, const u8, const bool);
|
||||
};
|
||||
|
||||
extern FaultList faults;
|
||||
extern FaultSettings faultSettings;
|
||||
// extern const u8 EEPROM_FAULTS[];
|
||||
|
||||
#endif // FAULTS_H_INCLUDED
|
|
@ -0,0 +1,250 @@
|
|||
#ifndef _MY_MACROS_H_INCLUDED
|
||||
#define _MY_MACROS_H_INCLUDED
|
||||
|
||||
#define _DEBUG 1
|
||||
#define _DEBUG_SENSORS 0
|
||||
#define _DEBUG_DISPLAY 0
|
||||
#define _DEBUG_MENU 0
|
||||
#define _DEBUG_MODBUS 0
|
||||
#define _MODBUS 1
|
||||
// Das Ermitteln einer Durchschnittstemperatur braucht (zu) viel RAM und ist wahrscheinlich unnötig
|
||||
#define _MODBUS_AVERAGE_TEMPERATURES 0
|
||||
|
||||
#define _REGS_INFRONTOF_EVENTS 6
|
||||
// Ergibt sich aus 0xFF - 0x06, ev. wird
|
||||
#define _MODBUS_MAX_EVENTS 249
|
||||
|
||||
#define _VERSION_MAJOR 0
|
||||
#define _VERSION_MINOR 0
|
||||
#define _VERSION_MICRO 1
|
||||
#define _VERSION_NUMBER _VERSION_MICRO | (_VERSION_MINOR << 6) | (_VERSION_MAJOR << 12)
|
||||
#define _VERSION_STRING "v0.0.1"
|
||||
|
||||
#define _MODBUS_ADDR_MIN 1
|
||||
#define _MODBUS_ADDR_MAX 247 // Laut QModMaster letzte Adresse
|
||||
#define _MODBUS_DELAY_MIN 0 // 1/10 Millisekunden
|
||||
#define _MODBUS_DELAY_MAX 250 // 1/10 Millisekunden
|
||||
|
||||
#define _MODBUS_VALVE_T1_INDEX 0
|
||||
#define _MODBUS_VALVE_T2_INDEX 1
|
||||
#define _MODBUS_VALVE_PR_INDEX 2
|
||||
#define _MODBUS_VALVE_PF_INDEX 3
|
||||
#define _MODBUS_T1_INDEX 2
|
||||
#define _MODBUS_T2_INDEX 3
|
||||
#define _MODBUS_P_INDEX 4
|
||||
|
||||
#define _STD_TEMP_SETPOINT 400 // Hundertstel
|
||||
#define _STD_TEMP_HYSTERESIS 10 // Hundertstel
|
||||
#define _STD_P_SETPOINT 100 // Hundertstel
|
||||
#define _STD_P_HYSTERESIS 5 // Hundertstel
|
||||
#define _STD_P_EN_INC 1
|
||||
#define _STD_P_EN_DEC 1
|
||||
#define _STD_T_EN 1
|
||||
#define _STD_C_EN 0
|
||||
#define _MIN_TEMP_SETPOINT 10 // Hundertstel
|
||||
#define _MAX_TEMP_SETPOINT 3000 // Hundertstel
|
||||
#define _MIN_TEMP_HYSTERESIS 1 // Hundertstel
|
||||
#define _MAX_TEMP_HYSTERESIS 100 // Hundertstel
|
||||
#define _MIN_P_SETPOINT 0 // Hundertstel
|
||||
#define _MAX_P_SETPOINT 300 // Hundertstel
|
||||
#define _MIN_P_HYSTERESIS 1 // Hundertstel
|
||||
#define _MAX_P_HYSTERESIS 50 // Hundertstel
|
||||
|
||||
#define _P_SENSOR_1_5V_0_5BAR 1
|
||||
#define _P_SENSOR_0_5V_0_6BAR 2
|
||||
|
||||
#define _STD_FAULTS_ACOUSTIC 1
|
||||
#define _STD_FAULTS_OPTICAL 1
|
||||
#define _STD_FAULTS_T_ON 1
|
||||
#define _STD_FAULTS_P_ON 0
|
||||
#define _STD_FAULTS_T_R_RATE 10 // Hundertstel
|
||||
#define _STD_FAULTS_T_F_RATE 10 // Hundertstel
|
||||
#define _STD_FAULTS_P_RATE 10 // Hundertstel
|
||||
#define _MIN_FAULTS_RATE 0 // Hundertstel
|
||||
#define _MAX_FAULTS_RATE 1000 // Hundertstel
|
||||
|
||||
// Alarme
|
||||
|
||||
#define _MAX_FAULTS 30
|
||||
|
||||
// #define _CHECK_FAULT_INTERVAL 300000 // 5 Minuten
|
||||
// #define _CHECK_FAULT_INTERVAL 3000 // 3 Sekunden (für Testzwecke)
|
||||
// #define _CHECK_T_FAULT_INTERVAL 3600000 // 1 Stunde
|
||||
// #define _CHECK_P_FAULT_INTERVAL 10000 // 10 Sekunden
|
||||
#define _CHECK_T_FAULT_INTERVAL 3000 // 3 Sekunden (für Testzwecke)
|
||||
#define _CHECK_P_FAULT_INTERVAL 3000 // 3 Sekunden (für Testzwecke)
|
||||
|
||||
// EEPROM Adressen:
|
||||
|
||||
#define _EEPROM_OFFSET 0 // Falls sich die Register nicht mehr beschreiben lassen
|
||||
#define _EEPROM_MODBUS_ADDRESS (0 + _EEPROM_OFFSET) // 1 byte
|
||||
#define _EEPROM_MODBUS_BAUDRATE (1 + _EEPROM_OFFSET) // 4 bytes
|
||||
#define _EEPROM_MODBUS_DELAY (5 + _EEPROM_OFFSET) // 1 byte
|
||||
#define _EEPROM_TEMP_SETPOINT (6 + _EEPROM_OFFSET) // 4 bytes
|
||||
#define _EEPROM_TEMP_HYSTERESIS (10 + _EEPROM_OFFSET) // 4 bytes
|
||||
#define _EEPROM_P_SETPOINT (14 + _EEPROM_OFFSET) // 4 bytes
|
||||
#define _EEPROM_P_HYSTERESIS (18 + _EEPROM_OFFSET) // 4 bytes
|
||||
#define _EEPROM_P_EN_INC (22 + _EEPROM_OFFSET) // 1 byte
|
||||
#define _EEPROM_P_EN_DEC (23 + _EEPROM_OFFSET) // 1 byte
|
||||
#define _EEPROM_P_SENSOR (24 + _EEPROM_OFFSET) // 1 byte
|
||||
#define _EEPROM_BG_LIGHT (25 + _EEPROM_OFFSET) // 1 byte
|
||||
#define _EEPROM_T_EN (26 + _EEPROM_OFFSET) // 1 byte
|
||||
#define _EEPROM_CONTROL_EN (27 + _EEPROM_OFFSET) // 1 byte
|
||||
// bisschen Reserveplatz
|
||||
#define _EEPROM_POWERON_COUNT (48 + _EEPROM_OFFSET) // 2 bytes
|
||||
#define _EEPROM_FAULT_SIZE 6 // 6 bytes für 1 Fehler
|
||||
#define _EEPROM_FAULT_SETTINGS (50 + _EEPROM_OFFSET) // 20 bytes (incl. Reserve)
|
||||
#define _EEPROM_FAULT_LAST_ID (70 + _EEPROM_OFFSET) // 2 byte
|
||||
#define _EEPROM_FAULT_COUNT (72 + _EEPROM_OFFSET) // 1 byte
|
||||
/*
|
||||
* Bytes 1, 2: Alarm ID
|
||||
* Bytes 3, 4: Bit 0...11: counterActivated
|
||||
* Bytes 3, 4: Bit 12...15: Alarm-Code
|
||||
* Bytes 5, 6: Bit 0...11: counterDeactivated
|
||||
* Bytes 5, 6: Bit 12...13: active, deactivated
|
||||
* Bytes 5, 6: Bit 14...15: reserviert
|
||||
*/
|
||||
#define _EEPROM_FAULT_1 (73 + _EEPROM_OFFSET)
|
||||
#define _EEPROM_FAULT_2 (_EEPROM_FAULT_1 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_3 (_EEPROM_FAULT_2 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_4 (_EEPROM_FAULT_3 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_5 (_EEPROM_FAULT_4 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_6 (_EEPROM_FAULT_5 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_7 (_EEPROM_FAULT_6 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_8 (_EEPROM_FAULT_7 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_9 (_EEPROM_FAULT_8 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_10 (_EEPROM_FAULT_9 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_11 (_EEPROM_FAULT_10 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_12 (_EEPROM_FAULT_11 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_13 (_EEPROM_FAULT_12 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_14 (_EEPROM_FAULT_13 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_15 (_EEPROM_FAULT_14 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_16 (_EEPROM_FAULT_15 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_17 (_EEPROM_FAULT_16 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_18 (_EEPROM_FAULT_17 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_19 (_EEPROM_FAULT_18 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_20 (_EEPROM_FAULT_19 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_21 (_EEPROM_FAULT_20 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_22 (_EEPROM_FAULT_21 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_23 (_EEPROM_FAULT_22 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_24 (_EEPROM_FAULT_23 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_25 (_EEPROM_FAULT_24 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_26 (_EEPROM_FAULT_25 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_27 (_EEPROM_FAULT_26 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_28 (_EEPROM_FAULT_27 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_29 (_EEPROM_FAULT_28 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
#define _EEPROM_FAULT_30 (_EEPROM_FAULT_29 + _EEPROM_OFFSET + _EEPROM_FAULT_SIZE)
|
||||
// bisschen Reserveplatz
|
||||
#define _EEPROM_FAULTS_ACOUSTIC 300 // 1 byte
|
||||
#define _EEPROM_FAULTS_OPTICAL 301 // 1 byte
|
||||
#define _EEPROM_FAULTS_T_ON 302 // 1 byte
|
||||
#define _EEPROM_FAULTS_P_ON 303 // 1 byte
|
||||
#define _EEPROM_FAULTS_T_R_RATE 304 // 2 bytes
|
||||
#define _EEPROM_FAULTS_T_F_RATE 306 // 2 bytes
|
||||
#define _EEPROM_FAULTS_P_RATE 308 // 2 bytes
|
||||
|
||||
extern u32 currMillis;
|
||||
|
||||
#if _DEBUG == 1
|
||||
#define _print(s) Serial.print(s)
|
||||
#define _println(s) Serial.println(s)
|
||||
#define _printf(s) Serial.print(F(s))
|
||||
#define _printlnf(s) Serial.println(F(s))
|
||||
#if _DEBUG_DISPLAY == 1
|
||||
struct __printTimeStruct {
|
||||
__printTimeStruct(const char *text) : _text(text) {
|
||||
_t0 = currMillis;
|
||||
};
|
||||
~__printTimeStruct() {
|
||||
_printf("Vergangene Millisekunden ["); _print(_text);
|
||||
_printf("]: "); _println(currMillis - _t0);
|
||||
};
|
||||
private:
|
||||
u32 _t0;
|
||||
const char *_text;
|
||||
};
|
||||
#define _printtime(text) __printTimeStruct __printt(text)
|
||||
#else
|
||||
#define _printtime(text)
|
||||
#endif // _DEBUG_DISPLAY
|
||||
#if _DEBUG_SENSORS == 1
|
||||
#define _prints(s) _print(s)
|
||||
#define _printsln(s) _println(s)
|
||||
#define _printsf(s) _printf(s)
|
||||
#define _printslnf(s) _printlnf(s)
|
||||
#else
|
||||
#define _prints(s)
|
||||
#define _printsln(s)
|
||||
#define _printsf(s)
|
||||
#define _printslnf(s)
|
||||
#endif // _DEBUG_SENSORS
|
||||
#if _DEBUG_MODBUS == 1
|
||||
#define _printb(s) _print(s)
|
||||
#define _printbln(s) _println(s)
|
||||
#define _printbf(s) _printf(s)
|
||||
#define _printblnf(s) _printlnf(s)
|
||||
#else
|
||||
#define _printb(s)
|
||||
#define _printbln(s)
|
||||
#define _printbf(s)
|
||||
#define _printblnf(s)
|
||||
#endif // _DEBUG_MODBUS
|
||||
#if _DEBUG_MENU == 1
|
||||
#define _printm(s) _print(s)
|
||||
#define _printmln(s) _println(s)
|
||||
#define _printmf(s) _printf(s)
|
||||
#define _printmlnf(s) _printlnf(s)
|
||||
#else
|
||||
#define _printm(s)
|
||||
#define _printmln(s)
|
||||
#define _printmf(s)
|
||||
#define _printmlnf(s)
|
||||
#endif // _DEBUG_MENU
|
||||
#else // _DEBUG != 1
|
||||
#define _print(s)
|
||||
#define _println(s)
|
||||
#define _printf(s)
|
||||
#define _printlnf(s)
|
||||
#define _prints(s)
|
||||
#define _printsln(s)
|
||||
#define _printsf(s)
|
||||
#define _printslnf(s)
|
||||
#define _printb(s)
|
||||
#define _printbln(s)
|
||||
#define _printbf(s)
|
||||
#define _printblnf(s)
|
||||
#define _printm(s)
|
||||
#define _printmln(s)
|
||||
#define _printmf(s)
|
||||
#define _printmlnf(s)
|
||||
#define _printtime(s)
|
||||
#endif
|
||||
|
||||
#if _MODBUS == 1
|
||||
extern bool timeStampOverflow;
|
||||
extern unsigned long timeStamp;
|
||||
extern u8 modbusValves[];
|
||||
extern u16 &eventCounter;
|
||||
extern u16 modbusData[];
|
||||
#define _setModbusValve(index, val)\
|
||||
if (bitRead(modbusValves[0], index) != val) {\
|
||||
bitWrite(modbusValves[0], index, val);\
|
||||
bitWrite(modbusData[1], index+8, val);\
|
||||
if (eventCounter <= _MODBUS_MAX_EVENTS) {\
|
||||
/* Die ersten 12 Bits beinhalten den relativen Zeitstempel in Zehntelsekunden */\
|
||||
/* Dieser Stempel ist immer 0xFFF, falls schon zuviel Zeit seit der letzten Referenzierung vergangen ist */\
|
||||
/* u16 result = (timeStampOverflow) ? 0xFFF : ((currMillis - timeStamp) / 100) & 0xFFF;*/\
|
||||
u16 result = (timeStampOverflow) ? 0xFFF : (modbusData[5] & 0xFFF);\
|
||||
/* Die Bits 12...14 beinhalten die Nr des geschalteten Ausgangs */\
|
||||
result |= index << 12;\
|
||||
/* Das MSB gibt an, ob der Ausgang ein- oder ausgeschaltet wurde */\
|
||||
result |= val << 15;\
|
||||
modbusData[_REGS_INFRONTOF_EVENTS + eventCounter] = result;\
|
||||
eventCounter++;\
|
||||
}\
|
||||
}
|
||||
#else
|
||||
#define _setModbusValve(index, val)
|
||||
#endif // _MODBUS == 1
|
||||
|
||||
#endif // _MY_MACROS_H_INCLUDED
|
|
@ -74,6 +74,11 @@ bool ModbusRTUSlave::addInputRegisterArea(u16 address, u16* values, int cnt)
|
|||
return false;
|
||||
}
|
||||
|
||||
// bool ModbusRTUSlave::addValidator(u16 reg, u16 min, u16 max, u16 step=5)
|
||||
// {
|
||||
// return validator.add(reg, min, max, step);
|
||||
// }
|
||||
|
||||
ModbusRTUSlaveWordAddress* ModbusRTUSlave::getWordAddress(wordsList *words, u16 Addr)
|
||||
{
|
||||
ModbusRTUSlaveWordAddress* ret=NULL;
|
||||
|
@ -170,7 +175,9 @@ void ModbusRTUSlave::process()
|
|||
{
|
||||
u16 stidx = (requestedRegister - a->addr) / 8;
|
||||
|
||||
bitWrite(a->values[stidx], (requestedRegister - a->addr)%8, Data==0xFF00);
|
||||
bool b = Data==0xFF00;
|
||||
callbackCoil(requestedRegister, b);
|
||||
bitWrite(a->values[stidx], (requestedRegister - a->addr)%8, b);
|
||||
|
||||
byte ret[8];
|
||||
ret[0]=requestedSlave;
|
||||
|
@ -201,7 +208,7 @@ void ModbusRTUSlave::process()
|
|||
{
|
||||
u16 stidx = requestedRegister - a->addr;
|
||||
|
||||
a->values[stidx] = Data;
|
||||
a->values[stidx] = callbackRegister(requestedRegister, Data);
|
||||
|
||||
byte ret[8];
|
||||
ret[0]=requestedSlave;
|
||||
|
@ -235,6 +242,8 @@ void ModbusRTUSlave::process()
|
|||
ModbusRTUSlaveBitAddress *a = getBitAddress(rwBits, requestedRegister, Length);
|
||||
if (a != NULL)
|
||||
{
|
||||
bool b;
|
||||
u16 offset = 0;
|
||||
u16 stidx = (requestedRegister - a->addr) / 8;
|
||||
int ng=(requestedRegister - a->addr) % 8;
|
||||
int ns=stidx;
|
||||
|
@ -244,8 +253,11 @@ void ModbusRTUSlave::process()
|
|||
byte val = lstResponse[i];
|
||||
for(int j=0;j<8;j++)
|
||||
{
|
||||
bitWrite(a->values[ns], ng++, bitRead(val,j));
|
||||
b = bitRead(val,j);
|
||||
callbackCoil(requestedRegister + offset, b);
|
||||
bitWrite(a->values[ns], ng++, b);
|
||||
if(ng==8){ns++;ng=0;}
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,7 +297,7 @@ void ModbusRTUSlave::process()
|
|||
{
|
||||
for(int i=7; i<7+ByteCount;i+=2)
|
||||
{
|
||||
u16 data = lstResponse[i] << 8 | lstResponse[i+1];
|
||||
u16 data = callbackRegister(requestedRegister, lstResponse[i] << 8 | lstResponse[i+1]);
|
||||
ModbusRTUSlaveWordAddress *a = getWordAddress(rwWords, requestedRegister + ((i-7)/2));
|
||||
if (a != NULL) { a->values[(requestedRegister + ((i-7)/2)) - a->addr] = data; }
|
||||
else { bvalid=false; break; }
|
||||
|
|
|
@ -4,22 +4,20 @@
|
|||
#include "Arduino.h"
|
||||
#include "utility/LinkedList.h"
|
||||
|
||||
class ModbusRTUSlaveWordAddress
|
||||
struct ModbusRTUSlaveWordAddress
|
||||
{
|
||||
public :
|
||||
u16 addr;
|
||||
byte len;
|
||||
u16 *values;
|
||||
ModbusRTUSlaveWordAddress(u16 Address, u16* value, int cnt);
|
||||
u16 addr;
|
||||
byte len;
|
||||
u16 *values;
|
||||
ModbusRTUSlaveWordAddress(u16 Address, u16* value, int cnt);
|
||||
};
|
||||
|
||||
class ModbusRTUSlaveBitAddress
|
||||
struct ModbusRTUSlaveBitAddress
|
||||
{
|
||||
public :
|
||||
u16 addr;
|
||||
byte len;
|
||||
u8 *values;
|
||||
ModbusRTUSlaveBitAddress(u16 Address, u8* value, int cnt);
|
||||
u16 addr;
|
||||
byte len;
|
||||
u8 *values;
|
||||
ModbusRTUSlaveBitAddress(u16 Address, u8* value, int cnt);
|
||||
};
|
||||
|
||||
using wordsList = LinkedList<ModbusRTUSlaveWordAddress*>;
|
||||
|
@ -38,6 +36,9 @@ class ModbusRTUSlave
|
|||
void process();
|
||||
unsigned long waitWithAnswerMicroS = 0;
|
||||
|
||||
u16 (*callbackRegister)(u16 reg, u16 val) = [](u16, u16 val){return val;};
|
||||
void (*callbackCoil)(u16 reg, bool val);
|
||||
|
||||
private:
|
||||
byte slaveAddress;
|
||||
byte requestedSlave;
|
||||
|
@ -48,8 +49,6 @@ class ModbusRTUSlave
|
|||
bool isReading;
|
||||
unsigned long receivedLastRequest;
|
||||
|
||||
// LinkedList<ModbusRTUSlaveWordAddress*> *rWords;
|
||||
// LinkedList<ModbusRTUSlaveBitAddress*> *rBits;
|
||||
wordsList *rWords;
|
||||
bitsList *rBits;
|
||||
wordsList *rwWords;
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
||
|
||||
|| @file HashMap.h
|
||||
|| @version 1.0 Beta
|
||||
|| @author Alexander Brevig
|
||||
|| @contact alexanderbrevig@gmail.com
|
||||
||
|
||||
|| @description
|
||||
|| | This library provides a simple interface for storing data with an associate key
|
||||
|| #
|
||||
||
|
||||
|| @license
|
||||
|| | This library is free software; you can redistribute it and/or
|
||||
|| | modify it under the terms of the GNU Lesser General Public
|
||||
|| | License as published by the Free Software Foundation; version
|
||||
|| | 2.1 of the License.
|
||||
|| |
|
||||
|| | This library is distributed in the hope that it will be useful,
|
||||
|| | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|| | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
|| | Lesser General Public License for more details.
|
||||
|| |
|
||||
|| | You should have received a copy of the GNU Lesser General Public
|
||||
|| | License along with this library; if not, write to the Free Software
|
||||
|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|| #
|
||||
||
|
||||
*/
|
||||
|
||||
#ifndef HASHMAP_H
|
||||
#define HASHMAP_H
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
/* Handle association */
|
||||
template<typename hash,typename map>
|
||||
class HashType {
|
||||
public:
|
||||
HashType(){ reset(); }
|
||||
|
||||
HashType(hash code,map value):hashCode(code),mappedValue(value){}
|
||||
|
||||
void reset(){ hashCode = 0; mappedValue = 0; }
|
||||
hash getHash(){ return hashCode; }
|
||||
void setHash(hash code){ hashCode = code; }
|
||||
map getValue(){ return mappedValue; }
|
||||
void setValue(map value){ mappedValue = value; }
|
||||
|
||||
HashType& operator()(hash code, map value){
|
||||
setHash( code );
|
||||
setValue( value );
|
||||
}
|
||||
private:
|
||||
hash hashCode;
|
||||
map mappedValue;
|
||||
};
|
||||
|
||||
/*
|
||||
Handle indexing and searches
|
||||
TODO - extend API
|
||||
*/
|
||||
template<typename hash, typename map>
|
||||
class HashMap {
|
||||
public:
|
||||
HashMap(HashType<hash,map>* newMap,byte newSize){
|
||||
hashMap = newMap;
|
||||
size = newSize;
|
||||
for (byte i=0; i<size; i++){
|
||||
hashMap[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
HashType<hash,map>& operator[](int x){
|
||||
//TODO - bounds
|
||||
return hashMap[x];
|
||||
}
|
||||
|
||||
byte getIndexOf( hash key ){
|
||||
for (byte i=0; i<size; i++){
|
||||
if (hashMap[i].getHash()==key){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
map getValueOf( hash key ){
|
||||
for (byte i=0; i<size; i++){
|
||||
if (hashMap[i].getHash()==key){
|
||||
return hashMap[i].getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void debug(){
|
||||
for (byte i=0; i<size; i++){
|
||||
Serial.print(hashMap[i].getHash());
|
||||
Serial.print(" - ");
|
||||
Serial.println(hashMap[i].getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
HashType<hash,map>* hashMap;
|
||||
byte size;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|| @changelog
|
||||
|| | 1.0 2009-07-13 - Alexander Brevig : Initial Release
|
||||
|| #
|
||||
*/
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
||
|
||||
|| @file HashMap.h
|
||||
|| @version 1.0 Beta
|
||||
|| @author Alexander Brevig
|
||||
|| @contact alexanderbrevig@gmail.com
|
||||
||
|
||||
|| @description
|
||||
|| | This library provides a simple interface for storing data with an associate key
|
||||
|| #
|
||||
||
|
||||
|| @license
|
||||
|| | This library is free software; you can redistribute it and/or
|
||||
|| | modify it under the terms of the GNU Lesser General Public
|
||||
|| | License as published by the Free Software Foundation; version
|
||||
|| | 2.1 of the License.
|
||||
|| |
|
||||
|| | This library is distributed in the hope that it will be useful,
|
||||
|| | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|| | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
|| | Lesser General Public License for more details.
|
||||
|| |
|
||||
|| | You should have received a copy of the GNU Lesser General Public
|
||||
|| | License along with this library; if not, write to the Free Software
|
||||
|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|| #
|
||||
||
|
||||
*/
|
||||
|
||||
#ifndef HASHMAP_H
|
||||
#define HASHMAP_H
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
/* Handle association */
|
||||
template<typename hash,typename map>
|
||||
class HashType {
|
||||
public:
|
||||
HashType(){ reset(); }
|
||||
|
||||
HashType(hash code,map value):hashCode(code),mappedValue(value){}
|
||||
|
||||
void reset(){ hashCode = 0; mappedValue = 0; }
|
||||
hash getHash(){ return hashCode; }
|
||||
void setHash(hash code){ hashCode = code; }
|
||||
map getValue(){ return mappedValue; }
|
||||
void setValue(map value){ mappedValue = value; }
|
||||
|
||||
HashType& operator()(hash code, map value){
|
||||
setHash( code );
|
||||
setValue( value );
|
||||
}
|
||||
private:
|
||||
hash hashCode;
|
||||
map mappedValue;
|
||||
};
|
||||
|
||||
/*
|
||||
Handle indexing and searches
|
||||
TODO - extend API
|
||||
*/
|
||||
template<typename hash, typename map>
|
||||
|
||||
class HashMap {
|
||||
public:
|
||||
HashMap(HashType<hash,map>* newMap,byte newSize){
|
||||
hashMap = newMap;
|
||||
size = newSize;
|
||||
for (byte i=0; i<size; i++){
|
||||
hashMap[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
HashType<hash,map>& operator[](int x){
|
||||
//TODO - bounds
|
||||
return hashMap[x];
|
||||
}
|
||||
|
||||
byte getIndexOf( hash key ){
|
||||
for (byte i=0; i<size; i++){
|
||||
if (hashMap[i].getHash()==key){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
map getValueOf( hash key ){
|
||||
for (byte i=0; i<size; i++){
|
||||
if (hashMap[i].getHash()==key){
|
||||
return hashMap[i].getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void debug(){
|
||||
for (byte i=0; i<size; i++){
|
||||
Serial.print(hashMap[i].getHash());
|
||||
Serial.print(" - ");
|
||||
Serial.println(hashMap[i].getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
HashType<hash,map>* hashMap;
|
||||
byte size;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|| @changelog
|
||||
|| | 1.0 2009-07-13 - Alexander Brevig : Initial Release
|
||||
|| #
|
||||
*/
|
|
@ -0,0 +1,31 @@
|
|||
#include "mystrings.h"
|
||||
|
||||
char charBuffer200[200];
|
||||
char charBuffer501[50];
|
||||
char charBuffer502[50];
|
||||
char charBuffer503[50];
|
||||
// char charBuffer[50];
|
||||
|
||||
char* getMyStr200(const char* str)
|
||||
{
|
||||
strcpy_P(charBuffer200, str);
|
||||
return charBuffer200;
|
||||
}
|
||||
|
||||
char* getMyStr501(const char* str)
|
||||
{
|
||||
strcpy_P(charBuffer501, str);
|
||||
return charBuffer501;
|
||||
}
|
||||
|
||||
char* getMyStr502(const char* str)
|
||||
{
|
||||
strcpy_P(charBuffer502, str);
|
||||
return charBuffer502;
|
||||
}
|
||||
|
||||
char* getMyStr503(const char* str)
|
||||
{
|
||||
strcpy_P(charBuffer503, str);
|
||||
return charBuffer503;
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
#ifndef _MY_STRINGS_H_INCLUDED
|
||||
#define _MY_STRINGS_H_INCLUDED
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
const char STR_MENU_MAIN[] PROGMEM = "Temperatur\nDruck\nFehlerbehandlung\nSystem\nReset";
|
||||
const char STR_MENU_MAIN_TITLE[] PROGMEM = "Hauptmenü (%s)";
|
||||
|
||||
const char STR_MENU_TEMPERATURE[] PROGMEM = "Kühlung de/aktivieren\nSollwert\nHysterese";
|
||||
const char STR_TEMPERATURE[] PROGMEM = "Temperatur";
|
||||
const char STR_COOLING[] PROGMEM = "Kühlung";
|
||||
const char STR_T_SETP[] PROGMEM = "Temperatur\nSollwert";
|
||||
const char STR_T_HYST[] PROGMEM = "Temperatur\nHysterese";
|
||||
|
||||
const char STR_MENU_PRESSURE[] PROGMEM = "Drucksteigerung\nDruckabfall\nSollwert\nHysterese";
|
||||
const char STR_P[] PROGMEM = "Druck";
|
||||
const char STR_P_INC[] PROGMEM = "Drucksteigerung";
|
||||
const char STR_P_DEC[] PROGMEM = "Druckabfall";
|
||||
const char STR_P_SETP[] PROGMEM = "Druck\nSollwert";
|
||||
const char STR_P_HYST[] PROGMEM = "Druck\nHysterese";
|
||||
|
||||
const char STR_F_ERR_TITLE[] PROGMEM = "Fehler (%u)";
|
||||
const char STR_MENU_ERR_HANDLING[] PROGMEM = "offene Fehler\nalle löschen\nEinstellungen";
|
||||
const char STR_CURR_ERRS[] PROGMEM = "aktuelle Fehler";
|
||||
const char STR_MENU_FAULT_SETTINGS_TITLE[] PROGMEM = "Fehler-Settings";
|
||||
const char STR_MENU_FAULT_SETTINGS[] PROGMEM = "akustisches Signal\noptisches Signal\nTempregelung\nDruckregelung\nTemp+ Rate\nTemp- Rate\nDruckrate";
|
||||
const char STR_FAULTS_ACOUSTIC[] PROGMEM = "Summer zur\nFehlersignalisierung\nverwenden?";
|
||||
const char STR_FAULTS_OPTICAL[] PROGMEM = "Displaybeleuchtung\nim Fehlerfall\npulsieren lassen?";
|
||||
const char STR_FAULTS_T_OFF[] PROGMEM = "Temperatur im\nFehlerfall weiter\nregeln?";
|
||||
const char STR_FAULTS_P_OFF[] PROGMEM = "Druck im\nFehlerfall weiter\nregeln?";
|
||||
const char STR_FAULTS_T_R_RATE[] PROGMEM = "Min. Steigerungsrate\nfür Temperatur";
|
||||
const char STR_FAULTS_T_F_RATE[] PROGMEM = "Min. Abfallrate\nfür Temperatur";
|
||||
const char STR_FAULTS_P_RATE[] PROGMEM = "Min. Änderungsrate\nfür Druck";
|
||||
|
||||
const char STR_ADMIN_AUTH[] PROGMEM = "Systemeinstellungen:\nBerechtigung\nnachweisen:";
|
||||
const char STR_SYSTEM[] PROGMEM = "System";
|
||||
const char STR_MENU_SYSTEM[] PROGMEM = "Modbus\nDrucksensor";
|
||||
const char STR_MODBUS[] PROGMEM = "Modbus";
|
||||
const char STR_MENU_MODBUS[] PROGMEM = "Adresse\nBaudrate\nAntwort-Delay";
|
||||
const char STR_BAUDR[] PROGMEM = "Baudrate";
|
||||
const char STR_MENU_BAUDR[] PROGMEM = "300\n1200\n2400\n4800\n9600\n19200\n38400\n57600\n115200";
|
||||
const char STR_SEL_MODB_ADDR[] PROGMEM = "Modbus Adresse";
|
||||
const char STR_SEL_MODB_ADDR_F[] PROGMEM = "Dezimal: %d";
|
||||
const char STR_SEL_MODB_DELAY[] PROGMEM = "Modbus\nAntwort-Verzögerung\nin Millisekunden";
|
||||
const char STR_SEL_MODB_DELAY_F[] PROGMEM = "%d.%.d";
|
||||
const char STR_P_SENSOR[] PROGMEM = "Drucksensor";
|
||||
const char STR_MENU_P_SENSOR[] PROGMEM = "SMC: 1-5V,0-5 bar\nGems: 0-5V,0-6 bar";
|
||||
const char STR_RESTART_CONTROLLER[] PROGMEM = "Controller neustarten";
|
||||
const char STR_20_HYPHENS[] PROGMEM = "--------------------";
|
||||
const char STR_REALLY_RESTART[] PROGMEM = "Wirklich neustarten?";
|
||||
|
||||
const char STR_NO_YES[] PROGMEM = " nein \n ja ";
|
||||
//const char STR_YES_NO[] PROGMEM = " ja \n nein ";
|
||||
const char STR_ACTIVATE[] PROGMEM = "aktivieren";
|
||||
const char STR__FLOAT__[] PROGMEM = "__float__";
|
||||
const char STR_OK[] PROGMEM = " OK ";
|
||||
|
||||
const char STR_IN[] PROGMEM = "in";
|
||||
const char STR_ON[] PROGMEM = "ein";
|
||||
const char STR_OFF[] PROGMEM = "aus";
|
||||
const char STR_HOME_1[] PROGMEM = "--.-- \xb0\C";
|
||||
const char STR_HOME_2[] PROGMEM = "%d.%.2d \xb0\C";
|
||||
const char STR_HOME_3[] PROGMEM = "--.-- bar";
|
||||
const char STR_HOME_4[] PROGMEM = "%d.%.2d bar";
|
||||
const char STR_HOME_5[] PROGMEM = "%d.%.2d+-%d.%.2d Regelung %saktiv";
|
||||
const char STR_HOME_6[] PROGMEM = "%d.%.2d+-%d.%.2d P+ %s P- %s";
|
||||
const char STR_HOME_7[] PROGMEM = "Modbus Adr. %u, Baudr. %s";
|
||||
|
||||
const char STR_1W_ERR[] PROGMEM = "Fehler OneWire";
|
||||
const char STR_1W_F1[] PROGMEM = "%u (max: %u)";
|
||||
const char STR_1W_1[] PROGMEM = "OneWire-Sensoren";
|
||||
const char STR_1W_2[] PROGMEM = "Erfolgreich erkannt:";
|
||||
const char STR_1W_3[] PROGMEM = "Zu viele Sensoren:";
|
||||
const char STR_1W_4[] PROGMEM = "Keine Sensoren";
|
||||
const char STR_1W_5[] PROGMEM = "erkannt";
|
||||
|
||||
const char STR_F_DEC_0[] PROGMEM = "%d";
|
||||
const char STR_F_DEC_1[] PROGMEM = "%d.%.1d";
|
||||
const char STR_F_DEC_2[] PROGMEM = "%d.%.2d";
|
||||
|
||||
const char STR_F_S_MIN_MAX[] PROGMEM = "min: %s, max: %s";
|
||||
|
||||
const char STR_T_FAIL[] PROGMEM = "Fehler Tempsensor";
|
||||
const char STR_T_TOO_HI[] PROGMEM = "Temp. zu hoch";
|
||||
const char STR_T_TOO_LO[] PROGMEM = "Temp. zu niedrig";
|
||||
const char STR_T1_TOO_HI[] PROGMEM = "Temp. 1 zu hoch";
|
||||
const char STR_T1_TOO_LO[] PROGMEM = "Temp. 1 zu niedrig";
|
||||
const char STR_T2_TOO_HI[] PROGMEM = "Temp. 2 zu hoch";
|
||||
const char STR_T2_TOO_LO[] PROGMEM = "Temp. 2 zu niedrig";
|
||||
const char STR_P_FAIL[] PROGMEM = "Fehler Drucksensor";
|
||||
const char STR_P_TOO_HI[] PROGMEM = "Druck zu hoch";
|
||||
const char STR_P_TOO_LO[] PROGMEM = "Druck zu niedrig";
|
||||
const char STR_UNKNOWN_ERROR[] PROGMEM = "unbekannter Fehler";
|
||||
const char STR_NO_ERROR[] PROGMEM = "keine Fehler :-)";
|
||||
|
||||
const char STR_NEVER_DEACTIVATED_ACTIVE[] PROGMEM = "~ nie (aktiv)";
|
||||
const char STR_NEVER_DEACTIVATED_INACTIVE[] PROGMEM = "~ nie (inaktiv)";
|
||||
const char STR_GT_7_WEEKS_1[] PROGMEM = "* > 7 Wochen";
|
||||
const char STR_F_SECONDS_1[] PROGMEM = "* %u Sekunden";
|
||||
const char STR_F_MINUTES_1[] PROGMEM = "* %u Minuten";
|
||||
const char STR_F_HOURS_1[] PROGMEM = "* %u Stunden";
|
||||
const char STR_F_DAYS_1[] PROGMEM = "* %u Tage";
|
||||
const char STR_GT_7_WEEKS_2[] PROGMEM = "~ > 7 Wochen";
|
||||
const char STR_F_SECONDS_2[] PROGMEM = "~ %u Sekunden";
|
||||
const char STR_F_MINUTES_2[] PROGMEM = "~ %u Minuten";
|
||||
const char STR_F_HOURS_2[] PROGMEM = "~ %u Stunden";
|
||||
const char STR_F_DAYS_2[] PROGMEM = "~ %u Tage";
|
||||
const char STR_UNKNOWN_ACTIVATED[] PROGMEM = "* ? (vor %u Resets)";
|
||||
const char STR_UNKNOWN_DEACTIVAED[] PROGMEM = "~ ? (vor %u Resets)";
|
||||
|
||||
const char STR_DEL_ALL_INACTIVE_FAULTS[] PROGMEM = "Alle nicht\naktiven Fehler\nlöschen?";
|
||||
const char STR_BACK_DEL[] PROGMEM = " zurück \n löschen ";
|
||||
const char STR_BACK[] PROGMEM = " zurück ";
|
||||
|
||||
extern char charBuffer200[];
|
||||
extern char charBuffer501[];
|
||||
extern char charBuffer502[];
|
||||
extern char charBuffer503[];
|
||||
// extern char charBuffer[];
|
||||
extern char* getMyStr200(const char* str);
|
||||
extern char* getMyStr501(const char* str);
|
||||
extern char* getMyStr502(const char* str);
|
||||
extern char* getMyStr503(const char* str);
|
||||
|
||||
#endif // _MY_STRINGS_H_INCLUDED
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef _MYTYPES_H_INCLUDED
|
||||
#define _MYTYPES_H_INCLUDED
|
||||
|
||||
#define _SENSOR_FAULT 0x8000
|
||||
#define _MODBUS_INVALID_BAUDRATE 4294967295
|
||||
|
||||
enum PSensor : uint8_t {
|
||||
SMC_1_5V_0_5BAR=1, // Sensor mit Kabel
|
||||
GEMS_0_5V_0_6BAR // Sensor mit Würfelstecker
|
||||
};
|
||||
|
||||
struct Parameters { // Prozesswerte
|
||||
int16_t ts1 = _SENSOR_FAULT; // Soll-Temperatur 1 in 1/100 °C
|
||||
int16_t th1 = _SENSOR_FAULT; // Hysterese für Temperatur 1 (1/100)
|
||||
int16_t ts2 = _SENSOR_FAULT; // Soll-Temperatur 2 in 1/100 °C
|
||||
int16_t th2 = _SENSOR_FAULT; // Hysterese für Temperatur 2 (1/100)
|
||||
int16_t ps = _SENSOR_FAULT; // Druck in bar
|
||||
int16_t ph = _SENSOR_FAULT; // Hysterese für Druck
|
||||
uint8_t tEn = 255; // Kühlung (de)aktiviert
|
||||
uint8_t pInc = 255; // Drucksteigerung (de)aktiviert
|
||||
uint8_t pDec = 255; // Druckabfall (de)aktiviert
|
||||
uint8_t cEn = 255; // Controller (de)aktiviert
|
||||
};
|
||||
|
||||
struct Values { // aktuelle Messwerte
|
||||
int16_t t1 = _SENSOR_FAULT; // Temperatur in 1/100 °C
|
||||
int16_t t2 = _SENSOR_FAULT; // Temperatur in 1/100 °C
|
||||
int16_t p = _SENSOR_FAULT; // Druck in 1/100 bar
|
||||
};
|
||||
|
||||
struct ModbusParameters { // Parameter für Modbus
|
||||
uint32_t baudrate = _MODBUS_INVALID_BAUDRATE; // Modbus-Baudrate
|
||||
uint8_t address = 255; // Modbus-Adresse
|
||||
uint8_t delay = 255; // delay in 1/10 ms vor der Antwort
|
||||
};
|
||||
|
||||
struct ValveStates {
|
||||
bool t1;
|
||||
bool t2;
|
||||
bool pInc;
|
||||
bool pDec;
|
||||
};
|
||||
|
||||
extern PSensor pSensor;
|
||||
extern Parameters params;
|
||||
extern ModbusParameters modbusParams;
|
||||
extern Values vals;
|
||||
extern ValveStates vStates;
|
||||
|
||||
#endif // _MYTYPES_H_INCLUDED
|
Loading…
Reference in New Issue