При конфигурировании датчиков возникает необходимость ввести поправочные коэффициенты после калибровки. В идеале иметь возможность в конфигурационном файле задать простую математическую формулу для корректировки значений получаемых с датчика. К сожалению, для Arduino мне не удалось найти нормальную библиотеку для парсинга (вычисления) математических выражений заданных в виде строки.
Ресурсы микроконтроллера надо беречь, поэтому использовать код для продвинутых анализаторов строковых математических функций не годится. Поэтому я написал очень простой математический решатель, который не поддерживает приоритет математических операций и скобки, но его более чем достаточно для ввода поправочных коэффициентов.
Небольшой пример использования.
String expression = "%V%*1.1+0.5";
float value = modbusCfg.Eval(expression, 10.5);
Serial.println("Value of " + expression + ": " + String(value));
expression = "1.1+2.2*%V%+0.5";
value = modbusCfg.Eval(expression, 10.5);
Serial.println("Value of " + expression + ": " + String(value));
expression = "1+0.5";
value = modbusCfg.Eval(expression, 10);
Serial.println("Value of " + expression + ": " + String(value)); В исходном строковом выражнии %V% заменяется на значение полученное от датчика. Например, датчики нередко возвращают int и для приведения цифр к нормальной величине нужно разделить на 10. В этом случае выражение будет %V%/10. При этом даже цифровые термодатчики врут, поскольку дешевые термодатчики, похоже, никто не калибрует. Например, если термодатчик врет на 0,7 градуса, показывая завышенные значения, то выражение будет %V%/10 + 0.7.
Поскольку, нередко, достаточно умножить полученное значение на 0.1, например. В этом случае в выражении достаточно написать 0.1 — операция умножения выполняется по-умолчанию, если не указан %V%.
Этот блок кода используется в моей библиотеке ModbusConfig для конфигурирования датчиков различного типа.
void ModbusConfig::math_operation(math_op op, float &prev_val, String &current_val, float &value)
{
if (prev_val != -16101975) //Check if the default value has changed
{
if (current_val.length() > 0)
{
float second = current_val.toFloat();
switch (op)
{
case math_op::Mul:
value = prev_val * second;
break;
case math_op::Add:
value = prev_val + second;
break;
case math_op::Div:
value = prev_val / second;
break;
case math_op::Sub:
value = prev_val - second;
break;
case math_op::None:
printf("There is no operation.");
}
prev_val = value;
current_val = "";
}
}
else
{
if (current_val.length() > 0)
{
prev_val = current_val.toFloat();
current_val = "";
}
}
}
float ModbusConfig::Eval(String expr, float value)
{
String pattern = "%V%";
int pos = expr.indexOf(pattern);
if (pos == -1)
{
expr = "%V%*" + expr;
}
expr.replace("%V%", String(value));
String val = "";
math_op last_op = math_op::None;
float prev_val = -16101975;//Set the some default value to check if the value has changed
value = 0;
for (int i = 0; i < expr.length(); i++)
{
switch (expr[i])
{
case '*':
math_operation(last_op, prev_val, val, value);
last_op = math_op::Mul;
break;
case '+':
math_operation(last_op, prev_val, val, value);
last_op = math_op::Add;
break;
case '/':
math_operation(last_op, prev_val, val, value);
last_op = math_op::Div;
break;
case '-':
math_operation(last_op, prev_val, val, value);
last_op = math_op::Sub;
break;
default:
if (isdigit(expr[i]) || expr[i] == '.' || expr[i] == ',')
{
val += (expr[i] == ',') ? '.' : expr[i];
}
break;
}
}
math_operation(last_op, prev_val, val, value);
return value;
}
1 Responses to Вычисление простых математических выражений на ESP32/ESP8266/Arduino