Using temp array on already fairly full UNO WiFi Rev2 [Closed]

Your data saving ideas using certain definitions is very interesting and I will muse those options certainly. I like the FRAM idea and not losing the data after a restart. Know nothing about it but will investigate what is involved.

I am using DS18B20s (the real ones btw...lol) and the tank temps vary between 150 and 175 dgf so not a large span at all. And I currently am using straight integer values (no float precision) as my use of Stackstring for the webpage display precludes floating values. Which is one drawback about Stackstring.

Thanks for sharing your knowledge. :+1:

It’s just going to be like my print function, going through the array but instead of sending to the serial monitor, you’ll be sending the data formatted with some html to the web client.

That’s definitely a good use of the structure. You can pack together different types of variables to make one record. A timestamp is a great addition.

@edthewino

You can find my FRAM library here - GitHub - RobTillaart/FRAM_I2C: Arduino library for I2C FRAM

If you have a range of 150 - 175 °F there are two options:

either you use 150.0 ..175.5 => 255 values in one byte with decimal precision

uint8_t codedValue = (TF - 150.0) * 10;
float TF = (codedValue * 0.1) + 150:

or
you use the range 0 - 255°F just as integer.

The latter has the advantage that you see when the tank is cooling down or overheating.
So it allows you to add safety margins.

You can also select something in between like the range from 120-200 °F with one decimal
(steps of 0.2°F) that balances precision and detection of over/underheating.

Rob,

Again thank you for sharing your link. I will certainly look at what you have setup and see if
I can incorporate certain aspects of it into my boiler code. :ok_hand:

Is there anything preventing using an array where you assign a specific integer value
for a specific data variable?

Example:

array[0] = analog input value A stored; triggered by digital input 1 [boiler lockout/enable]

array[1] = analog input value A stored; triggered by digital input 2 [aquastat call for heat]

array[2] = analog input value A stored; triggered by digital input 3 [boiler Run command]

array[3] = analog input value A stored; triggered by digital input 1 [boiler lockout/enable]

array[4] = analog input value A stored; triggered by digital input 2 [aquastat call for heat]

array[5] = analog input value A stored; triggered by digital input 3 [boiler Run command]

and so on....for 4 or 5 sets...

These values would be overwritten once all the "sets" are filled. The reason I ask is this would allow me to correlate specific array assignments to specific digital input actions.

Does this make sense? ..lol

You can use two arrays, one to store the values and one to store the pin that triggered the storing of a value. Below demonstrates (assuming that a HIGH signal triggered.

const uint8_t maxStorage = 100;
uint16_t reading[maxStorage];
uint8_t pinIndex[maxStorage];

const uint8_t trigPins[] = {3, 4, 5};


void setup()
{
  // put your setup code here, to run once:

}

void loop()
{
  static uint8_t index;

  for (uint8_t cnt = 0; cnt < sizeof(trigPins) / sizeof(trigPins[0]); cnt++)
  {
    if (digitalRead(trigPins[cnt]) == HIGH)
    {
      reading[index] = analogRead(A0);
      pinIndex[index] = cnt;
    }
    index++;
    if (index == maxStorage)
    {
      index = 0;
    }
  }
}

In above the index of the trigger pin is stored at the same time as the reading. I've used the pin index instead of the physical pin number to prepare for the last code below.

It would be neater to use a struct that can allow you to indicate which pin is associated with the entry. That would look like below

const uint8_t maxStorage = 100;
const uint8_t trigPins[] = {3, 4, 5};

struct READING
{
  uint16_t reading;
  uint8_t pinIndex;
};

READING readings[maxStorage];


void setup()
{
  // put your setup code here, to run once:

}

void loop()
{
  static uint8_t index;

  for (uint8_t cnt = 0; cnt < sizeof(trigPins) / sizeof(trigPins[0]); cnt++)
  {
    if (digitalRead(trigPins[cnt]) == HIGH)
    {
      readings[index].reading = analogRead(A0);
      readings[index].pinIndex = cnt;
    }
    index++;
    if (index == maxStorage)
    {
      index = 0;
    }
  }
}

And if you're worried about RAM usage, you can use bitfields.

const uint8_t maxStorage = 100;
const uint8_t trigPins[] = {3, 4, 5};

struct READING
{
  uint16_t reading: 10;   // analogRead returns a 10 bit value
  uint16_t pinIndex:  2;  // 2 bits allow for 4 trigger pins
};

READING readings[maxStorage];


void setup()
{
  // put your setup code here, to run once:

}

void loop()
{
  static uint8_t index;

  for (uint8_t cnt = 0; cnt < sizeof(trigPins) / sizeof(trigPins[0]); cnt++)
  {
    if (digitalRead(trigPins[cnt]) == HIGH)
    {
      readings[index].reading = analogRead(A0);
      readings[index].pinIndex = cnt;
    }
    index++;
    if (index == maxStorage)
    {
      index = 0;
    }
  }
}

The change is in the struct where above code now specifies how many bits a variable uses. You can check the difference by printing sizeof(READING) in setup. For the first code with the struct the size should be 3 bytes, for the second one it should be two bytes.

That is interesting how you laid that out. My neophytic programming mind is trying to digest everything presented. First, I did not realize semicolons were a thing in for statements (cnt = 0;)

Second, is that a division symbol you are using with "sizeof (trigPins) / sizeof (trigPins[0]);" ???

Talking with you forum experts reminds me just how little I really know. Just enuf to be dangerous most of the time. ...lol

That means "back-to-school" :wink:

Yes

sizeof(x) gives the size in bytes of a variable with the name 'x'. So sizeof(trigPins) gives 3.

In the first example, sizeof(pinIndex) will give 100 (100 times 1 byte) but sizeof(reading) will give 200 (100 times 2 bytes).

sizeof(x[0]) will give the size of the first element of an array with the name 'x'. For an uint16_t that will be 2. Divide the size of the 'reading' array (200) by the size of the first element of that array (2) and you get the number of elements in the array.

It's may be a bit overkill to use this division for uint8_t arrays (because dividing by 1 is not very useful) but it's kind-of automatic for me to use it.

Note that sizeof(x) is evaluated at compile time, not when the code is running. So for (uint8_t cnt = 0; cnt < sizeof(trigPins) / sizeof(trigPins[0]); cnt++) becomes for (uint8_t cnt = 0; cnt < 3; cnt++) before your code will actually be compiled.

Just a side note on this - as GCC supports variable length arrays, sizeof will also work at run time for those.

Your willingness to explain the circumstances around the use of division is very appreciated.
It is very easy to copy & paste code to use in a sketch but I am not fond of using code where my understanding is eqivalent to "it's magic." I am fond of Arthur C. Clarke's quote:
"Any sufficiently advanced technology is indistinguishable from magic."

thanks for the assist... :+1:

Ok, your 1st code segment works fine once you put the serial monitor output inside the 'for loop' and not outside it! ...lol..

I gotta try those other two now and see how all that pans out. :+1:

I copied and pasted your code in to the IDE and of course it complies w/o errors.

What I noticed is that this code is designed for inputing three different temp sensors.
My objective is to use three DIGITAL inputs to trigger a recording of one COMMON temp sensor.
In other words when the boiler lockout input signal changes state in my heating system I want to record the hot water tank temp. If the tank aquastat calls for heat I want to record the tank temp. And lastly when the boiler RUN command is issued I want to record the tank temp.
I am going to study that link you provided about circular arrays and see if it is adaptable to my needs.
thanks for your input... :+1:

So I think that I am not able to modify your code to actually use real analog inputs as it appears you are randomly generating values for demonstration purposes. I commented the part that randomly generates numeric values. But the data fields are all blank. It did
compile though!!! Which proves code that compiles can still be junk code. ...lol...

void loop() {
 int16_t tempSensor1 = analogRead(A0);
 int16_t tempSensor2 = analogRead(A1);
 int16_t tempSensor3 = analogRead(A2);

//  addHistoricalData(random(200), random(200), random(200));  // add a new random entry
 
  printHistoricalData();
  delay(2000);
}

This is correctly acquiring the analog values but you fail to add them into the array since you commented out the function call where I was adding random stuff into the array.

If you add an
addHistoricalData(tempSensor1, tempSensor2, tempSensor3);

After reading the data then the print will work

addHistoricalData() is the function managing the circular array (ie adds the data in the space available possibly overwriting the oldest data once the array is full)

I wanted to be sure and tell you that the code you provided is the one I was able to install, modify to suit my needs, and with a bit more tweaking I think will be my solution.
I have added digital inputs to the structure and they are being recorded in conjunction with the analog value. As soon as I went back and added the inputs to the ADD function as you suggested everything started humming along.

A lot of others provided their code and memory usage insights and I appreciate everyone's generosity to share. :+1:

Great!

Keep at it!