Помогите реализовать запись числа с точкой

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Andrey19888
Родился
Сообщения: 12
Зарегистрирован: Вс июл 16, 2006 23:52:49

Помогите реализовать запись числа с точкой

Сообщение Andrey19888 »

С Ик пульта вводится число с плавающей точкой. Т.е. для получения числа, например, 0.005 вводится сначала 0, затем точка, затем еще 2 нуля и 5. Посоветуйте как грамотно организовать запись данных в переменную Float
Пишу на СИ CVAVR
Жизнь как рояль: клавиша белая, клавиша черная, крышка
codenamehawk
Вымогатель припоя
Сообщения: 528
Зарегистрирован: Вт фев 09, 2010 17:52:26

Re: Помогите реализовать запись числа с точкой

Сообщение codenamehawk »

В библиотеке stdlib.h
есть функция

float atof(char *str)
converts the characters from string str to floating point.

должна вам помочь.
Andrey19888
Родился
Сообщения: 12
Зарегистрирован: Вс июл 16, 2006 23:52:49

Re: Помогите реализовать запись числа с точкой

Сообщение Andrey19888 »

Спасибо огромное. Попробую. О результате отпишусь :)
Жизнь как рояль: клавиша белая, клавиша черная, крышка
Andrey19888
Родился
Сообщения: 12
Зарегистрирован: Вс июл 16, 2006 23:52:49

Re: Помогите реализовать запись числа с точкой

Сообщение Andrey19888 »

Сделал по совету и столкнулся с проблемой
unsigned char *add = "12.075";
char s[20];


sdf=atof(add);
sprintf(s,"%f",sdf);
lcd_puts(s);

в итоге на экране имеем вместо 12.075 12.074999 :dont_know:
Жизнь как рояль: клавиша белая, клавиша черная, крышка
lix
Опытный кот
Сообщения: 703
Зарегистрирован: Вс янв 17, 2010 15:32:19
Откуда: Курган

Re: Помогите реализовать запись числа с точкой

Сообщение lix »

sprintf(s,"%.3f",sdf);
Andrey19888
Родился
Сообщения: 12
Зарегистрирован: Вс июл 16, 2006 23:52:49

Re: Помогите реализовать запись числа с точкой

Сообщение Andrey19888 »

Спасибо. Заработало. Единственный момент, что в переменной sdf по прежнему остается неточное значение, а мне с ней нужно будет работать. Как там можно поправить?
Жизнь как рояль: клавиша белая, клавиша черная, крышка
codenamehawk
Вымогатель припоя
Сообщения: 528
Зарегистрирован: Вт фев 09, 2010 17:52:26

Re: Помогите реализовать запись числа с точкой

Сообщение codenamehawk »

Andrey19888 писал(а):Сделал по совету и столкнулся с проблемой
unsigned char *add = "12.075";
char s[20];


sdf=atof(add);
sprintf(s,"%f",sdf);
lcd_puts(s);

в итоге на экране имеем вместо 12.075 12.074999 :dont_know:


Попробуйте так

Код: Выделить всё

unsigned char add[7] = "12.075";
unsigned char s[20];
float sdf;

Код: Выделить всё

sdf=atof(add);
sprintf(s,"%f",sdf);
Andrey19888
Родился
Сообщения: 12
Зарегистрирован: Вс июл 16, 2006 23:52:49

Re: Помогите реализовать запись числа с точкой

Сообщение Andrey19888 »

Безрезультатно. На экране всеравно 12,074999. Если в sprintf(s,"%.3f",sdf); на экране правильно, но в переменной же всеравно нет :(
Жизнь как рояль: клавиша белая, клавиша черная, крышка
Vov123
Опытный кот
Сообщения: 804
Зарегистрирован: Чт мар 12, 2009 16:31:05

Re: Помогите реализовать запись числа с точкой

Сообщение Vov123 »

Поставь вместо типа данных float double.
Andrey19888
Родился
Сообщения: 12
Зарегистрирован: Вс июл 16, 2006 23:52:49

Re: Помогите реализовать запись числа с точкой

Сообщение Andrey19888 »

Ставил .. не помогает. Я уже неделю борюсь с этой проблемой :(
Жизнь как рояль: клавиша белая, клавиша черная, крышка
codenamehawk
Вымогатель припоя
Сообщения: 528
Зарегистрирован: Вт фев 09, 2010 17:52:26

Re: Помогите реализовать запись числа с точкой

Сообщение codenamehawk »

Andrey19888 писал(а):Безрезультатно. На экране всеравно 12,074999. Если в sprintf(s,"%.3f",sdf); на экране правильно, но в переменной же всеравно нет :(

Это похоже функция sprintf выдает такой результат, а переменная sdf равна 12.075
codenamehawk
Вымогатель припоя
Сообщения: 528
Зарегистрирован: Вт фев 09, 2010 17:52:26

Re: Помогите реализовать запись числа с точкой

Сообщение codenamehawk »

Вывод на экран sprintf(s,"%8.3f",sdf);
Где 8 общее количевство знаков в (s), а 3 количевство знаков после запятой.
Последний раз редактировалось codenamehawk Ср янв 05, 2011 12:59:33, всего редактировалось 1 раз.
Andrey19888
Родился
Сообщения: 12
Зарегистрирован: Вс июл 16, 2006 23:52:49

Re: Помогите реализовать запись числа с точкой

Сообщение Andrey19888 »

Сейчас проведу эксперимент попробую сравнить sdf c числом 12.075.

Вот тут народ тоже пишет про такие проблемы

http://www.avrfreaks.net/index.php?name ... 49&start=0
Жизнь как рояль: клавиша белая, клавиша черная, крышка
codenamehawk
Вымогатель припоя
Сообщения: 528
Зарегистрирован: Вт фев 09, 2010 17:52:26

Re: Помогите реализовать запись числа с точкой

Сообщение codenamehawk »

Посмотрите пример
atmega16.rar
atmega16.prj проект для CV
atmega16_cof.aps для отладки в АВР студио
(100.03 КБ) 151 скачивание


Не забывайте, что если для float попробуете задать число типа 12.0000000075 , оно будет округленно.
Почитайте http://ru.wikipedia.org/wiki/%D0%A7%D0% ... 0%BE%D0%B9
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Помогите реализовать запись числа с точкой

Сообщение ARV »

опять перепетии с float... ну не нужно его применять! поверьте, можно обойтись и без него, а значит, и не иметь всех проблем, с ним связанных: большого объема кода, проблемы округления, медленной скорости расчетов...

вы передаете ряд цифр, среди которых есть точка, положение точки по сути своей определяет множитель (или делитель, что непринципиально), на который надо умножить(разделить) число.
передаете 12.345 - это значит, число 12345 гнадо разделить на 1000
передаете 12.3 - это знсчит, число 123 надо разделить на 10
и т.д.
для хранения числа выбирайте, предположим, long - думаю, вам хватит с запасом на все случаи жизни. итак, принимаете цифры числа, запоминаете число в переменной long, а положение точки задает вам другое число - делитель, для котрого хватит и обычного int, хотя и long можно не пожалеть.

далее корректируете свою математику в программе так, чтобы ВСЕ расчеты велись в принятом формате: отдельно числа, отдельно делители - это просто! вычисляете все действия над числами, результат преобразуете в строку и вставляете в эту строку в нужное место точку: место этой точки определяется элементарными действиями над ДЕЛИТЕЛЯМИ - это тоже несложно, не так ли?

в итоге вы имеете очень компактный и простой код, работающий быстро. все это называется "математика с фиксированной точкой", в которой все действия осуществляются НАД ЦЕЛЫМИ ЧИСЛАМИ. в некоторых случаях можно еще сильнее упростить задачу, если подумать получше...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
codenamehawk
Вымогатель припоя
Сообщения: 528
Зарегистрирован: Вт фев 09, 2010 17:52:26

Re: Помогите реализовать запись числа с точкой

Сообщение codenamehawk »

Если у вас в предложении
ARV писал(а):опять перепетии с float... ну не нужно его применять!

заменить на "при определенных условиях, не стоит применять float", то я ваш совет поддержу.

Но если проц быстрый и места много, почему бы float не применить ?

Трудности при изучении, возникают как правило всегда,
но это не повод отказаться от того, что не получается написать с наскоку.
clawham
Поставщик валерьянки для Кота
Сообщения: 1957
Зарегистрирован: Пт окт 31, 2008 09:38:55
Откуда: Одесса
Контактная информация:

Re: Помогите реализовать запись числа с точкой

Сообщение clawham »

ARV, разрешите тогда Вас ещё одним примером нагрузить...
Делаю миксер для вертолёта - суть в том что входные сигналы - это импульс длительностью от 1000 us до 2000 us (1-2 милисеки) повторяются они 20 рас в секунду...таких каналов в передатчике 6 как и в приёмнике....мне надо сделать так чтоб контроллер захватил один сигнал(общий газ) и потом вывел результат в аппаратный ШИМ (управление двигателями) но...если второй входной сигнал = 1520 нс - то оба канала копируются-тоесть:
вход 1=1000 - на выход 0 0
вход 1=1500 - на выход 256 256
вход 1=2000 - на выход 511 511

теперь второй вход это дизбаланс - если на втором входе меньше 1520 то первый выход уменьшается пропорционально отклонению от нейтрали а второй - увеличивается и наоборот

тоесть так:
вход 1 всегда 1500(для примера)

вход 2=1520 - выходы 256 256
вход 2=1600 - выходы 266 246
вход 2=1400 - выходы 246 266

вот так примерно....но ещё есть другая вещь- степень влияния тоесть когда второй сигнал в нуле то при среднем значении первого канала первый выход равен 0 а второй - максимуму
а бывает надо "затупить" это дело...тоесть уменьшить диапазон влияния в 2 раза в 3 или в 1.78 например(задавать с третего канала

ТАК ВОТ....сейчас я это делаю так:

Код: Выделить всё

unsigned int Mem_Min_Gas = 1000;
unsigned int Mem_Max_Gas = 2000;
unsigned int Mem_Min_Gyro = 1000;
unsigned int Mem_Max_Gyro = 2000;


float TempA = 0;
float TempB = 0;

float Delta_Gas = 0;
float Delta_Gyro = 0;


          //ждём пока вход Газ упадёт в нуль
          while(Gas_in);                   
          //теперь ждём поднятия в 1                           
          //TCCR2=TimOn;
          TCCR2=0x00;                   // таймер глушим
          Timer_ext = 0;                // обнуляем накопитель таймера
          TCNT2 = 0;
          #asm("wdr")                   // обнулили и сам таймер
          while(!Gas_in);
          //запускаем таймер
          TCCR2=TimOn;
          // ждём пока вход Газ упадёт вниз
          while(Gas_in);
          //срочно тормозим таймер
          TCCR2=0x00;
          // расчитываем кол-во отсчетов от нуля
          In_Gas = TCNT2+Timer_ext;
         
          #asm("wdr")           
         
          //ждём пока вход Гиры упадёт в нуль
          while(Gyro_in);                   
          //теперь ждём поднятия в 1                           
          //TCCR2=TimOn;
          TCCR2=0x00;                   // таймер глушим
          Timer_ext = 0;                // обнуляем накопитель таймера
          TCNT2 = 0;                    // обнулили и сам таймер
          while(!Gyro_in);
          //запускаем таймер
          TCCR2=TimOn;
          // ждём пока вход Гyro упадёт вниз
          while(Gyro_in);
          //срочно тормозим таймер
          TCCR2=0x00;           
          // расчитываем кол-во отсчетов от нуля
          In_Gyro = TCNT2+Timer_ext;


            // расчитываем выход газа
            //TempA = (float)(Gas_in-Mem_Min_Gas)/(Mem_Max_Gas-Mem_Min_Gas)*0x03ff;
            TempA = (float)(In_Gas);
            TempA = TempA - (float)(Mem_Min_Gas);
            Delta_Gas = Mem_Max_Gas;
            Delta_Gas-= Mem_Min_Gas;
            TempA = TempA/Delta_Gas;
            TempA = TempA * 500.0;
                       
            // расчитываем выход гиры
            //TempA = (float)(Gas_in-Mem_Min_Gas)/(Mem_Max_Gas-Mem_Min_Gas)*0x03ff;
            TempB = (float)(In_Gyro);
            TempB = TempB - (float)(Mem_Min_Gyro);
            Delta_Gyro = Mem_Max_Gyro;
            Delta_Gyro-= Mem_Min_Gyro;
            TempB = TempB/Delta_Gyro;
            TempB = TempB * 500.0;
           
            Delta_Gyro = (TempB-Gyro_Centr)/2;
           
            TempB = TempA;
            TempA = TempB+Delta_Gyro;
            TempB = TempB-Delta_Gyro;
           
            if(TempA<0)
                TempA = 0;
            if(TempA>510)
                TempA = 510;
            if(TempB<0)
                TempB = 0;
            if(TempB>510)
                TempB = 510;
           
            OCR1A = TempA;
            OCR1B = TempB;



суть работы - таймер считает микросекунды и в переменных In_Gyro и Gas_in появляются значения длительности импульса в микросекундах...

здесь я затупил влияние разбалансового второгосигнала(гироскопа) в два раза...а хочется взять третий канал и с пульта на лету это дело корректировать...а ещё внести Экспоненту но это потом....
так вот....как бы это всё можно было б упростить....получается малая дискретность того флоата что расчитывается в строке

Код: Выделить всё

TempA = TempA/Delta_Gas;
TempA = TempA * 500.0;


ведь мы приводим его к диапазону 0...1 а потом умножаем на нужный мне выходной диапазон(для PWM регистра)

при этом значения минимума, максимума и среднего положения длительности сигнала калибруется/меняется/расчитывается при включении(например разбалансный центр может быть не 1520 как опложено а 1401, а минимум не 1000 а 983, а максимум не 2000 а 1973)
Что нас не убило сделало нас осторожней
Не доверяйте русским лужам - это может быть вход в метро.
Andrey19888
Родился
Сообщения: 12
Зарегистрирован: Вс июл 16, 2006 23:52:49

Re: Помогите реализовать запись числа с точкой

Сообщение Andrey19888 »

codenamehawk писал(а):
Andrey19888 писал(а):Безрезультатно. На экране всеравно 12,074999. Если в sprintf(s,"%.3f",sdf); на экране правильно, но в переменной же всеравно нет :(

Это похоже функция sprintf выдает такой результат, а переменная sdf равна 12.075



Как не парадоксально, но вот что я сделал
float sdf=0.0;
unsigned char *add = "12.075";

sdf=atof(add);
if (sdf==12.075){
lcd_putsf("ok");
};


И на дисплей вывелось ОК ...т.е. получается что ф-я sprintf не корректно отрабатывает.


ARV у меня уже были попытки реализации по вашему алгоритму, но у меня вводится может как оч маленькое число 0.005 например так и 135.26. И тогда представлять становится довольно сложно, темболее ввод идет по 1 цифре с пульта
Жизнь как рояль: клавиша белая, клавиша черная, крышка
codenamehawk
Вымогатель припоя
Сообщения: 528
Зарегистрирован: Вт фев 09, 2010 17:52:26

Re: Помогите реализовать запись числа с точкой

Сообщение codenamehawk »

Примените sprintf(s,"%8.3f",sdf); :)))
Andrey19888
Родился
Сообщения: 12
Зарегистрирован: Вс июл 16, 2006 23:52:49

Re: Помогите реализовать запись числа с точкой

Сообщение Andrey19888 »

С выводом я уже разобрался. Волновала только проблема что в переменной хранится не правильное число. Но эксперимент показал что функция sprintf не корректно отрабатывает и приходится округлять
Жизнь как рояль: клавиша белая, клавиша черная, крышка
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»