Dear guys!
Some time has passed since my last post, and the good thing: The whole thing runs WITHOUT ANY ERROR since post #145 = since Okt. 2023 (today is the 11.1.2024) (still without a watchdog circuitry).
I think we can call this now a solution!
Thanks to YOUR help, I managed it now, I think!
SHORT SUMMARY:
For me, the main items why the code before was not working properly (remember , I had intermittent -127°C and +85°C readings on the 1-wire temperature sensors) and now IS working, are as follows:
- Use as basis the "Hacktronics tutorial" Arduino 1-Wire Tutorial
- Remove all the serial commands from the code
- Soldered additional blocking caps between VCC and GND directly onto the Arduino Nano board.
With these 3 measures, the errors were gone I think.
I put 2 more "things" now in the code:
- Additionally, I re-programmed my code to non-blocking form (i.e. do not wait for a temperature conversion), as this is good programming style, as suggested.
- I added a hardware watchdog circuitry and tested it so far on a replica Arduino Nano board and it works.
So here is my "final" code I think, at least connected to the above written issues I had. Of course in the future, I will add more features, but this is another story... :
// This Arduino sketch reads DS18B20 "1-Wire" digital
// temperature sensors.
// Tutorial:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-tutorial.html
/****************** Include Files ******************************************************/
// "" => Looks in the same directory as the 'C' file I compile
// <> => Looks in the library paths
// OLED-Display
#include <U8x8lib.h>
// 1-wire
#include <OneWire.h>
#include <DallasTemperature.h>
// MCP3221 (For I2C)
#include "MCP3221.h"
/****************** Constants **********************************************************/
// WTD Watchdog "STWD100YNYWY3F": Timeout twd = 1.6 sec. ; tpw = 210 ms
#define WTD_EN_Q_pin 6 // Pin D6
#define WTD_WDI_pin 7 // Pin D7
// VCC voltage reference: Used for MCP3221 and internal Arduino ADC
const float VCC_VREF_V = 5.02; // Voltage reference ( = VCC) for in units [V] ; Measured / verified with Fluke 289 on 29.12.2023: 5.02V correct directly at added blocking capacitors which were added on 10. and 11.10.2023
// Timing for the endless Arduino program loop
#define waitTime1 1000 // [ms] // For flow meter 1s
#define waitTime2 3000 // [ms]
// 1-wire
#define ONE_WIRE_BUS 2 // Data wire is plugged into port D2 on the Arduino; Make sure a pull-up resistor (e.g. 4k7) is connected (so from Data to VCC) ; Changed from 1k to 4k7 on 21.10.22.
#define TEMPERATURE_PRECISION 12 // 12 is maximum but slower.
#define NUM_OW_SENSORS 8 // the number of DS18B20 sensors on the 1-Wire bus.
// MCP3221 (For I2C)
// Each MCP3221 has 1 of 8 possible I2C addresses (factory hardwired & recognized by its specific part number & top marking on the package itself):
// PART DEVICE I2C ADDRESS PART
// NUMBER (BIN) (HEX) (DEC) MARKING
// MCP3221A0T-E/OT 01001000 0x48 72 GE
// MCP3221A1T-E/OT 01001001 0x49 73 GH
// MCP3221A2T-E/OT 01001010 0x4A 74 GB
// MCP3221A3T-E/OT 01001011 0x4B 75 GC
// MCP3221A4T-E/OT 01001100 0x4C 76 GD
// MCP3221A5T-E/OT 01001101 0x4D 77 GA
// MCP3221A6T-E/OT 01001110 0x4E 78 GF
// MCP3221A7T-E/OT 01001111 0x4F 79 GG
const byte SLAVE1 = 0x4E; // I2C address of the MCP3221 for measuring the compressor current
const byte SLAVE2 = 0x4F; // I2C address of the MCP3221 for measuring the pump current
const float MPC3221_VREF_V = VCC_VREF_V; // Voltage reference ( = VCC) for the MCP3221 in units [V]
// ACS723 over MCP3221
// Sensitivity
const float SENS_ACS723_05__V_PER_A = 0.4; // SENSitivity of the "ACS723LLCTR-05AB-T" in units [V/A]
const float SENS_ACS723_10__V_PER_A = 0.2; // SENSitivity of the "ACS723LLCTR-10AB-T" in units [V/A]
// Internal ADC for 12V VBB (VBAT) voltage reading
const int VBB_MEAS_ANALOG_IN_PIN = A6; // Pin used for voltage VBB (VBAT) measurement reading through internal Arduino ADC
const float VBB_MEAS_RES_DIV_GAIN = 4; // Gain setting of the RESistor DIVider (potentiometer) between the VBB (VBAT) voltage (max. 20V foreseen) to VCC related (approx. 5V nom).
// Alive / Error LED
const int AliveErrorLED = 4; // Pin "D4"
// Switches ( = Pushbuttons)
#define ERROR_WINDOW_SW 30 // +/- this value
int AnalogSwPin = 7; // switch circuit input connected to analog pin 7
// Compressor switch on / off
#define ComprOnOffPin A3 // An analog hardware is connected to pin A3 which switches the relay off immediately as soon as this pin is going low. If this pin is going high, approx. 7 min has to be waited due to an RC time constant until the relay switches on.
// Misc.
#define DEBUG_OFF
// ??????????????????????? ****************** WAS IST DAS ????? **********************************************************`?????????????????????????????/
// 1-wire
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// Assign the addresses of your 1-Wire temp sensors.
// See the tutorial on how to obtain these addresses:
// http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html
DeviceAddress S01_ColdIntoPWT = { 0x28, 0x41, 0x6B, 0x07, 0xD6, 0x01, 0x3C, 0xAA }; // S01_ColdIntoPWT = TempSensors_Temps[0]
DeviceAddress S02_ColdFromPWT = { 0x28, 0x4F, 0xEA, 0x07, 0xD6, 0x01, 0x3C, 0xBF }; // S02_ColdFromPWT = TempSensors_Temps[1]
DeviceAddress S03_HotFromCompr = { 0x28, 0xCF, 0xC2, 0x07, 0xD6, 0x01, 0x3C, 0x93 }; // S03_HotFromCompr = TempSensors_Temps[2]
DeviceAddress S04_HotFromPWT = { 0x28, 0xD4, 0x45, 0x07, 0xD6, 0x01, 0x3C, 0xAA }; // S04_HotFromPWT = TempSensors_Temps[3]
DeviceAddress S05_AmbientOfUnit = { 0x28, 0xC9, 0x05, 0x07, 0xD6, 0x01, 0x3C, 0x52 }; // S05_AmbientOfUnit = TempSensors_Temps[4]
DeviceAddress S06_InsideFluid = { 0x28, 0xAA, 0xD5, 0xAC, 0x1D, 0x13, 0x02, 0xE5 }; // S06_InsideFluid = TempSensors_Temps[5]
DeviceAddress S07_CoolBoxS01 = { 0x28, 0xD4, 0xD1, 0xEA, 0x32, 0x14, 0x01, 0xDF }; // S07_CoolBoxS01 = TempSensors_Temps[6]
DeviceAddress S08_CoolBoxS02 = { 0x28, 0xAA, 0xC3, 0xDB, 0x1D, 0x13, 0x02, 0x2B }; // S08_CoolBoxS02 = TempSensors_Temps[7]
/****************** Constructors ******************************************************/
// OLED-Display
U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); // Please update the pin numbers according to your setup. Use U8X8_PIN_NONE if the reset pin is not connected
/****************** Variables **********************************************************/
// Arduino program loop
uint32_t currentTime;
uint32_t timer1;
uint32_t timer2;
// 1-wire
static float TempSensors_Temps[NUM_OW_SENSORS]; // Array which holds the current temperatures of all 1-wire temperature sensors
// Temperature control
// Inside cooling box, set the initial value to which the system shall control the temperatures of the water e.g.
float Temp_CoolBoxS0x_Lo = +0.1; // -0.3; Upd#002
float Temp_CoolBoxS0x_Hi = +0.7; // +0.5; Upd#002
bool Change_S01_Lo_or_Hi = false; // If the switches / keys shall change the "Lo" or the "Hi" value of the "S01" temperature sensor.
int TempSenseForCompressorCtrl = 8; // Defines the current active tempsens which controls the compressor, either "7" = "Ext. S01" or "8" = "Ext. S02"
// Flow-sensor
volatile int flow_frequency; // Measures flow sensor pulses
float l_minute = 0.0; // Calculated litres/minute
unsigned char flowsensor = 3; // Sensor Input on port D3
// MCP3221
//static unsigned int Compr_Cur_DigCode; // COMPRessor digital code read through MCP3221 ( 0 .. 4095 )
static float Compr_Cur_DigCode; // COMPRessor digital code read through MCP3221 ( 0 .. 4095 )
static float Compr_Cur_A; // COMPRessor CURrent read through MCP3221 stored in this variable in units "[A]"
static float Pump_Cur_DigCode; // PUMP digital code read through MCP3221 ( 0 .. 4095 )
static float Pump_Cur_A; // PUMP CURrent read through MCP3221 stored in this variable in units "[A]"
// Compressor switch on / off
bool ComprOnOff = false; // If the compressor shall be turned on or off
// Internal ADC for 12V VBB (VBAT) voltage reading
static int VBBmeas_ADC_val_DigCode = 0;
static float VBBmeas_ADC_val_V = 0; // ADC value for VBB (VBAT) measurement in units [V] but still from 0 .. 5V (not converted)
static float VBBmeas_VBB_V = 0; // VBB (VBAT) measurement: VBB measured / converted in(to) units [V]
// Misc
static unsigned short SysErr = 0; // If there is an error in the system, e.g. overtemperature of the compressor etc.
static unsigned short uCalive = 1; // Change value every e.g. 1s and display some character on OLED display
// WTD Watchdog "STWD100YNYWY3F": Timeout twd = 1.6 sec. ; tpw = 210 ms
bool WTD_WDI = false;
/***************************************************************************************/
/* Interrupt Subprogram / Function */
/***************************************************************************************/
void flow () // Interrupt function
{
flow_frequency++;
}
/***************************************************************************************/
/* Subprogram */
/***************************************************************************************/
// I2C Scanner from: "https://forum.arduino.cc/index.php?topic=632881.0" ; This sketch tests the standard 7-bit addresses, Devices with higher bit address might not be seen properly.
// If called stand-alone, it needs "#include <Wire.h>".
void func_I2C_Scanner()
{
digitalWrite( AliveErrorLED , HIGH );
byte error, address;
int nDevices;
#ifdef DEBUG_ON
Serial.print(F("\n----------------------\n"));
Serial.println("Scanning for I2C devices ...");
nDevices = 0;
#endif
for(address = 1; address < 127; address++ )
{
Wire.beginTransmission(address);
#ifdef DEBUG_ON
error = Wire.endTransmission(); // The i2c_scanner uses the return value of the Write.endTransmisstion to see if a device did acknowledge to the address.
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknown error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
#endif
}
#ifdef DEBUG_ON
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
#endif
}
/***************************************************************************************/
/* Subprogram */
/***************************************************************************************/
// Read 3 Switches = Pushbuttons over an analog input pin.
// (c) Bernd Cettl, 07/2021, based on script from "Doug LaRue" from "Nov. 2008".
/*
* analogPin VCC (+5 V)
* | |
* | |
* o -------------- |
* | | |
* | \ |
* ----- 120R / |
* ----- 100nF \ |
* | / |
* | \ |
* _____ |____ \____|
* ___ ground | SW1 |
* _ \ \
* / /
* 1k5 \ \ 1k5
* / /
* \ \
* |____ \____|
* | SW2 |
* \ \
* / /
* 1k5 \ \ 1k5
* / /
* \ \
* |____ \____|
* | SW3
* \
* 1k5 /
* \
* /
* \
* |
* _____
* ___ ground
* _
*
*/
int buttonPushed(int pinNum) {
int val; // variable to store the read value
val = analogRead(pinNum); // read the input pin
#ifdef DEBUG_ON
Serial.print(F("Switch / Button pressed read ADC value still in digital code (0..1023): "));
Serial.print(val);
Serial.print(F("[]\n"));
#endif
if ( val >= (1023-ERROR_WINDOW_SW) and val <= (1023) ) { // 1022 .. 1023
#ifdef DEBUG_ON
Serial.println("switch 1 pressed/triggered");
#endif
return 1;
}
else if ( val >= (681-ERROR_WINDOW_SW) and val <= (681+ERROR_WINDOW_SW) ) { // 681
#ifdef DEBUG_ON
Serial.println("switch 2 pressed/triggered");
#endif
return 2;
}
else if ( val >= (340-ERROR_WINDOW_SW) and val <= (340+ERROR_WINDOW_SW) ) { // 340
#ifdef DEBUG_ON
Serial.println("switch 3 pressed/triggered");
#endif
return 3;
}
else if ( val >= (615-ERROR_WINDOW_SW) and val <= (615+ERROR_WINDOW_SW) ) { // 615
#ifdef DEBUG_ON
Serial.println("switch 2 AND 3 at same time pressed/triggered");
#endif
return 23;
}
else
return 0; // no button found to have been pushed
}
/***************************************************************************************/
/* Main: Setup // put your setup code here, to run once: */
/***************************************************************************************/
void setup(void)
{
// WTD
pinMode( WTD_WDI_pin , OUTPUT );
digitalWrite( WTD_WDI_pin , LOW ); // Set any value at setup, hi or lo does not matter, because this pin should toggle anyway.
// System LED
pinMode( LED_BUILTIN , OUTPUT );
// AliveErrorLED
pinMode( AliveErrorLED , OUTPUT );
// Compressor switch on / off
pinMode( ComprOnOffPin , OUTPUT );
// Switches
pinMode( AnalogSwPin , INPUT );
// start serial port
#ifdef DEBUG_ON
Serial.begin(9600);
#endif
// 1-wire
// Do not wait for conversion
sensors.setWaitForConversion(false);
// Start up the library
sensors.begin();
// set the resolution to X bit
sensors.setResolution(S01_ColdIntoPWT, TEMPERATURE_PRECISION);
sensors.setResolution(S02_ColdFromPWT, TEMPERATURE_PRECISION);
sensors.setResolution(S03_HotFromCompr, TEMPERATURE_PRECISION);
sensors.setResolution(S04_HotFromPWT, TEMPERATURE_PRECISION);
sensors.setResolution(S05_AmbientOfUnit, TEMPERATURE_PRECISION);
sensors.setResolution(S06_InsideFluid, TEMPERATURE_PRECISION);
sensors.setResolution(S07_CoolBoxS01, TEMPERATURE_PRECISION);
sensors.setResolution(S08_CoolBoxS02, TEMPERATURE_PRECISION);
// Ask for a 1st conversion
sensors.requestTemperatures();
// Flow-sensor
pinMode(flowsensor, INPUT);
digitalWrite(flowsensor, HIGH); // Optional Internal Pull-Up
attachInterrupt(digitalPinToInterrupt(flowsensor), flow, RISING); // Setup Interrupt
// Start communication with I2C: Needed for MCP3221
Wire.begin();
// I2C devices
// I2C Scanner
func_I2C_Scanner();
// MCP3221: Hint from "https://forum.arduino.cc/index.php?topic=550117.0": Summary: It works, if we move the constructors ( = "MCP3221 mcp3221A(SLAVE1);" ; "MCP3221 mcp3221B(SLAVE2);") __INTO_ "loop()", thereby constructing 2 new slave devices at each cycle like so:
MCP3221 mcp3221A(SLAVE1);
// Ping
#ifdef DEBUG_ON
Serial.print(F("Slave A reading:\t"));
Serial.print(mcp3221A.ping() ? (F("Not Found\n")) : (F("Found!\n")));
#endif
// Set different things
mcp3221A.setSmoothing(NO_SMOOTHING);
// Get raw data
Compr_Cur_DigCode = mcp3221A.getData();
#ifdef DEBUG_ON
Serial.print(F("Compressor current still in digital code (0..4095): "));
Serial.print(Compr_Cur_DigCode);
Serial.print(F("[]\n"));
#endif
MCP3221 mcp3221B(SLAVE2);
// Ping
#ifdef DEBUG_ON
Serial.print(F("Slave B reading:\t"));
Serial.print(mcp3221B.ping() ? (F("Not Found\n")) : (F("Found!\n")));
#endif
// Set different things
mcp3221B.setSmoothing(NO_SMOOTHING);
// Get raw data
Pump_Cur_DigCode = mcp3221B.getData();
#ifdef DEBUG_ON
Serial.print(F("Pump current still in digital code (0..4095): "));
Serial.print(Pump_Cur_DigCode);
Serial.print(F("[]\n"));
#endif
// OLED-Display
u8x8.begin();
u8x8.setPowerSave(0);
// Write to OLED-Display
u8x8.setFont(u8x8_font_chroma48medium8_r);
u8x8.drawString(0,0,"Starting up...");
u8x8.refreshDisplay(); // only required for SSD1606/7
// Show setup display 2 seconds long
delay(2000);
// Clear display in order that some remaining characters are not displayed during the loop. E.g. If here in setup it says "Temperatures:" and later in the loop just say "Temps:" in the same line, that it doesn't write: "Temps:atures:"
u8x8.clear();
// Timing for the endless Arduino program loop
timer1 = millis();
timer2 = timer1;
// WTD
pinMode( WTD_EN_Q_pin , OUTPUT ); // Configure at END of setup as output, so that before it is default input and a pull-up resistor ties it high.
digitalWrite( WTD_EN_Q_pin , LOW ); // Enable watchdog at when start-up procedure is finished. Should be the last command in "setup", because from this time on, the time "twd" on the watchdog chip is running.
}
/***************************************************************************************/
/* Subprogram */
/***************************************************************************************/
float func_getTemperature(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
#ifdef DEBUG_ON
if (tempC == -127.00) {
Serial.print("Error getting temperature");
} else {
Serial.print("C: ");
Serial.print(tempC);
Serial.print(" F: ");
Serial.print(DallasTemperature::toFahrenheit(tempC));
}
#endif
return(tempC);
}
/***************************************************************************************/
/* Subprogram */
/***************************************************************************************/
void func_Task_exec_every_waitTime1(void)
{
// WTD: Toggle
WTD_WDI = !WTD_WDI;
digitalWrite( WTD_WDI_pin , WTD_WDI );
// Flow-sensor: Shall be the 1st entry in the loop (except Debug) because it shall be best exactly 1000ms and the difference how much it is more than 1000ms is calibrated away "(currentTime - cloopTime)", but if there are other time-consuming variable tasks in-between, this calibration is not good anymore. the
if(flow_frequency != 0){
// Flow sensor "YF-S201": Frequency (Hz) = 7.5 * Flow rate (L/min) ; Pulses per Liter: 450 ; Pulse frequency (Hz) = 7.5Q, Q is flow rate in L/min. //l_minute = (flow_frequency / 7.5); // (Pulse frequency x 60 min) / 7.5Q = flowrate in L/hour
l_minute = 1000.0 / ( currentTime - timer1 ) * ( flow_frequency / 7.5 ); // Because the variables "currentTime" and e.g. "timer1" are both in units [ms], also the difference is e.g. 2000ms. So 1000/2000 = * 0.5, if executed every 2 seconds. Because if e.g. executed every 2 seconds, with same flow rate, the pulses are doubled ( flow_frequency * 2 ), and the time passed also "currentTime - timer1", so e.g. "1000.0/(2000)" = *0.5 ==> And with *2*0.5 = 1 again.
flow_frequency = 0; // Reset Counter
//Serial.print(l_minute, DEC); // Print litres/min
//Serial.println(" l/min");
l_minute = l_minute * 0.9; // Correction: 3.0 l/min from Wasseruhr, YF-S201 displayed 3.33 l/min. => After this correction measured approx. correct at least with flow rates checked with 1 (one) l/min, and 3 l/min (on 21.02.2021).
}
else {
l_minute = 0; // To not keep the last value forever if there is no more flow.
}
// Reset the time count right after (in order that not even more time passes than 1000ms) the Flow-Sensor but also not before it (otherwise calibration of flow sensor will fail, see there).
// cloopTime = currentTime; // Updates cloopTime
// 1-wire
#ifdef DEBUG_ON
Serial.print("Getting temperatures...\n\r");
#endif
// Get the temperatures into a variable // Takes 100 ms getting all 8 temperatures into a variable ( = as follows ) , measured on 30.12.2023:
TempSensors_Temps[0] = func_getTemperature( S01_ColdIntoPWT );
TempSensors_Temps[1] = func_getTemperature( S02_ColdFromPWT );
TempSensors_Temps[2] = func_getTemperature( S03_HotFromCompr );
TempSensors_Temps[3] = func_getTemperature( S04_HotFromPWT );
TempSensors_Temps[4] = func_getTemperature( S05_AmbientOfUnit );
TempSensors_Temps[5] = func_getTemperature( S06_InsideFluid );
TempSensors_Temps[6] = func_getTemperature( S07_CoolBoxS01 );
TempSensors_Temps[7] = func_getTemperature( S08_CoolBoxS02 );
// Initiate a temperature conversion // Takes 2.5 ms initiating a temperature conversion ( = as follows ) , measured on 30.12.2023:
sensors.requestTemperatures(); // If set the command "sensors.setWaitForConversion(false);" is applied in the setup, this command here ("sensors.requestTemperatures();") must be applied AFTER fetching / getting the temperatures ("func_getTemperature"), otherwise, (a) "+85" reading(s) can/will occur because it does not have the time.
// Check if there is a temperature above 70°C, and if yes, set a "systen error" ("SysErr")
int countAbove70 = 0;
for( int i=0; i<NUM_OW_SENSORS; i++)
{
if( TempSensors_Temps[i] > 70.0)
{
countAbove70++;
}
}
#ifdef DEBUG_ON
Serial.print(F( "There are "));
Serial.print( countAbove70);
Serial.println(F( " sensors above 70.0"));
#endif
if( countAbove70 > 0) // at least one sensor above 70 degrees
{
SysErr = 1;
}
else
{
SysErr = 0;
}
// MCP3221: // Takes approx. only 220 us the complete MCP3221 ( = as follows ) , measured on 30.12.2023. // Hint from "https://forum.arduino.cc/index.php?topic=550117.0": Summary: It works, if we move the constructors ( = "MCP3221 mcp3221A(SLAVE1);" ; "MCP3221 mcp3221B(SLAVE2);") __INTO_ "loop()", thereby constructing 2 new slave devices at each cycle like so:
// Set different things and get raw data
MCP3221 mcp3221A(SLAVE1);
mcp3221A.setSmoothing(NO_SMOOTHING); // Obviously has to be repeated here in the loop. Is not enough to once define it in the setup.
Compr_Cur_DigCode = mcp3221A.getData();
MCP3221 mcp3221B(SLAVE2);
mcp3221B.setSmoothing(NO_SMOOTHING); // Obviously has to be repeated here in the loop. Is not enough to once define it in the setup.
Pump_Cur_DigCode = mcp3221B.getData();
// Print raw data to serial
#ifdef DEBUG_ON
Serial.print(F("Compressor current still in digital code (0..4095): "));
Serial.print(Compr_Cur_DigCode);
Serial.print(F("[]\n"));
Serial.print(F("Pump current still in digital code (0..4095): "));
Serial.print(Pump_Cur_DigCode);
Serial.print(F("[]\n"));
#endif
// Convert raw data to current
Compr_Cur_A = MPC3221_VREF_V * ( 2 * Compr_Cur_DigCode - 4096 ) / ( 4096 * 2 * SENS_ACS723_10__V_PER_A );
Pump_Cur_A = MPC3221_VREF_V * ( 2 * Pump_Cur_DigCode - 4096 ) / ( 4096 * 2 * SENS_ACS723_05__V_PER_A );
// Print converted currents to Amperes to serial
#ifdef DEBUG_ON
Serial.print(F("Compressor current in units [A]: "));
Serial.print(Compr_Cur_A);
Serial.print(F("[]\n"));
Serial.print(F("Pump current in units [A]: "));
Serial.print(Pump_Cur_A);
Serial.print(F("[]\n"));
#endif
// 12V VBB (VBAT) voltage reading (internal ADC) // Takes approx. only 130 us the complete 12V VBB (VBAT) voltage meas. ( = as follows ) , measured on 30.12.2023.
VBBmeas_ADC_val_DigCode = analogRead( VBB_MEAS_ANALOG_IN_PIN );
VBBmeas_ADC_val_V = VBBmeas_ADC_val_DigCode * ( VCC_VREF_V / 1024 );
VBBmeas_VBB_V = VBBmeas_ADC_val_V * VBB_MEAS_RES_DIV_GAIN;
// Switches
int buttNum = buttonPushed(AnalogSwPin);
#ifdef DEBUG_ON
Serial.print("Button "); Serial.print(buttNum); Serial.println(" was pushed.");
#endif
if ( Change_S01_Lo_or_Hi == false ) { // If "Change_S01_Lo_or_Hi" = e.g. Lo ( = e.g. "false") ==> Allow to modify the "Lo" value with the switches / keys.
if ( buttNum == 1 ) {
Temp_CoolBoxS0x_Lo = Temp_CoolBoxS0x_Lo + 0.1;
}
else if ( buttNum == 2 ) {
Temp_CoolBoxS0x_Lo = Temp_CoolBoxS0x_Lo - 0.1;
}
}
else { // If "Change_S01_Lo_or_Hi" = e.g. Hi ( = e.g. "true") ==> Allow to modify the "Hi" value with the switches / keys.
if ( buttNum == 1 ) {
Temp_CoolBoxS0x_Hi = Temp_CoolBoxS0x_Hi + 0.1;
}
else if ( buttNum == 2 ) {
Temp_CoolBoxS0x_Hi = Temp_CoolBoxS0x_Hi - 0.1;
}
}
if ( buttNum == 3 ) { // Button nr. 3 changes the modification of either the "Lo" or "Hi" value of the "S01".
Change_S01_Lo_or_Hi = !Change_S01_Lo_or_Hi;
}
if ( buttNum == 23 ) { // Button nr. 2 and 3 at same time changes the tempsense for active compressor control
if ( TempSenseForCompressorCtrl == 7 ) {
TempSenseForCompressorCtrl = 8; // Change the tempsense for active compressor control
#ifdef DEBUG_ON
Serial.println("TempSenseForCompressorCtrl = 8 was set");
#endif
}
else if ( TempSenseForCompressorCtrl == 8 ) {
TempSenseForCompressorCtrl = 7; // Change the tempsense for active compressor control
#ifdef DEBUG_ON
Serial.println("TempSenseForCompressorCtrl = 7 was set");
#endif
}
}
// Higher limit must be higher than the lower limit, because it does only cooling
if ( Temp_CoolBoxS0x_Lo >= Temp_CoolBoxS0x_Hi ) {
Temp_CoolBoxS0x_Hi = Temp_CoolBoxS0x_Lo + 1;
}
#ifdef DEBUG_ON
Serial.print("Temp_CoolBoxS0x_Lo = "); Serial.println(Temp_CoolBoxS0x_Lo);
Serial.print("Temp_CoolBoxS0x_Hi = "); Serial.println(Temp_CoolBoxS0x_Hi);
#endif
// Compressor switch on / off control
if ( SysErr == 1 ) { // If a system error ( = e.g. critical temperature is reached anywhere) occurred ...
ComprOnOff = false; // ... turn off the compressor
}
else {
if ( TempSensors_Temps[TempSenseForCompressorCtrl-1] < Temp_CoolBoxS0x_Lo ) { // If the temperature of sensor "S0x" (so ext. Sensor "S01" or "S02") is <= as the minimum set temperature ...
ComprOnOff = false; // ... turn off the compressor
}
if ( TempSensors_Temps[TempSenseForCompressorCtrl-1] > Temp_CoolBoxS0x_Hi ) { // If the temperature of sensor "S0x" (so ext. Sensor "S01" or "S02") is <= as the minimum set temperature ...
ComprOnOff = true; // ... turn on the compressor
}
}
if ( ComprOnOff == false ) {
digitalWrite( ComprOnOffPin , LOW );
}
if ( ComprOnOff == true ) {
digitalWrite( ComprOnOffPin , HIGH );
}
// OLED-Display // Takes 220 .. 230 ms writing the complete display ( = as follows ) , measured on 30.12.2023.
// Blanks for safety if temp sense temp values "are out of range" or if the decimal point (".") changes position due to the minus sign ("-"). To write the full display with blank characters / strings does not look nice because it is too slow.
for (uint8_t i = 0; i < NUM_OW_SENSORS; i++) { // For all 8 lines
u8x8.drawString(2, i, " ");
u8x8.drawString(7, i, " ");
u8x8.drawString(8, i, " ");
u8x8.drawString(13, i, " ");
}
// Draw blanks at the end of the last 2 lines because to see which line = which sensors controls the compressor
u8x8.drawString(8, 6, " ");
u8x8.drawString(8, 7, " ");
// Write temperatures to OLED-Display
u8x8.drawString(0, 0, "CI"); // Cold Into the plate heat exchanger
u8x8.drawString(0, 1, "CO"); // Cold Out of the plate heat exchanger
u8x8.drawString(0, 2, "HC"); // Hot out of the Compressor
u8x8.drawString(0, 3, "HO"); // Hot Out of the plate heat exchanger
u8x8.drawString(0, 4, "AT"); // Ambient Temperature
u8x8.drawString(0, 5, "IF"); // Inside Fluid
u8x8.drawString(0, 6, "S1"); // CoolBox inside Sensor 01
u8x8.drawString(0, 7, "S2"); // CoolBox inside Sensor 02
for (uint8_t i = 0; i < NUM_OW_SENSORS; i++) {
u8x8.setCursor(3,i); // Set cursor to column 3 of display (starting with column "0")
u8x8.print(TempSensors_Temps[i],2);
}
// Write flow rate to OLED-Display
u8x8.drawString(9, 1, " "); // Obviously additionally needed to clear this part of the display, otherwise could happen, that if number falls below 4 digits (e.g. "1000"), then the last "0" remains, so e.g. if first was "1234mV" displayed, then only "980mV" that the display showed "9804mV".
u8x8.setCursor(9,1);
u8x8.print(l_minute,2);
u8x8.drawString(9, 0, "CAL!"); // Durchfluss-Sensor brauch erneute Kalibration nachdem die LoopTime ohne Delay umgestellt worden ist!!
u8x8.drawString(14, 1, "FR");
// Write compressor and pump current to OLED-Display
u8x8.drawString(9, 2, " "); // Obviously additionally needed to clear this part of the display, otherwise could happen, that if number falls below 4 digits (e.g. "1000"), then the last "0" remains, so e.g. if first was "1234mV" displayed, then only "980mV" that the display showed "9804mV".
u8x8.setCursor(9,2);
u8x8.print(Compr_Cur_A , 1); // Although "unsigned int", "1" decimal place necessary; with "0", it doesn't display the voltage
u8x8.drawString(14, 2, "CC"); // CC = Compressor Current
u8x8.drawString(9, 3, " "); // Obviously additionally needed to clear this part of the display, otherwise could happen, that if number falls below 4 digits (e.g. "1000"), then the last "0" remains, so e.g. if first was "1234mV" displayed, then only "980mV" that the display showed "9804mV".
u8x8.setCursor(9,3);
u8x8.print(Pump_Cur_A , 1); // Although "unsigned int", "1" decimal place necessary; with "0", it doesn't display the voltage
u8x8.drawString(14, 3, "PC"); // PC = Pump Current
// Write VBB voltage to OLED-Display
u8x8.drawString(9, 4, " "); // Obviously additionally needed to clear this part of the display, otherwise could happen, that if number falls below 4 digits (e.g. "1000"), then the last "0" remains, so e.g. if first was "1234mV" displayed, then only "980mV" that the display showed "9804mV".
u8x8.setCursor(9,4);
u8x8.print(VBBmeas_VBB_V , 1); // Although "unsigned int", "1" decimal place necessary; with "0", it doesn't display the voltage
u8x8.drawString(14, 4, "VB"); // VB = VBB (VBAT) = nom. 12V
// Switches
// u8x8.setCursor(15,5);
// u8x8.print(buttNum , 1); // Although "unsigned int", "1" decimal place necessary; with "0", it doesn't display the voltage
// Compressor state
if ( ComprOnOff == false ) {
u8x8.drawString(13, 5, "OFF");
}
if ( ComprOnOff == true ) {
u8x8.drawString(13, 5, " ON");
}
// Display the set 2 temperature threshold values (switch-on and switch-off threshold)
// Lower value
u8x8.drawString(8, TempSenseForCompressorCtrl-1, " ");
if ( Temp_CoolBoxS0x_Lo < 0 ) {
u8x8.drawString(8, TempSenseForCompressorCtrl-1, "-");
}
else {
u8x8.drawString(8, TempSenseForCompressorCtrl-1, "+");
}
u8x8.setCursor(9,TempSenseForCompressorCtrl-1);
u8x8.print( abs(Temp_CoolBoxS0x_Lo) , 1); // Although "unsigned int", "1" decimal place necessary; with "0", it doesn't display the voltage
// Higher value
u8x8.drawString(12, TempSenseForCompressorCtrl-1, " "); // One blank " " less thank above ( = with "Temp_CoolBoxS0x_Lo") because end column of display.
if ( Temp_CoolBoxS0x_Hi < 0 ) {
u8x8.drawString(12, TempSenseForCompressorCtrl-1, "-");
}
else {
u8x8.drawString(12, TempSenseForCompressorCtrl-1, "+");
}
u8x8.setCursor(13,TempSenseForCompressorCtrl-1);
u8x8.print( abs(Temp_CoolBoxS0x_Hi) , 1); // Although "unsigned int", "1" decimal place necessary; with "0", it doesn't display the voltage
// Show that uC and display is alive and switch "Alive/Error LED": // If everything ok, then AliveErrorLED = "HI,LO,LO,LO", else "HI,LO,HI,HI" PWM.
switch (uCalive) {
case 1:
u8x8.drawString(15, 0, "-");
uCalive = 2;
digitalWrite( LED_BUILTIN , HIGH );
digitalWrite( AliveErrorLED , HIGH );
break;
case 2:
u8x8.drawString(15, 0, "\\");
uCalive = 3;
digitalWrite( LED_BUILTIN , LOW );
digitalWrite( AliveErrorLED , LOW );
break;
case 3:
u8x8.drawString(15, 0, "|");
uCalive = 4;
if ( SysErr >= 1 )
digitalWrite( AliveErrorLED , HIGH );
break;
case 4:
u8x8.drawString(15, 0, "/");
uCalive = 1;
break;
default:
u8x8.drawString(15, 0, "E"); // Error !
break; // Wird nicht benötigt, wenn Statement(s) vorhanden sind
}
// Update OLED-Display
u8x8.refreshDisplay(); // only required for SSD1606/7
}
/***************************************************************************************/
/* Subprogram */
/***************************************************************************************/
void func_Task_exec_every_waitTime2(void)
{
// delay(50);
}
/***************************************************************************************/
/* Main: Loop // put your main code here, to run repeatedly: */
/***************************************************************************************/
void loop(void)
{
// Timing for the endless Arduino program loop // Scheduler: Especially for flow-sensor
currentTime = millis();
// Execution every "waitTime1" ms
if ( currentTime - timer1 > waitTime1 )
{
func_Task_exec_every_waitTime1();
timer1 = currentTime; // Assign this variable only at the end after (all the) function call(s) (execution(s)), because inside those execution(s), the timer variable(s) (such es e.g. "timer1" , "timer2") might be used. If this line would be placed before the function calls, the timer variables woulld have the very same value as the variable "currentTime".)
}
// Execution every "waitTime2" ms
if ( currentTime - timer2 > waitTime2 )
{
func_Task_exec_every_waitTime2();
timer2 = currentTime; // Assign this variable only at the end after (all the) function call(s) (execution(s)), because inside those execution(s), the timer variable(s) (such es e.g. "timer1" , "timer2") might be used. If this line would be placed before the function calls, the timer variables woulld have the very same value as the variable "currentTime".)
}
}
Thank you so much for all your help, have a nice year 2024, and bye,
bernd2700