Почему данные, которые я отправляю на сервер, округляются и как вместо этого отправить все число с плавающей запятой?

#include <Arduino.h>
#include <WiFi.h>
#include "WiFiManager.H"
#include <HTTPClient.H>
#include "ESPAsyncWebServer.h"
#include <AsyncTCP.h>

float version = 1.9;

uint32_t chipId = 0;
String chipId2 = "";
int i;

String serverName = "http://d";

// Менеджер Wi-Fi
// Локальная инициализация. После того, как его бизнес сделан, нет необходимости держать его рядом
WiFiManager wifiManager;

// Создаем объект AsyncWebServer на порту 80
AsyncWebServer server2(80);
WiFiServer server(80);

// переменные для подсчета импульсов счетчиков.
int count1=0;
float prior_count1=0;
int count2=0;
float prior_count2=0;
int count3=0;
float prior_count3=0;
int count4=0;
float prior_count4=0;
int countgas=0;
float prior_countgas=0;
int countwater=0;
float prior_countwater=0;

String payloadpulse = "0";

unsigned long lastTime = 0;
unsigned long timerDelay = 6000;

String guifactor1 = "1000";
String guifactor2 = "1000";
String guifactor3 = "1000";
String guifactor4 = "1000";
String guifactorgas = "1000";
String guifactorwater = "1000";

String counter1 = "1";
String counter2 = "1";
String counter3 = "1";
String counter4 = "1";
String counter5 = "1";
String counter6 = "1";

// функция для увеличения значения счетчика на 1.
void pulse1() {
  if (counter1.toInt() == 1) {
    count1 = count1 + 1;
  }
  
  if (counter1.toInt() == 2) {
    count1 = count1 - 1;
  }
}

void pulse2() {
  if (counter2.toInt() == 1) {
    count2 = count2 + 1;
  }
  
  if (counter2.toInt() == 2) {
    count2 = count2 - 1;
  }
}

void pulse3() {
  if (counter3.toInt() == 1) {
    count3 = count3 + 1;
  }
  
  if (counter3.toInt() == 2) {
    count3 = count3 - 1;
  }
}

void pulse4() {
  if (counter4.toInt() == 1) {
    count4 = count4 + 1;
  }
  
  if (counter4.toInt() == 2) {
    count4 = count4 - 1;
  }
}

void pulsegas() {
  if (counter5.toInt() == 1) {
    countgas = countgas + 1;
  }
  
  if (counter5.toInt() == 2) {
    countgas = countgas - 1;
  }
}

void pulsewater() {
  if (counter6.toInt() == 1) {
    countwater = countwater + 1;
  }
  
  if (counter6.toInt() == 2) {
    countwater = countwater - 1;
  }
}
                                                                                                                
void setup() {                                                                                                                                       
  Serial.begin(115200);                                                                                                                 

  wifiManager.autoConnect("ss", "ss");

  pinMode(25, INPUT_PULLDOWN); // Установите GPIO25 в качестве цифрового вывода
  attachInterrupt(digitalPinToInterrupt(25), pulse1, RISING); 

  pinMode(19, INPUT_PULLDOWN); // Установите GPIO19 в качестве цифрового вывода
  attachInterrupt(digitalPinToInterrupt(19), pulse2, RISING); 

  pinMode(23, INPUT_PULLDOWN); // Установите GPIO22 в качестве цифрового вывода
  attachInterrupt(digitalPinToInterrupt(23), pulse3, RISING); 

  pinMode(18, INPUT_PULLDOWN);// Установить GPIO18 в качестве цифрового вывода
  attachInterrupt(digitalPinToInterrupt(18), pulse4, RISING); 

  pinMode(21, INPUT_PULLDOWN); // Установите GPIO22 в качестве цифрового вывода
  attachInterrupt(digitalPinToInterrupt(21), pulsegas, RISING); 

  pinMode(5, INPUT_PULLDOWN); // Установите GPIO5 в качестве цифрового вывода
  attachInterrupt(digitalPinToInterrupt(5), pulsewater, RISING); 
}

//------------------------------------------------ --------------------
void loop() {
  float new_count1  = static_cast<float> (count1) / guifactor1.toInt();
  float new_count2 = static_cast<float> (count2) / guifactor2.toInt();
  float new_count3 = static_cast<float> (count3) / guifactor3.toInt();
  float new_count4 = static_cast<float> (count4) / guifactor4.toInt();
  float new_countgas = static_cast<float> (countgas) / guifactorgas.toInt();
  float new_countwater = static_cast<float> (countwater) / guifactorwater.toInt();

  // отслеживает количество импульсов счетчиков пульса
  if (new_count1 != prior_count1 ||
   new_count2 != prior_count2 ||
    new_count3 != prior_count3 ||
     new_count4 != prior_count4 ||
      new_countgas != prior_countgas ||
       new_countwater != prior_countwater) {
     Serial.println(new_count1, 4);
     Serial.println(new_count2, 4);
     Serial.println(new_count3, 4);
     Serial.println(new_count4, 4);
     Serial.println(new_countgas, 4);
     Serial.println(new_countwater, 4);
     prior_count1 = new_count1;
     prior_count2 = new_count2;
     prior_count3 = new_count3;
     prior_count4 = new_count4;
     prior_countgas = new_countgas;
     prior_countwater = new_countwater;
  }
  // отправляет обновление в сеть
  if ((new_count1 > 0 && ((millis() - lastTime) > timerDelay)) ||
   (new_count2 > 0 && ((millis() - lastTime) > timerDelay)) ||
    (new_count3 > 0 && ((millis() - lastTime) > timerDelay)) ||
     (new_count4 > 0 && ((millis() - lastTime) > timerDelay)) ||
      (new_countgas > 0 && ((millis() - lastTime) > timerDelay)) ||
       (new_countwater > 0 && ((millis() - lastTime) > timerDelay))) {
  {
      // проверяет, подключен ли Wi-Fi.
      if (WiFi.status()== WL_CONNECTED) {
        HTTPClient http;
        // подготовка HTTP GET запроса.
         String serverPath = serverName + "?chip_id=" + chipId + "&count1=" + new_count1 + "&count2=" + new_count2 + "&count3=" +
         new_count3 + "&count4=" + new_count4 + "&countgas=" + new_countgas + "&countwater=" + new_countwater;
        // Ваше доменное имя с URL-адресом или IP-адрес с путем.
        http.begin(serverPath.c_str());
        // Отправляем запрос HTTP GET.
        int httpResponseCode = http.GET();
        // подтверждает приход ответа от сервера или отправляет ошибку.
        if (httpResponseCode>0) {
          count1 = 0;
          count2 = 0;
          count3 = 0;
          count4 = 0;
          countgas = 0;
          countwater = 0;
          payloadpulse = http.getString();
          Serial.println(payloadpulse);
         }
         else {
          Serial.print("Error code: ");
          Serial.println(httpResponseCode);
         }
        // закрывает HTTP-соединение.
        http.end();
      }
      else {
       Serial.println("WiFi Disconnected");
      }  
    }
  }
  
  //сброс таймера после отправки данных
  if (((millis() - lastTime) > timerDelay)) {
    lastTime = millis();
  }
}

Программа представляет собой счетчик импульсов, который должен прибавлять 0,001 импульса каждый раз, когда он его обнаруживает. Я ожидаю, что он отправит на сервер 0,006, но вместо этого он отправляет 0,01. Как убедиться, что он не отправляет округленные данные?

, 👍1

Обсуждение

Он может быть округлен путем преобразования числа с плавающей запятой в строку. Вы можете использовать что-то вроде: String(someFloat, 3). Также вы должны помнить, что существуют ограничения для чисел с плавающей запятой, но в этом случае все должно быть в порядке. Неявно десятичные точки — это только 2 знака: String(double, unsigned char decimalPlaces=2);, @KIIV

@KIIV: это должен быть ответ., @Edgar Bonet

Здесь слишком много объектов String, которые тяжеловесны и недружественны для памяти Arduino. guifactor1 и др. должно быть int или float. counter1 и др. должно быть int равным ±1, которое вы добавляете к счетчикам: void pulse1() { count1 += increment1; }., @Edgar Bonet

@EdgarBonet это не весь мой код, например, guifactor представляет собой строку, потому что я сохраняю ее в spiffs, @Jay van de Wetering

Запускается ли этот код на NodeMCU (или другой плате на базе ESP8266 или ESP32)? Если это так, вы можете использовать функцию printf, т.е. Serial.printf("%.5f", someFloat); где "5" - это количество цифр, которое вам нужно после запятой. Формат printf описан [здесь] (https://alvinalexander.com/programming/printf-format-cheat-sheet/)., @StarCat


1 ответ


Лучший ответ:

3

Конструктор объекта String из float выглядит следующим образом:

String(double, unsigned char decimalPlaces=2);

Поэтому, если вы не хотите иметь две десятичные цифры, вам нужно использовать String(someFloat, 3).

Также вы должны помнить, что существуют ограничения для чисел с плавающей запятой, но в данном случае это не так.

И, как упоминал Эдгар, объекты String немного опасны, если ими злоупотреблять, особенно построение serverPath — худший способ, как это сделать (каждый его уровень создает новый временный объект, который будет скопирован в следующий больший и освобожден) .

Было бы дешевле сделать так:

String serverPath;
serverPath.reserve(100); // зарезервировать место, чтобы не изменять размер; должна быть правильная оценка
serverPath += serverName;
serverPath += "?chip_id=";  // на AVR это должно быть F()
serverPath += chipId;
serverPath += "&count1=";
serverPath += new_count1;
serverPath += "&count2=";
serverPath += new_count2;
serverPath += "&count3=";
serverPath += new_count3;
serverPath += "&count4=";
serverPath += new_count4;
serverPath += "&countgas=";
serverPath += new_countgas;
serverPath += "&countwater=";
serverPath += new_countwater;

или вы можете использовать магию C++:

template <class T> inline String & operator<<(String & out, T const & what) {
    out += what;
    return out;
}

String serverPath;
serverPath.reserve(100); // резервируем место, чтобы не менять размер

serverPath << serverName << "?chip_id=" << chipId << "&count1="
           << new_count1 << "&count2=" << new_count2 << "&count3="
           << new_count3 << "&count4=" << new_count4 << "&countgas="
           << new_countgas << "&countwater=" << new_countwater;

этот код использует serverPath << имя_сервера добавляет имя_сервера в путь_сервера, и в результате снова получается путь_сервера, а затем продолжается как путь serverPath << "?chip_id=" и т. д.

,

спасибо, это работает со строкой (someFloat, 3), @Jay van de Wetering