Страница 1 из 2
Помогите реализовать запись числа с точкой
Добавлено: Вт янв 04, 2011 16:27:52
Andrey19888
С Ик пульта вводится число с плавающей точкой. Т.е. для получения числа, например, 0.005 вводится сначала 0, затем точка, затем еще 2 нуля и 5. Посоветуйте как грамотно организовать запись данных в переменную Float
Пишу на СИ CVAVR
Re: Помогите реализовать запись числа с точкой
Добавлено: Вт янв 04, 2011 17:37:36
codenamehawk
В библиотеке stdlib.h
есть функция
float atof(char *str)
converts the characters from string str to floating point.
должна вам помочь.
Re: Помогите реализовать запись числа с точкой
Добавлено: Вт янв 04, 2011 18:15:18
Andrey19888
Спасибо огромное. Попробую. О результате отпишусь

Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 10:28:14
Andrey19888
Сделал по совету и столкнулся с проблемой
unsigned char *add = "12.075";
char s[20];
sdf=atof(add);
sprintf(s,"%f",sdf);
lcd_puts(s);
в итоге на экране имеем вместо 12.075 12.074999

Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 10:53:03
lix
sprintf(s,"%.3f",sdf);
Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 11:09:47
Andrey19888
Спасибо. Заработало. Единственный момент, что в переменной sdf по прежнему остается неточное значение, а мне с ней нужно будет работать. Как там можно поправить?
Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 12:08:39
codenamehawk
Andrey19888 писал(а):Сделал по совету и столкнулся с проблемой
unsigned char *add = "12.075";
char s[20];
sdf=atof(add);
sprintf(s,"%f",sdf);
lcd_puts(s);
в итоге на экране имеем вместо 12.075 12.074999

Попробуйте так
Код: Выделить всё
unsigned char add[7] = "12.075";
unsigned char s[20];
float sdf;
Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 12:20:46
Andrey19888
Безрезультатно. На экране всеравно 12,074999. Если в sprintf(s,"%.3f",sdf); на экране правильно, но в переменной же всеравно нет

Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 12:47:34
Vov123
Поставь вместо типа данных float double.
Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 12:50:23
Andrey19888
Ставил .. не помогает. Я уже неделю борюсь с этой проблемой

Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 12:50:56
codenamehawk
Andrey19888 писал(а):Безрезультатно. На экране всеравно 12,074999. Если в sprintf(s,"%.3f",sdf); на экране правильно, но в переменной же всеравно нет

Это похоже функция sprintf выдает такой результат, а переменная sdf равна 12.075
Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 12:57:28
codenamehawk
Вывод на экран sprintf(s,"%8.3f",sdf);
Где 8 общее количевство знаков в (s), а 3 количевство знаков после запятой.
Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 12:58:58
Andrey19888
Сейчас проведу эксперимент попробую сравнить sdf c числом 12.075.
Вот тут народ тоже пишет про такие проблемы
http://www.avrfreaks.net/index.php?name ... 49&start=0
Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 13:51:08
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
Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 14:13:43
ARV
опять перепетии с float... ну не нужно его применять! поверьте, можно обойтись и без него, а значит, и не иметь всех проблем, с ним связанных: большого объема кода, проблемы округления, медленной скорости расчетов...
вы передаете ряд цифр, среди которых есть точка, положение точки по сути своей определяет множитель (или делитель, что непринципиально), на который надо умножить(разделить) число.
передаете 12.345 - это значит, число 12345 гнадо разделить на 1000
передаете 12.3 - это знсчит, число 123 надо разделить на 10
и т.д.
для хранения числа выбирайте, предположим, long - думаю, вам хватит с запасом на все случаи жизни. итак, принимаете цифры числа, запоминаете число в переменной long, а положение точки задает вам другое число - делитель, для котрого хватит и обычного int, хотя и long можно не пожалеть.
далее корректируете свою математику в программе так, чтобы ВСЕ расчеты велись в принятом формате: отдельно числа, отдельно делители - это просто! вычисляете все действия над числами, результат преобразуете в строку и вставляете в эту строку в нужное место точку: место этой точки определяется элементарными действиями над ДЕЛИТЕЛЯМИ - это тоже несложно, не так ли?
в итоге вы имеете очень компактный и простой код, работающий быстро. все это называется "математика с фиксированной точкой", в которой все действия осуществляются НАД ЦЕЛЫМИ ЧИСЛАМИ. в некоторых случаях можно еще сильнее упростить задачу, если подумать получше...
Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 14:47:20
codenamehawk
Если у вас в предложении
ARV писал(а):опять перепетии с float... ну не нужно его применять!
заменить на "при определенных условиях, не стоит применять float", то я ваш совет поддержу.
Но если проц быстрый и места много, почему бы float не применить ?
Трудности при изучении, возникают как правило всегда,
но это не повод отказаться от того, что не получается написать с наскоку.
Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 14:54:48
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)
Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 15:27:39
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 цифре с пульта
Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 15:44:08
codenamehawk
Примените sprintf(s,"%8.3f",sdf);

Re: Помогите реализовать запись числа с точкой
Добавлено: Ср янв 05, 2011 15:59:18
Andrey19888
С выводом я уже разобрался. Волновала только проблема что в переменной хранится не правильное число. Но эксперимент показал что функция sprintf не корректно отрабатывает и приходится округлять