Ограничить количество знаков после запятой во float

AndreySaf

✩✩✩✩✩✩✩
22 Сен 2020
7
0
Столкнулся с проблемой ограничения символов во float переменной (я новичок =))
Вот скетч:
C++:
#define measureCntMax 5                  // Количество необходимых измерений температуры для вычисления среднего значения
#include <OneWire.h>                     //Библиотека для работы с протоколом 1-Wire
#include <DallasTemperature.h>           //Библиотека для работы с датчиком DS18B20
#include <LiquidCrystal_I2C.h>           // Библиотека для работы с дисплеем LED 2004
LiquidCrystal_I2C lcd(0x27,20,4);        // Инициалируем дисплей
#define ONE_WIRE_BUS 6                   //Сигнальный провод DS18B20
OneWire oneWire(ONE_WIRE_BUS);           //Создаём объект для работы с библиотекой OneWire
DallasTemperature sensor(&oneWire);      //Создаём объект для работы с библиотекой DallasTemperature
float temperature;                       //Переменная для хранения значения температуры
int measureCnt = 0;                      //Счетчик произведенных измерений температуры
float tempMiddle = 100;                  //Для хранения усредненного значения температуры
float tempMiddleCnt = 0;                 //Хранилище для вычислений усредненного значения


void setup() {
  //Датчик температуры
  pinMode(ONE_WIRE_BUS, INPUT);
  //Дисплей
  lcd.init();                       //  Инициируем работу с LCD дисплеем
  lcd.backlight();                  //  Включаем подсветку LCD дисплея
 

  //Тепература
  sensor.begin();              //Инициализация работы датчика DS18B20
  sensor.setResolution(12);    //Устанавливаем разрешение датчика от 9 до 12 бит
 
  Serial.begin(9600);
}

void loop() {
  if(millis() % 1000 == 0) {
  //Температура
  sensor.requestTemperatures();                  //отправляем запрос на измерение температуры
  temperature = sensor.getTempCByIndex(0);       //считываем данные из регистра датчика и записываем в переменную
  measureCnt++;
  tempMiddleCnt = tempMiddleCnt + temperature;
    if(measureCnt == measureCntMax) {
      tempMiddle = tempMiddleCnt/measureCntMax;  // Вычисляем среднее значение температуры
      measureCnt = 0;
      tempMiddleCnt = 0;
    }
 
  // выводим температуру в Serial-порт
  Serial.print("Усредненное значение температуры C: ");
  Serial.println(tempMiddle);
 
  // Вывод на дисплей
  lcd.setCursor(0, 0);      //  Устанавливаем курсор
  lcd.print("Temp C: ");       // Выводим температуру
  lcd.print(tempMiddle);
  }
}
Суть такова: считываем значение температуры с датчика 5 раз и вычисляем среднее значение.
Ключевая переменная float tempMiddle. С ней я буду работать и ее надо вывести на дисплей и в Serial-порт
В Serial-порте выглядит так: 23.62
На дисплее LCD 2004 так: 23.620 (почему-то 0 в конце дописывает)
Нужно сделать число 23.6, помогите пожалуйста решить задачу!
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,302
Москва
Такой экран имеет свойство сохранять незатертые значения. Если вставить после после 50 строки
lcd.print(" "); то проблема с лишним нулем спрячется, но не уйдет совсем. Т.к. при другом кол-ве символов в температуре (когда она меньше 10 градусов) может потребоваться 2 пробела.
Что бы навсегда избавиться смотрите функции форматирования строки типа snprintf или format
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,407
976
58
Марий-Эл
А можно перед выводом значения затереть строку пробелами. Если число максимально 5 знаков, то выводишь 5 пробелов, возвращаешься и пишешь новое значение.
 

kostyamat

★★★★★★✩
29 Окт 2019
1,098
632
Что бы навсегда избавиться смотрите функции форматирования строки типа snprintf или format
Оно то хорошо, но. Вы интересовались когда либо, сколько весит в компилированом виде вот эта sprintf? Для есп куда не шло, но для 328-го перебор имхо.
 

AndreySaf

✩✩✩✩✩✩✩
22 Сен 2020
7
0
Я бы рад освоить все методы, но пока я в начале пути. Спасибо, что есть люди готовые помочь!
 

Wan-Derer

★★★★★✩✩
Команда форума
31 Июл 2018
2,132
412
Москва
wan-derer.ru
@AndreySaf, умножает температуру на 10 и переводишь float в int. Все вычисления делаешь в int. Результат переводишь во float и делишь на 10 (ну или просто выводить как n/10, точка, n%10).
Это называется "вычисления с фиксированной точкой" (в отличие от float - с плавающей). Работает быстро, память не жрёт, рекомендуется для слабых процессоров.
 
  • Лойс +1
Реакции: AndreySaf

poty

★★★★★★✩
19 Фев 2020
3,230
940
Короче, самый простой вариант, до момента, когда разберётесь с предложениями (послушайте @Wan-Derer, дело говорит!) заменить в функциях Serial.println и lcd.print переменную tempMiddle на
((float)((int)(tempMiddle * 10)))/10
 
  • Лойс +1
Реакции: AndreySaf

Александр Симонов

★★★★✩✩✩
2 Авг 2018
727
208
Есть лёгкий упрощенный вариант sprintf для вещественных чисел -- dtostrf

Но он на самом деле и не нужен. У дисплея есть метод .print(float, int), который обрежет дробную часть до указанного колва цифр. Такой же, как у Serial
1605289367388.png
 

AndreySaf

✩✩✩✩✩✩✩
22 Сен 2020
7
0
Написал так:
C++:
lcd.print(((float)((int)(tempMiddle * 10)))/10, 1);
Показывает значение 23.6, как и надо. Это наверно самый простой способ :giggle:
 

poty

★★★★★★✩
19 Фев 2020
3,230
940
Мне кажется, тут перебор. :)Либо воспользоваться решением Александра Симонова, либо моим. Объединять большого смысла нет.
 

bort707

★★★★★★✩
21 Сен 2020
3,056
910
C++:
lcd.print(((float)((int)(tempMiddle * 10)))/10, 1);
Это наверно самый простой способ
@AndreySaf,, вы нифига не поняли совет @Wan-Derer. Когда он писал про то, что переменную надо домножить на 10 и перевести в int - это нужно делать не перед выводом в принт, а во всей программе, чтобы совсем отказаться от флоат.
А ваша строчка, что я процитировал выше - это абсолютная бессмыслица, если во всей остальной программе у вас переменная tempMiddle остается float.
Захотите поспорить - попробуйте обосновать, нафига вы тут ее сначала умножаете на 10, переводите в инт, потом обратно делите и приводите во флоат...
Эту строчку можно заменить вот этой - куда короче и понятнее
C++:
lcd.print(tempMiddle, 1);
сравните сколько у вас лишнего в строке наворочено
 
Изменено:

poty

★★★★★★✩
19 Фев 2020
3,230
940
@bort707, если памяти и времени хватает, заморачиваться с переводом в int смысла нет. Совет @Wan-Derer хорошо применять в сложных скетчах, вряд ли пока автор на такие замахивается.
Метод @AndreySaf хорош, тут возразить нечего, однако он требует поддержки со стороны того класса С++, в котором применяется. В данном случае - повезло, однако, я посмотрел на способ округления, применённый в Print.h, там он универсальнее, понятно, но затраты на него сильно превышают простое преобразование типов.
И - да, я отметил, что лучше применять один из предложенных способов.
Так что короче и понятнее - не значит эффективнее.
 

AndreySaf

✩✩✩✩✩✩✩
22 Сен 2020
7
0
Записал в loop так:
C++:
tempMiddle = ((float)((int)(tempMiddleCnt/measureCntMax * 10)))/10;                             // Вычисляем среднее значение температуры
Т.е. конвертируется сразу в int при вычислении
Если записать так:
C++:
tempMiddle = ((int)(tempMiddleCnt/measureCntMax * 10))/10;                             // Вычисляем среднее значение температуры
то округляется до целого числа и дробная часть не выводится.
 

AndreySaf

✩✩✩✩✩✩✩
22 Сен 2020
7
0
А вот так красивее и выводится как надо, с дробью
C++:
tempMiddle = ((int)(tempMiddleCnt/measureCntMax * 10))/10.f;
 

AndreySaf

✩✩✩✩✩✩✩
22 Сен 2020
7
0
@AndreySaf,
чем вас вот этот вариант не устраивает?
C++:
lcd.print(tempMiddle, 1);
Если не перевести float в int, т.е. написать так:
C++:
tempMiddle = tempMiddleCnt/measureCntMax;
а не так:
C++:
tempMiddle = ((int)(tempMiddleCnt/measureCntMax * 10))/10.f;
То на дисплее в конце добавляется 0
 

bort707

★★★★★★✩
21 Сен 2020
3,056
910
тогда вся ваша красота с умножениями, делениями и переводом во флоат лишняя
 
  • Лойс +1
Реакции: kostyamat

poty

★★★★★★✩
19 Фев 2020
3,230
940
Думаю проще привести идею @Wan-Derer, в реализованном варианте, иначе Вас сейчас запутают окончательно:
Оптимизация кода:
#include <OneWire.h>                      //Библиотека для работы с протоколом 1-Wire
#include <DallasTemperature.h>            //Библиотека для работы с датчиком DS18B20
#include <LiquidCrystal_I2C.h>            //Библиотека для работы с дисплеем LED 2004

#define ONE_WIRE_BUS 6                    //Сигнальный провод DS18B20
#define measureCntMax 5                   //Количество необходимых измерений температуры для вычисления среднего значения

LiquidCrystal_I2C lcd(0x27,20,4);         //Инициалируем дисплей
OneWire oneWire(ONE_WIRE_BUS);            //Создаём объект для работы с библиотекой OneWire
DallasTemperature sensor(&oneWire);       //Создаём объект для работы с библиотекой DallasTemperature

int measureCnt = 0;                       //Счетчик произведенных измерений температуры
int tempMiddle = 0;                       //Для хранения усредненного значения температуры

void setup() {
  pinMode(ONE_WIRE_BUS, INPUT);           //Датчик температуры
  sensor.begin();                         //Инициализация работы датчика температуры DS18B20
  sensor.setResolution(12);               //Устанавливаем разрешение датчика от 9 до 12 бит
 
  lcd.init();                             //Инициируем работу с LCD дисплеем
  lcd.backlight();                        //Включаем подсветку LCD дисплея
 
  Serial.begin(9600);
}

void loop() {
  if(millis() % 1000 == 0) {
    sensor.requestTemperatures();         //Отправляем запрос на измерение температуры
                                          //Считываем данные из регистра датчика и записываем в переменную
    tempMiddle += 10 * (sensor.getTempCByIndex(0)+0.05);
    measureCnt++;
 
    if(measureCnt == measureCntMax) {
      tempMiddle /= measureCntMax;        //Вычисляем среднее значение температуры
                                          //Выводим температуру в Serial-порт
      Serial.print("Усредненное значение температуры C: ");
      Serial.println(tempMiddle/10.f);
                                          //Вывод на дисплей
      lcd.setCursor(0, 0);                //Устанавливаем курсор
      lcd.print("Temp C: ");              //Выводим температуру
      lcd.print(tempMiddle/10.f);
      measureCnt = 0;
      tempMiddle = 0;
    }
  }
}
 

olegkyka

✩✩✩✩✩✩✩
25 Июл 2019
5
1
А, с этим скетчем не подмогнете? Делаю вроде по аналогии, а выводит все равно два знака после запятой.

C++:
#include <ESP8266WebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Шина данных подключена к выводу D4 на ESP8266
#define ONE_WIRE_BUS D4
// Настройка объекта oneWire для связи с любыми устройствами OneWire
OneWire oneWire(ONE_WIRE_BUS);
// Передаем ссылку на объект oneWire объекту Dallas Temperature.
DallasTemperature sensors(&oneWire);

int tempSensor1;

uint8_t sensor1[10] = { 0x28, 0x72, 0xB2, 0x79, 0x97, 0x19, 0x03, 0xF1  };

/* Введите SSID и пароль от вашей сети*/
const char* ssid = ".......";   // SSID
const char* password = "......";  // пароль

ESP8266WebServer server(80);            
void setup()
{
  Serial.begin(115200);
  delay(100);
  sensors.begin();            
  Serial.println("Connecting to ");
  Serial.println(ssid);
  // подключиться к вашей локальной wi-fi сети
  WiFi.begin(ssid, password);
  // проверить, выполнено ли подключение wi-fi сети
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected..!");
  Serial.print("Got IP: ");  Serial.println(WiFi.localIP());
  server.on("/", handle_OnConnect);
  server.onNotFound(handle_NotFound);
  server.begin();
  Serial.println("HTTP server started");
}

void loop()
{
  server.handleClient();
}

void handle_OnConnect()
{
  sensors.requestTemperatures();
  tempSensor1 = (sensors.getTempC(sensor1)+0.05)*10; // Получить значение температуры
  server.send(200, "text/html", SendHTML());
}

void handle_NotFound()
{
  server.send(404, "text/plain", "Not found");
}

String SendHTML()
{
  String ptr =
"<!DOCTYPE html>"
"<html>"
"<head>"
"<title>ESP8266 Temperature Monitor</title>"
"<meta name='viewport' content='width=device-width, initial-scale=1.0'>"
"<link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600' rel='stylesheet'>"
"<style>"
"html { font-family: 'Open Sans', sans-serif; display: block; margin: 0px auto; text-align: center;color: #444444;}"
"body{margin-top: 50px;}"
"h1 {margin: 50px auto 30px;}"
".side-by-side{display: table-cell;vertical-align: middle;position: relative;}"
".text{font-weight: 600;font-size: 19px;width: 200px;}"
".temperature{font-weight: 300;font-size: 50px;padding-right: 15px;}"
".living-room .temperature{color: #3B97D3;}"
".superscript{font-size: 17px;font-weight: 600;position: absolute;right: -5px;top: 15px;}"
".data{padding: 10px;}"
".container{display: table;margin: 0 auto;}"
".icon{width:82px}"
"</style>"
"<script>\n"
"setInterval(loadDoc,1000);\n"
"function loadDoc() {\n"
"var xhttp = new XMLHttpRequest();\n"
"xhttp.onreadystatechange = function() {\n"
"if (this.readyState == 4 && this.status == 200) {\n"
"document.body.innerHTML =this.responseText}\n"
"};\n"
"xhttp.open(\"GET\", \"/\", true);\n"
"xhttp.send();\n"
"}\n"
"</script>\n"
"</head>"
"<body>"
"<h1>ESP8266 Temperature Monitor</h1>"
"<div class='container'>"
"<div class='data living-room'>"
"<div class='side-by-side icon'>"
"<svg enable-background='new 0 0 65.178 45.699'height=45.699px id=Layer_1 version=1.1 viewBox='0 0 65.178 45.699'width=65.178px x=0px xml:space=preserve xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink y=0px><polygon fill=#3B97D3 points='8.969,44.261 8.969,16.469 7.469,16.469 7.469,44.261 1.469,44.261 1.469,45.699 14.906,45.699 "
"14.906,44.261 '/><polygon fill=#3B97D3 points='13.438,0 3,0 0,14.938 16.438,14.938 '/><polygon fill=#3B97D3 points='29.927,45.699 26.261,45.699 26.261,41.156 32.927,41.156 '/><polygon fill=#3B97D3 points='58.572,45.699 62.239,45.699 62.239,41.156 55.572,41.156 '/><path d='M61.521,17.344c-2.021,0-3.656,1.637-3.656,3.656v14.199H30.594V21c0-2.02-1.638-3.656-3.656-3.656"
"c-2.02,0-3.657,1.636-3.657,3.656v14.938c0,2.021,1.637,3.655,3.656,3.655H61.52c2.02,0,3.655-1.637,3.655-3.655V21"
"C65.177,18.98,63.54,17.344,61.521,17.344z'fill=#3B97D3 /><g><path d='M32.052,30.042c0,2.02,1.637,3.656,3.656,3.656h16.688c2.019,0,3.656-1.638,3.656-3.656v-3.844h-24"
"L32.052,30.042L32.052,30.042z'fill=#3B97D3 /><path d='M52.396,6.781H35.709c-2.02,0-3.656,1.637-3.656,3.656v14.344h24V10.438"
"C56.053,8.418,54.415,6.781,52.396,6.781z'fill=#3B97D3 /></g></svg>"
"</div>"
"<div class='side-by-side text'>Living Room</div>"
"<div class='side-by-side temperature'>";
ptr += (tempSensor1/10.f);
ptr += "<span class='superscript'>&deg;C</span></div>"
"</div>"
"</body>"
"</html>";
  return ptr;
}
Screenshot_1.jpg
 
Изменено:

bort707

★★★★★★✩
21 Сен 2020
3,056
910
Выложите код нормально, без левого форматирования. Что у вас за ATTACH в 11 строке?
В какой строке вы выводите значение? Или надо догадаться?