Пишу на СИ CVAVR
Помогите реализовать запись числа с точкой
- Сообщения: 12
- Зарегистрирован: Вс июл 16, 2006 23:52:49
С Ик пульта вводится число с плавающей точкой. Т.е. для получения числа, например, 0.005 вводится сначала 0, затем точка, затем еще 2 нуля и 5. Посоветуйте как грамотно организовать запись данных в переменную Float
Пишу на СИ CVAVR
Пишу на СИ CVAVR
Жизнь как рояль: клавиша белая, клавиша черная, крышка
- Реклама
- Сообщения: 541
- Зарегистрирован: Вт фев 09, 2010 17:52:26
В библиотеке stdlib.h
есть функция
float atof(char *str)
converts the characters from string str to floating point.
должна вам помочь.
есть функция
float atof(char *str)
converts the characters from string str to floating point.
должна вам помочь.
- Сообщения: 12
- Зарегистрирован: Вс июл 16, 2006 23:52:49
Спасибо огромное. Попробую. О результате отпишусь 
Жизнь как рояль: клавиша белая, клавиша черная, крышка
- Сообщения: 12
- Зарегистрирован: Вс июл 16, 2006 23:52:49
Сделал по совету и столкнулся с проблемой
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 = "12.075";
char s[20];
sdf=atof(add);
sprintf(s,"%f",sdf);
lcd_puts(s);
в итоге на экране имеем вместо 12.075 12.074999
Жизнь как рояль: клавиша белая, клавиша черная, крышка
- Реклама
- Сообщения: 12
- Зарегистрирован: Вс июл 16, 2006 23:52:49
Спасибо. Заработало. Единственный момент, что в переменной sdf по прежнему остается неточное значение, а мне с ней нужно будет работать. Как там можно поправить?
Жизнь как рояль: клавиша белая, клавиша черная, крышка
- Сообщения: 541
- Зарегистрирован: Вт фев 09, 2010 17:52:26
Попробуйте так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;Код: Выделить всё
sdf=atof(add);
sprintf(s,"%f",sdf);
- Сообщения: 12
- Зарегистрирован: Вс июл 16, 2006 23:52:49
Безрезультатно. На экране всеравно 12,074999. Если в sprintf(s,"%.3f",sdf); на экране правильно, но в переменной же всеравно нет 
Жизнь как рояль: клавиша белая, клавиша черная, крышка
- Сообщения: 804
- Зарегистрирован: Чт мар 12, 2009 16:31:05
- Сообщения: 12
- Зарегистрирован: Вс июл 16, 2006 23:52:49
Ставил .. не помогает. Я уже неделю борюсь с этой проблемой 
Жизнь как рояль: клавиша белая, клавиша черная, крышка
- Сообщения: 541
- Зарегистрирован: Вт фев 09, 2010 17:52:26
Это похоже функция sprintf выдает такой результат, а переменная sdf равна 12.075Andrey19888 писал(а):Безрезультатно. На экране всеравно 12,074999. Если в sprintf(s,"%.3f",sdf); на экране правильно, но в переменной же всеравно нет
- Сообщения: 541
- Зарегистрирован: Вт фев 09, 2010 17:52:26
Вывод на экран sprintf(s,"%8.3f",sdf);
Где 8 общее количевство знаков в (s), а 3 количевство знаков после запятой.
Где 8 общее количевство знаков в (s), а 3 количевство знаков после запятой.
Последний раз редактировалось codenamehawk Ср янв 05, 2011 12:59:33, всего редактировалось 1 раз.
- Сообщения: 12
- Зарегистрирован: Вс июл 16, 2006 23:52:49
Сейчас проведу эксперимент попробую сравнить sdf c числом 12.075.
Вот тут народ тоже пишет про такие проблемы
http://www.avrfreaks.net/index.php?name ... 49&start=0
Вот тут народ тоже пишет про такие проблемы
http://www.avrfreaks.net/index.php?name ... 49&start=0
Жизнь как рояль: клавиша белая, клавиша черная, крышка
- Сообщения: 541
- Зарегистрирован: Вт фев 09, 2010 17:52:26
Посмотрите пример
Не забывайте, что если для float попробуете задать число типа 12.0000000075 , оно будет округленно.
Почитайте http://ru.wikipedia.org/wiki/%D0%A7%D0% ... 0%BE%D0%B9
Почитайте http://ru.wikipedia.org/wiki/%D0%A7%D0% ... 0%BE%D0%B9
опять перепетии с float... ну не нужно его применять! поверьте, можно обойтись и без него, а значит, и не иметь всех проблем, с ним связанных: большого объема кода, проблемы округления, медленной скорости расчетов...
вы передаете ряд цифр, среди которых есть точка, положение точки по сути своей определяет множитель (или делитель, что непринципиально), на который надо умножить(разделить) число.
передаете 12.345 - это значит, число 12345 гнадо разделить на 1000
передаете 12.3 - это знсчит, число 123 надо разделить на 10
и т.д.
для хранения числа выбирайте, предположим, long - думаю, вам хватит с запасом на все случаи жизни. итак, принимаете цифры числа, запоминаете число в переменной long, а положение точки задает вам другое число - делитель, для котрого хватит и обычного int, хотя и long можно не пожалеть.
далее корректируете свою математику в программе так, чтобы ВСЕ расчеты велись в принятом формате: отдельно числа, отдельно делители - это просто! вычисляете все действия над числами, результат преобразуете в строку и вставляете в эту строку в нужное место точку: место этой точки определяется элементарными действиями над ДЕЛИТЕЛЯМИ - это тоже несложно, не так ли?
в итоге вы имеете очень компактный и простой код, работающий быстро. все это называется "математика с фиксированной точкой", в которой все действия осуществляются НАД ЦЕЛЫМИ ЧИСЛАМИ. в некоторых случаях можно еще сильнее упростить задачу, если подумать получше...
вы передаете ряд цифр, среди которых есть точка, положение точки по сути своей определяет множитель (или делитель, что непринципиально), на который надо умножить(разделить) число.
передаете 12.345 - это значит, число 12345 гнадо разделить на 1000
передаете 12.3 - это знсчит, число 123 надо разделить на 10
и т.д.
для хранения числа выбирайте, предположим, long - думаю, вам хватит с запасом на все случаи жизни. итак, принимаете цифры числа, запоминаете число в переменной long, а положение точки задает вам другое число - делитель, для котрого хватит и обычного int, хотя и long можно не пожалеть.
далее корректируете свою математику в программе так, чтобы ВСЕ расчеты велись в принятом формате: отдельно числа, отдельно делители - это просто! вычисляете все действия над числами, результат преобразуете в строку и вставляете в эту строку в нужное место точку: место этой точки определяется элементарными действиями над ДЕЛИТЕЛЯМИ - это тоже несложно, не так ли?
в итоге вы имеете очень компактный и простой код, работающий быстро. все это называется "математика с фиксированной точкой", в которой все действия осуществляются НАД ЦЕЛЫМИ ЧИСЛАМИ. в некоторых случаях можно еще сильнее упростить задачу, если подумать получше...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Сообщения: 541
- Зарегистрирован: Вт фев 09, 2010 17:52:26
Если у вас в предложении
Но если проц быстрый и места много, почему бы float не применить ?
Трудности при изучении, возникают как правило всегда,
но это не повод отказаться от того, что не получается написать с наскоку.
заменить на "при определенных условиях, не стоит применять float", то я ваш совет поддержу.ARV писал(а):опять перепетии с float... ну не нужно его применять!
Но если проц быстрый и места много, почему бы float не применить ?
Трудности при изучении, возникают как правило всегда,
но это не повод отказаться от того, что не получается написать с наскоку.
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 например(задавать с третего канала
ТАК ВОТ....сейчас я это делаю так:
суть работы - таймер считает микросекунды и в переменных In_Gyro и Gas_in появляются значения длительности импульса в микросекундах...
здесь я затупил влияние разбалансового второгосигнала(гироскопа) в два раза...а хочется взять третий канал и с пульта на лету это дело корректировать...а ещё внести Экспоненту но это потом....
так вот....как бы это всё можно было б упростить....получается малая дискретность того флоата что расчитывается в строке
ведь мы приводим его к диапазону 0...1 а потом умножаем на нужный мне выходной диапазон(для PWM регистра)
при этом значения минимума, максимума и среднего положения длительности сигнала калибруется/меняется/расчитывается при включении(например разбалансный центр может быть не 1520 как опложено а 1401, а минимум не 1000 а 983, а максимум не 2000 а 1973)
Делаю миксер для вертолёта - суть в том что входные сигналы - это импульс длительностью от 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;
здесь я затупил влияние разбалансового второгосигнала(гироскопа) в два раза...а хочется взять третий канал и с пульта на лету это дело корректировать...а ещё внести Экспоненту но это потом....
так вот....как бы это всё можно было б упростить....получается малая дискретность того флоата что расчитывается в строке
Код: Выделить всё
TempA = TempA/Delta_Gas;
TempA = TempA * 500.0;
при этом значения минимума, максимума и среднего положения длительности сигнала калибруется/меняется/расчитывается при включении(например разбалансный центр может быть не 1520 как опложено а 1401, а минимум не 1000 а 983, а максимум не 2000 а 1973)
Что нас не убило сделало нас осторожней
Не доверяйте русским лужам - это может быть вход в метро.
Не доверяйте русским лужам - это может быть вход в метро.
- Сообщения: 12
- Зарегистрирован: Вс июл 16, 2006 23:52:49
codenamehawk писал(а):Это похоже функция sprintf выдает такой результат, а переменная sdf равна 12.075Andrey19888 писал(а):Безрезультатно. На экране всеравно 12,074999. Если в sprintf(s,"%.3f",sdf); на экране правильно, но в переменной же всеравно нет
Как не парадоксально, но вот что я сделал
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 цифре с пульта
Жизнь как рояль: клавиша белая, клавиша черная, крышка
- Сообщения: 541
- Зарегистрирован: Вт фев 09, 2010 17:52:26
- Сообщения: 12
- Зарегистрирован: Вс июл 16, 2006 23:52:49
С выводом я уже разобрался. Волновала только проблема что в переменной хранится не правильное число. Но эксперимент показал что функция sprintf не корректно отрабатывает и приходится округлять
Жизнь как рояль: клавиша белая, клавиша черная, крышка


