dtostrf() STM32 проблема

Samodelkin_YouTube
Offline
Зарегистрирован: 16.12.2018

Всем привет. Помогите устранить проблему. Есть значение с датчика температуры "123.45", хочу получить целое число "123".

Использую  dtostrf().

В результате в порту получаю значение "123.0" Такая беда только с платами STM32F103. Когда загружаю скетч в ProMini все ОК получаю "123".

В чем может быть проблема?

char temp = 123.56;

void setup() {
  Serial.begin(9600);
}

void loop() {
  char temp_serial[20];
  dtostrf( temp , 3, 0, temp_serial);
  Serial.println (temp_serial);
}

 

nik182
Offline
Зарегистрирован: 04.05.2015

Может быть потому что char дробным не бывает?

sadman41
Offline
Зарегистрирован: 19.10.2016

Видимо, внутри STM32 framework первый аргумент обрабатывается иначе, нежели внутри AVR libc.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Serial.println(int(temp));

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Komandir пишет:

Serial.println(int(temp));

Это так не работает.  Это никак не работает, у него temp типа char. 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Думаю это машинально написано.

Samodelkin_YouTube
Offline
Зарегистрирован: 16.12.2018

Я хочу вывести значение на экране, использую библиотеку U8g2. Значение нужно выводить целым числом. Я не знаю как,  возможно есть какие-то другие методы.

Пробовал использовать sprintf() но могу понять как оно работает.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

char temp = 123.56; это не число !!!

float temp = 123.56; это число !!!

float temp=123.56;

void setup () {
   Serial.begin(9600);
   Serial.println("Start");
   Serial.println(temp);
   Serial.println(int(temp));
}

void loop() {
}
Start
123.56
123
 
Samodelkin_YouTube
Offline
Зарегистрирован: 16.12.2018

Извините перепутал.

Но когда даже float temp = 123.56;

То в консоли получаем "123.0"

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Вы слепой ?

Samodelkin_YouTube
Offline
Зарегистрирован: 16.12.2018

Вы не поняли проблему. Меня интересует функция dtostrf(). Для отображения данных на дисплее требуется тип данных char Поэтому я использую dtostrf().

float temp = 123.56;

void setup() {
  Serial.begin(9600);
}

void loop() {
  char temp_serial[20];
  dtostrf( temp , 3, 0, temp_serial);
  Serial.println (temp_serial);
}

 В консоле  "124.0"

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Samodelkin_YouTube пишет:

...хочу получить целое число...

может вы задачу не правильно описали ?

Samodelkin_YouTube
Offline
Зарегистрирован: 16.12.2018

все просто и понятно))

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018
float temp=123.56;


void setup () {
   char str[20];
   Serial.begin(9600);
   Serial.println("Start");
   Serial.println(temp);
   dtostrf(temp,3,0,str);
   Serial.println(str);
   sprintf(str,"%i",int(temp));
   Serial.println(str);
}

void loop() {
}
Start
123.56
124
123
 
rkit
Offline
Зарегистрирован: 23.11.2016

Serial.printf давно есть, даже на avr.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

rkit ему надо символьное представление числа, а не вывод в serial ...

Samodelkin_YouTube
Offline
Зарегистрирован: 16.12.2018

Спасибо . Все заработало.

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

sprintf(str,"%i",int(temp));

nik182
Offline
Зарегистрирован: 04.05.2015

У int не может быть дробной части. Ты что нибудь про типы данных знаешь? Прочитай учебник. Про типы. Про dtostrf , какой параметр отвечает за количество знаков после запятой у типа float. НЕ int.

b707
Offline
Зарегистрирован: 26.05.2017

код функции из официального ядра STM для ардуино:

char *dtostrf(double val, signed char width, unsigned char prec, char *sout)
{
  //Commented code is the original version
  /*char fmt[20];
  sprintf(fmt, "%%%d.%df", width, prec);
  sprintf(sout, fmt, val);
  return sout;*/

  // Handle negative numbers
  uint8_t negative = 0;
  if (val < 0.0) {
    negative = 1;
    val = -val;
  }

  // Round correctly so that print(1.999, 2) prints as "2.00"
  double rounding = 0.5;
  for (int i = 0; i < prec; ++i) {
    rounding /= 10.0;
  }

  val += rounding;

  // Extract the integer part of the number
  unsigned long int_part = (unsigned long)val;
  double remainder = val - (double)int_part;

  // Extract digits from the remainder
  unsigned long dec_part = 0;
  double decade = 1.0;
  for (int i = 0; i < prec; i++) {
    decade *= 10.0;
  }
  remainder *= decade;
  dec_part = (int)remainder;

  if (negative) {
    sprintf(sout, "-%ld.%0*ld", int_part, prec, dec_part);
  } else {
    sprintf(sout, "%ld.%0*ld", int_part, prec, dec_part);
  }
  // Handle minimum field width of the output string
  // width is signed value, negative for left adjustment.
  // Range -128,127
  char fmt[129] = "";
  unsigned int w = width;
  if (width < 0) {
    negative = 1;
    w = -width;
  } else {
    negative = 0;
  }

  if (strlen(sout) < w) {
    memset(fmt, ' ', 128);
    fmt[w - strlen(sout)] = '\0';
    if (negative == 0) {
      char *tmp = malloc(strlen(sout) + 1);
      strcpy(tmp, sout);
      strcpy(sout, fmt);
      strcat(sout, tmp);
      free(tmp);
    } else {
      // left adjustment
      strcat(sout, fmt);
    }
  }

  return sout;
}

видно что как минимум 1 цифра после запятой будет выведена

Разница между

dtostrf( temp , 3, 0, temp_serial);

и

dtostrf( temp , 3, 1, temp_serial);

только в том, что первая для temp = 123.52 выведет 123.0, а вторая 123.5

Вывод - функция dtostrf() предназначена для печати float - то есть чисел со знаками после точки. Если вам нужно печатать целое - то сначала переведите свое число в целое, а потом печататйте как целое - через sprintf, itoa и так далее

Samodelkin_YouTube
Offline
Зарегистрирован: 16.12.2018

Ок, спасибо. Я получил ответ на все вопросы.