Отображение чисел с плавающей запятой на ЖК-дисплее

Как получить переменную volts для отображения чисел с плавающей запятой на ЖК-дисплее?

ЖК-дисплей отображает только значения с плавающей запятой с большим количеством десятичных знаков с E в конце. Мне нужно только 2 десятичных знака, так как мне это отобразить?

int main (void){

    adcinit();

    lcd_init();//initializes LCD
    lcd_clear();//clear screen
    lcd_home();


    uint16_t value;
    float volts;
    while(1){
        ADCSRA |= (1<<ADSC);//start ADC conversion
        delay_ms(54);//delay 54 millisecond
        value = ADCW;//assign ADC conversion to value
        volts=(value*5)/1023;
        lcd_goto_xy(0,0);// coordinates of the cursor on LCD Display
        lcd_printf("ADC Value: %d ",value);//display on LCD
        lcd_goto_xy(0,1);// coordinates of the cursor on LCD Display
        lcd_printf("Volts: %f ",volts);//display on LCD
    }
}

person user7187418    schedule 21.11.2016    source источник
comment
Что он отображает?   -  person user253751    schedule 21.11.2016
comment
Здесь есть проблема volts=(value*5)/1023. Все это целые числа, поэтому результатом вычисления будет целое число. Это, вероятно, не то, что вы хотите. Попробуйте использовать volts = (value * 5f) / 1023f.   -  person clstrfsck    schedule 21.11.2016
comment
Или рассмотрите возможность отображения милливольт: unsigned volts=(value*5000L + 1024/2 /* add this value to round */)/1024; и избегайте математики FP.   -  person chux - Reinstate Monica    schedule 21.11.2016
comment
с приведенным выше кодом он отображает, volts: 1.00000E0 на ЖК-дисплее.   -  person user7187418    schedule 21.11.2016
comment
chux, когда вы говорите /* округлить это значение */, вы имеете в виду, например, для 2 знаков после запятой: unsignedvolts(value*5000L+1024/2*100)/1024; ?   -  person user7187418    schedule 21.11.2016
comment
все зависит от функции lcd_printf, которая, вероятно/возможно, предоставляется какой-то секретной библиотекой. Подробности смотрите там.   -  person datafiddler    schedule 21.11.2016
comment
почему номер 1023? Кажется странным   -  person Jacek Cz    schedule 21.11.2016
comment
используйте "Volts: %.2f " в качестве строки формата, так как .2 заставляет использовать только две десятичные цифры после запятой.   -  person Luis Colorado    schedule 23.11.2016


Ответы (3)


Если функция lcd_printf() основана на той же библиотеке, что и функция sprintf() для Arduino, спецификатор формата '%f' плохо управляется даже при использовании в качестве '%.2f'.

Шаг 1: Прежде чем предлагать альтернативные решения, необходимо получить хорошо рассчитанное значение с плавающей запятой из числового значения, считанного с аналого-цифрового преобразователя.

Если АЦП является 10-разрядным, диапазон должен быть 1024 (вместо 1023).

value = ADCW;//assign ADC conversion to value
volts=((float)value*5.0f)/(1024.0f); 

Шаг 2.1. Первое и быстрое решение для отображения 2-значного фиксированного числа с плавающей запятой — преобразовать его в 2 целых числа.

lcd_printf("Volts: %d.%02d ",(int)volts, (int)(volts*100)%100));//display on LCD

Вместо

lcd_printf("Volts: %.2f ",volts);//display on LCD

Шаг 2.2. Более «официальное» решение для отображения фиксированного значения с плавающей запятой с двумя десятичными знаками — использовать функцию dtostrf(), предложенную в "Arduino sprintf float не форматирует".

char str_volts[15]; // to store the float-to-string converted value
lcd_printf("Volts: %s ",dtostrf(volts, 4, 2, str_volts));//display on LCD
// 4 = minimum number of char ('X.XX'), 2 = number of decimals

Вместо

lcd_printf("Volts: %.2f ",volts);//display on LCD
person J. Piquard    schedule 21.11.2016

Я отвечаю на вопрос в ПОСЛЕДНЕМ предложении исходного поста, а не в заголовке. Но это правильный ответ для вашего проекта.

Вы говорите: «Мне нужно только 2 десятичных знака» — так что это должно сказать вам, что нет необходимости в математике с плавающей запятой. Физикам и инженерам нужны числа с плавающей запятой для представления очень, очень маленьких или очень, очень больших величин, но вам нужна «фиксированная точка», что означает выполнение целочисленной математики и правильный выбор единиц измерения. Фиксированная точка быстрее, точнее и уменьшает размер вашего скомпилированного двоичного файла, поскольку нет необходимости в коде с плавающей запятой.

Самое простое решение — использовать целые числа и отображать милливольты, точно так же, как функция delay(), которую вы только что использовали, принимает в качестве аргумента целое число миллисекунд, а не дробное число секунд.

#define VREF 5000
uint32_t mvolts;
.
.
mvolts=(value*VREF)>>10; // No floats here...
lcd_printf("milliVolts: %d",mvolts); // ...and no casts

Если вы должны отображать вольты, то это поможет:

lcd_printf("Volts: %d.%02d ",mvolts/1000, (mvolts%1000)/10);

Заметьте, кстати, что mvolts — это 32-битное целое число, потому что сейчас вы умножаете 10-битное число на 5000, а это не укладывается в 16-битное число. Это необходимо, потому что вам нужно сохранить точность значения при масштабировании. Я не думаю, что это заголовок не по теме, так как я полагаю, что вы хотите отображать правильное значение или нет смысла отображать эти два десятичных знака.

Если вы не будете осторожны, компилятор вычислит значение 5000/1024 — 4,8828125, а затем выполнит целочисленную арифметику, которая отсекает дробную часть и в итоге умножает результат АЦП на 4. Чтобы гарантировать правильное поведение, умножьте на 5000 потом разделить - 2 отдельные операции. Поскольку 1024 равно 2**10, сдвиг вправо на десять битов идентичен делению на 1024.

Наконец, не думайте, что чтение 1023 из АЦП на самом деле означает 5000 вольт с 4 значащими цифрами; откалибруйте проверенный вольтметр, изменив #define VREF, чтобы получить правильный результат.

person Peter Lister    schedule 22.11.2016
comment
Только что отредактировав мой ответ, мне просто пришло в голову, что ваша причина думать, что вам вообще нужны поплавки, может заключаться в представлении коэффициента масштабирования. Это так?chux и msandiford прокомментировали выше одни и те же проблемы - я просто более подробно объясняю, что происходит. - person Peter Lister; 22.11.2016
comment
если вам нужны только центы вольта, вам нужно разделить последнее выражение, если вызов lcd_printf() на десять, чтобы получить правильный результат, как mvolts % 1000 / 10 - person Luis Colorado; 23.11.2016
comment
Луис: Хороший улов, я склонен думать в mV. - person Peter Lister; 25.11.2016

Попробуй это:

Редактировать: я только что отредактировал отображение напряжения, потому что значение было целым. Но принцип был бы таким же.

int main (void){

    adcinit();

    lcd_init();//initializes LCD
    lcd_clear();//clear screen
    lcd_home();


    uint16_t value;
    float volts;
    while(1){
        ADCSRA |= (1<<ADSC);//start ADC conversion
        delay_ms(54);//delay 54 millisecond
        value = ADCW;//assign ADC conversion to value
        volts=(float)(value*5)/1023;
        lcd_goto_xy(0,0);// coordinates of the cursor on LCD Display
        lcd_printf("ADC Value: %d ",value);//display on LCD
        lcd_goto_xy(0,1);// coordinates of the cursor on LCD Display
        lcd_printf("Volts: %.2f ",volts);//display on LCD
    }
}
person someRandomSerbianGuy    schedule 21.11.2016
comment
кастинг кажется неправильным или, по крайней мере, непонятным для тех, кто читает этот код. Обычно это вольт=(значение*5.0)/1023; (не обсуждайте здесь 1023 г.) - person Jacek Cz; 21.11.2016
comment
Приведение относится к левой стороне деления, поэтому оно кажется правильным, даже если оно излишне сбивает читателя с толку. - person Nisse Engström; 21.03.2017