Find highest/lowest value within a defined range

#include <Wire.h>

void setup() {

  Serial.begin(9600, SERIAL_8N1);
  Serial1.begin(9600, SERIAL_8N1);
  Serial.setTimeout(500);
  Serial1.setTimeout(50);
  Wire.begin();

}


void loop() {

  delay(10000);
  String IcolMin = String(0.0330, 4);
  String IcolMax = String(0.0900, 4);
  String Icol = String(0.0000, 4);

  Serial1.println(":OUTP CH1,ON");

  int cnt = 0;

while (cnt < 20 && (Icol < IcolMin) || (Icol > IcolMax)){
  Serial1.println(":MEAS:CURR? CH1");
  Icol = Serial1.readString();
  cnt++;
  }

if ((Icol > IcolMin) && (Icol < IcolMax)){
  Serial.println(" I=");
  Serial.println(Icol.toFloat() * 1000);
  Serial.println("mA");
}
  else {
  Serial.println("Failed");
}

I made this to readout values from a serial device.
As you can see it takes up to 20 measurements between a defined min/max.
I would like to add the possibility to find the highest and/or lowest value out of these measurements and save them to a new variable or overwrite the existing variable "Icol".

Unfortunately I need to use Serial.readString(); to get valid data

You don’t “need to”, you chose to…
The String class has a (not error proof) method to convert the String to a float
To find the min and max,define two float variables minVal and maxVal, and initialize minVal whith the largest possible expected value and maxVal with the lowest and each time you get a new value compare with minVal and maxVal and update appropriately

There are two ways to initialize:

  • Set the minVal and maxVal out of range. If, for example, the room temperature is measured, then set the minVal to +1000.0 and the maxVal to -1000.0. It allows to detect if a new value was set or not.
  • Set the minVal and maxVal to the first value and try to find a lower and higher one. This is safer, but the first value has to be available at the moment of initialization.

With the "range based" for-loop, the code is very simple:

const float numbers[] = 
{
  10.0, 100.0, -123.0, 560.3, 3.5, 7.123456, 0.0, -10.5, 
};

void setup() 
{
  Serial.begin( 115200);

  // find min
  float min = numbers[0];
  for( auto a:numbers)      // "range based" for-loop
    if( a < min)
      min = a;

  // find max
  float max = numbers[0];
  for( auto a:numbers)
    if( a > max)
      max = a;

  Serial.print( "Minimum = ");
  Serial.println( min);
  Serial.print( "Maximum = ");
  Serial.println( max);
}

void loop() 
{
}

This sketch in Wokwi: MinMax.ino - Wokwi Arduino Simulator

If you don’t know the first value nor the range (and If the compiler supports it, Inever tried), you can get the min and max float values

#include <limits>
std::numeric_limits<float>::max();
std::numeric_limits<float>::min();

this doesn't work on AVR based boards

That's OK, because the Due doesn't have an AVR.

how to implement this?

but how do I get the individual measurements into an array?

Give it a try and post your code

#include <limits>
#include <Wire.h>

void setup() {

  Serial.begin(9600, SERIAL_8N1);
  Serial1.begin(9600, SERIAL_8N1);
  Serial.setTimeout(500);
  Serial1.setTimeout(50);
  Wire.begin();

}


void loop() {

  delay(10000);
  String IcolMin = String(0.0330, 4);
  String IcolMax = String(0.0900, 4);
  String Icol = String(0.0000, 4);

  Serial1.println(":OUTP CH1,ON");

  int cnt = 0;

while (cnt < 20 && (Icol < IcolMin) || (Icol > IcolMax)){
  Serial1.println(":MEAS:CURR? CH1");
  Icol = Serial1.readString();
  cnt++;
  }

if ((Icol > IcolMin) && (Icol < IcolMax)){
  Serial.println(" I=");
  std::numeric_limits<float>::max();
  Serial.println(Icol.toFloat() * 1000);
  Serial.println("mA");
}
  else {
  Serial.println("Failed");
}

output: Failed

Have you tried printing the values?

new approach

///////////////////////////////////////////////////////////////////
//TEMPLATE FUNCTIONS FIND MIN MAX
///////////////////////////////////////////////////////////////////
template <typename T, size_t size> T maxRead(const T (&arr)[size]) {
  T maxValue {arr[0]};
  for (auto &value : arr) maxValue = max(maxValue, value);
  return maxValue;
}

template <typename T, size_t size> T minRead(const T (&arr)[size]) {
  T minValue {arr[0]};
  for (auto &value : arr) minValue = min(minValue, value);
  return minValue;
}
///////////////////////////////////////////////////////////////////

byte measCount = 20;
String value[20];

void setup() {
  Serial.begin(9600, SERIAL_8N1);
  Serial1.begin(9600, SERIAL_8N1);
  Serial.setTimeout(500);
  Serial1.setTimeout(50);
  Serial1.println(":OUTP CH1,OFF");
  Serial1.println(":APPL CH1,6,0.2");
}

void loop() {
  
Serial1.println(":OUTP CH1,ON");
delay(100);
Serial.println("Starting measurement");
  for (int x = 0; x < measCount; x++) {
    Serial1.println(":MEAS:CURR? CH1");
    value[x] = Serial1.readString();
  }
  int z = 19;
  for (int y = 0; y < measCount; y++) {
      Serial.print(value[y]);

      if (y == z) {
      Serial.print("max");
      Serial.println(maxRead(value));
      Serial.print("min");
      Serial.println(minRead(value));
      } else {
    }
  }
  Serial1.println(":OUTP CH1,OFF");
  Serial1.println(":APPL CH1,6,0.2");
  delay(3000);
}

found these templates, still working on the rest

What the return type of readString()? does it match where you are attempting to store the data?

data out of the monitor:

Starting measurement
0.0000
0.0000
0.0000
0.0000
0.0139
0.0139
0.0117
0.0117
0.0117
0.0117
0.0116
0.0116
0.0116
0.0116
0.0116
0.0116
0.0116
0.0116
0.0116
0.0116
max0.0139

min0.0000

so how to define range? :thinking:

Was that an answer to my questions?

it is still a String I guess

I had 2 questions.

I am assuming I wouldn't get output if it would be the wrong data type? Obviously it can store and print the data

You edited and modified the code since I asked… (noticed the Orange pencil?) now the discussion is meaningless…