реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Не работает с float, mega16
Serg_greS
сообщение Apr 27 2006, 13:43
Сообщение #1


Частый гость
**

Группа: Новичок
Сообщений: 85
Регистрация: 13-01-05
Из: Москва
Пользователь №: 1 922



Помогите разобраться вот с чем:
с АЦП считываются значения напряжения с последующим отображением на 5-ти 7-ми сегментных индикаторах, так вот при использовании целых типов все хорошо, а стоит написать float, так такое ощущение, как будто проц висит. float нужен для апроксимации логарифмической зависимости. В чем грабли?
IAR AVR 4.12

апроксимация вида: X = -(log((0.0025*Y)/4.959)/0.029)
Y - значение с АЦП (10 бит)
Go to the top of the page
 
+Quote Post
_artem_
сообщение Apr 27 2006, 14:00
Сообщение #2


учащийся
*****

Группа: Свой
Сообщений: 1 065
Регистрация: 29-10-05
Из: города контрастов
Пользователь №: 10 249



code please ...


--------------------
Зачем лаять на караван , когда на него можно плюнуть?

Go to the top of the page
 
+Quote Post
Виктория
сообщение Apr 27 2006, 14:30
Сообщение #3


инженер
****

Группа: Свой
Сообщений: 520
Регистрация: 19-09-05
Из: Самара
Пользователь №: 8 701



Цитата
X = -(log((0.0025*Y)/4.959)/0.029)


А также основание логарифма - натуральный, десятичный и диапазон Y, при котором тестирование происходило smile.gif

А может тяжелый вес для AVR. Советую упростить, хотя так
X=-(log(((int)(Y/4)*10000.)/0.143811

Это на первый взгляд, может кто еще проще предложит. Можно, например, константу 0.143811 (это 4.959*0.029) под знак логарифма внести и объединить с 10000. smile.gif
Go to the top of the page
 
+Quote Post
WHALE
сообщение Apr 27 2006, 17:34
Сообщение #4


Знающий
****

Группа: Свой
Сообщений: 902
Регистрация: 2-01-06
Из: Краснодар
Пользователь №: 12 768



а симулятор что показывает?


--------------------
"Hello, word!" - 17 errors 56 warnings
Go to the top of the page
 
+Quote Post
Old1
сообщение Apr 27 2006, 20:34
Сообщение #5


Знающий
****

Группа: Свой
Сообщений: 697
Регистрация: 26-07-05
Из: Могилев
Пользователь №: 7 095



Цитата(Serg_greS @ Apr 27 2006, 16:43) *
... так вот при использовании целых типов все хорошо, а стоит написать float, так такое ощущение, как будто проц висит. float нужен для апроксимации логарифмической зависимости. В чем грабли?
IAR AVR 4.12
...

Может быть стек переполняется? Попробуйте увеличить размер CSTACK...
Go to the top of the page
 
+Quote Post
arttab
сообщение Apr 28 2006, 01:20
Сообщение #6


Профессионал
*****

Группа: Свой
Сообщений: 1 432
Регистрация: 7-12-04
Из: Новосибирск
Пользователь №: 1 371



float пробовал на меги8 - работает. только код сильно увеличился. Посмотрите достаточно ли время для общета между измерениями. я в начале прерываний ставлю команду вывод в ноль, а в конце в 1. и вначале маин до цикла выставить в 1. потом смотрю осциллом время прерываний и основного цикла.
С приведением float для вывода на индикатор ошибки нет?


--------------------
OrCAD, Altium,IAR, AVR....
Go to the top of the page
 
+Quote Post
Serg_greS
сообщение Apr 28 2006, 04:00
Сообщение #7


Частый гость
**

Группа: Новичок
Сообщений: 85
Регистрация: 13-01-05
Из: Москва
Пользователь №: 1 922



Код следующий:

//Mega16
//iar EW AVR 4.12

#include <iom16.h>
#include <ioavr.h>
#include <inavr.h>
#include <stdlib.h>
#include <math.h>

#define NUM_IZM 128

//#define _N0 0x03
//#define _N1 0x9f
//#define _N2 0x25
//#define _N3 0x0d
//#define _N4 0x99
//#define _N5 0x49
//#define _N6 0x41
//#define _N7 0x1f
//#define _N8 0x01
//#define _N9 0x09

// 1-st digit 0x10
// 2-nd digit 0x08
// 3-rd digit 0x04
// 4-th digit 0x02
// 5-th digit 0x01


//fuses 8MHz CKSEL3=0 CKSEL2=1 CKSEL1=0 CKSEL0=0
// SUT1=1 SUT0=0 65ms startup


__flash unsigned char Nums[]={0x03, 0x9f, 0x25, 0x0d, 0x99, 0x49, 0x41, 0x1f, 0x01, 0x09};


#pragma vector = TIMER2_OVF_vect
__interrupt void TIMER2_OVF(void);

#pragma vector = TIMER2_COMP_vect
__interrupt void TIMER2_COMP(void);

unsigned char print[5];
unsigned char num=0, di=0;
unsigned int i=0;
unsigned int temp=0, gc=0;
//float temperature=0.0;

void init(void);
void long2char(unsigned int);
unsigned int ADCread(void);


//long int ADCread(void);

void main(void)
{
init();
di=0;
while(1)
{
temp = ADCread();
gc=(unsigned int)((log(((temp*0.0025)-0.1438)/4.959))/0.029);
long2char(gc);
}
}

unsigned int ADCread(void)
{
unsigned long ADC=0, tempADC=0;
unsigned char i=0;
while (i < NUM_IZM) // Усреднение по NUM_IZM замерам
{
// VCC ref and ADCx
ADMUX = (1<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (0<<MUX4) | (0<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0);
//Начинаем одиночное преобразование // ADLAR=0 -> ADCH ------98 ADCL 76543210
ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC));

// ADCSRA |= (1<<ADSC); // ADLAR=1 -> ADCH 98765432 ADCL 10------
// while(!(ADCSRA & (1 << ADIF))); //Ждем окончания преобразования
ADCSRA |= (1<<ADIF); //Сбрасываем флаг
tempADC = ADCL;
tempADC += (ADCH<<8);
ADC +=tempADC;
i++;
}
ADC /= NUM_IZM;
return ((unsigned int)ADC);
}


#pragma vector = TIMER2_OVF_vect
__interrupt void TIMER2_OVF(void)
{
di++;
if (di>=5)
{
di=0;
// i++;
}


}

#pragma vector = TIMER2_COMP_vect
__interrupt void TIMER2_COMP(void)
{
PORTB = 0x1f^(1<<di);
PORTC = Nums[print[di]];

}

void long2char(unsigned int input_num)
{
unsigned char ni=5;
while (ni>0)
{
print[ni-1]=div(input_num,10).rem;
input_num /=10;
ni--;

}
}


#pragma inline=forced
void init (void)
{
//port setup using portb & portc

PORTC = (1<<PORTC7) | (1<<PORTC6) | (1<<PORTC5) | (1<<PORTC4) | (1<<PORTC3) | (1<<PORTC2) | (1<<PORTC1) | (1<<PORTC0);
DDRC = (1<<DDC7) | (1<<DDC6) | (1<<DDC5) | (1<<DDC4) | (1<<DDC3) | (1<<DDC2) | (1<<DDC1) | (1<<DDC0);
PORTB = (1<<PORTB4) | (1<<PORTB3) | (1<<PORTB2) | (1<<PORTB1) | (1<<PORTB0);
DDRB = (1<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (1<<DDB0);



TCCR2 = (0<<FOC2) | (0<<WGM20) | (0<<COM21) | (0<<COM20) | (0<<WGM21) | (0<<CS22) | (0<<CS21) | (1<<CS20);
TIFR = (1<<OCF2) | (1<<TOV2); //clear
TIMSK = (1<<OCIE2) | (1<<TOIE2); //enable interrupt


TCNT2 = 0;
OCR2 = 0x7f;

//ADC init
//internal 2.56v with external capacitor at AREF pin
//ADC0 single ended
ADMUX = (1<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (0<<MUX4) | (0<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0);


ADCSRA = (1<<ADEN) | (0<<ADSC) | (0<<ADATE) | (1<<ADIF) | (0<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0);


ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC)); //wait for end conversion
ADCSRA=ADCSRA; //clear ADCSRA
__enable_interrupt();

}
Go to the top of the page
 
+Quote Post
Serg_greS
сообщение Apr 28 2006, 04:35
Сообщение #8


Частый гость
**

Группа: Новичок
Сообщений: 85
Регистрация: 13-01-05
Из: Москва
Пользователь №: 1 922



Логарифм натуральный, т.е. с основанием е
Go to the top of the page
 
+Quote Post
Old1
сообщение Apr 28 2006, 07:22
Сообщение #9


Знающий
****

Группа: Свой
Сообщений: 697
Регистрация: 26-07-05
Из: Могилев
Пользователь №: 7 095



Цитата(Serg_greS @ Apr 28 2006, 07:00) *
Код следующий:
...
temp = ADCread();
gc=(unsigned int)((log(((temp*0.0025)-0.1438)/4.959))/0.029);
...

Насколько я понял значения переменной temp лежат в диапазоне от 0 до 1023, при этом в соответствии с формулой переменная gc будет всегда отрицательная, а у вас используется приведение к беззнаковому типу...но даже в этом случае переменная gc вычисляется без зависаний, похоже, что дело не в числах с плавающей точкой... я ваш код проверил на реальном устройстве на М16...
Go to the top of the page
 
+Quote Post
Serg_greS
сообщение May 2 2006, 04:52
Сообщение #10


Частый гость
**

Группа: Новичок
Сообщений: 85
Регистрация: 13-01-05
Из: Москва
Пользователь №: 1 922



и все равно что-то не то, даже если использовать:

gc=(unsigned int)((-log(((temp*0.0025))/4.959))/0.029);

(в коде минус потерялся в результате экспериментов)
то логарифм не вычисляется только при нуле с АЦП (что крайне маловероятно), при этом в симуляторе (AVR Studio) все вычисляется правильно, а индикаторы по прежнему не горят, хотя ведущие нули должны гореть всегда.

а на float я стал грешить после того, как сделал переменную gc типа float :

.....
float gc=0.0;
.....
temp = ADCread();
gc=120-((0x3ff-temp))*0.48;
long2char((unsigned int)gc);
.....

до этого было :

unsigned int temp=0, gc=0;
.....
temp = ADCread();
gc=120-((0x3ff-temp))/5;
long2char(gc);
.....
и вроде как работало, но точность не та
Go to the top of the page
 
+Quote Post
proba
сообщение May 2 2006, 06:50
Сообщение #11


Местный
***

Группа: Участник
Сообщений: 358
Регистрация: 29-05-05
Пользователь №: 5 526



С по сушеству 16 битный язык.
советую каждое решение отдельно выписать (и с printf на com посылать).
выражение X = -(log((0.0025*Y)/4.959)/0.029)
будет иметь вид:
float X;
X=(float)Y;
X*=0.0025;
X/=4.959;
X= log(X);
X/=0.029;
но проще будет вычислит таблицу на PC и исползовать для lookup. занимает 2kB .

Сообщение отредактировал proba - May 2 2006, 06:54
Go to the top of the page
 
+Quote Post
vet
сообщение May 2 2006, 06:51
Сообщение #12


Знающий
****

Группа: Свой
Сообщений: 550
Регистрация: 16-06-04
Из: Казань
Пользователь №: 32



Цитата(Serg_greS)
а на float я стал грешить после того, как сделал переменную gc типа float :
Предлагаю операнды во float-point арифметике всё же приводить к правильному типу. В данном случае это будет выглядеть так:
gc = 120.0 - ((float)(0x3ff-temp))*0.48;


--------------------
Главная линия этого опуса ясна мне насквозь!
Go to the top of the page
 
+Quote Post
Serg_greS
сообщение May 2 2006, 08:11
Сообщение #13


Частый гость
**

Группа: Новичок
Сообщений: 85
Регистрация: 13-01-05
Из: Москва
Пользователь №: 1 922



в общем, помучал еще немного и выяснилось, что "виснет" при использовании логарифма.
если писать:
...
gc=(-log(temp/5)*3448);
...
то ругается компиллятор что нужен тип с плавающей запятой под логарифмом
если записать:
....
gc=(-log(unsigned int)(temp/5)*3448);
....
то опять "висит"
В общем что-то не ладно с логарифмом.

Про использование таблицы, я думал, но решил сначала с формулой подумать и вдобавок этож надо ~1000 значений вписать.
Go to the top of the page
 
+Quote Post
Serg_greS
сообщение May 3 2006, 06:18
Сообщение #14


Частый гость
**

Группа: Новичок
Сообщений: 85
Регистрация: 13-01-05
Из: Москва
Пользователь №: 1 922



подскажите в чем проблема при вычислении, если вот эту часть
Цитата
temp = ADCread();
gc=(unsigned int)((log(((temp*0.0025)-0.1438)/4.959))/0.029);
long2char(gc);


заменить на :
ADCread();
if (temp<37) temp=37;
gc=(unsigned int)(22499365 - 22473186*(powf(temp,0.00015)));
long2char(gc);

А то выяснилось, что такая функция намного лучше приводит значения полученные с АЦП к тем значениям, которым они соответствуют.
В AVR Studio вся арифметика проходит гладко и без сбоев:
с АЦП 965 --> gc=3002
с АЦП 0 --> 37 --> gc=14002
в реальном железе индикаторы не горят, хотя нули должны гореть всегда.

и еще: в свойствах проекта CSTACK=0x256 RSTACK=128 надо ли их уменьшить/увеличить?

Сообщение отредактировал Serg_greS - May 3 2006, 06:32
Go to the top of the page
 
+Quote Post
Serg_greS
сообщение May 3 2006, 08:07
Сообщение #15


Частый гость
**

Группа: Новичок
Сообщений: 85
Регистрация: 13-01-05
Из: Москва
Пользователь №: 1 922



Подскажите почему не работает такая конструкция:
gc=(temp*0.5);
или
gc=(temp*(float)0.5);
тогда как
gc=(temp/2);
работает?
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 18:33
Рейтинг@Mail.ru


Страница сгенерированна за 0.01503 секунд с 7
ELECTRONIX ©2004-2016