Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Не работает с float
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Serg_greS
Помогите разобраться вот с чем:
с АЦП считываются значения напряжения с последующим отображением на 5-ти 7-ми сегментных индикаторах, так вот при использовании целых типов все хорошо, а стоит написать float, так такое ощущение, как будто проц висит. float нужен для апроксимации логарифмической зависимости. В чем грабли?
IAR AVR 4.12

апроксимация вида: X = -(log((0.0025*Y)/4.959)/0.029)
Y - значение с АЦП (10 бит)
_artem_
code please ...
Виктория
Цитата
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
WHALE
а симулятор что показывает?
Old1
Цитата(Serg_greS @ Apr 27 2006, 16:43) *
... так вот при использовании целых типов все хорошо, а стоит написать float, так такое ощущение, как будто проц висит. float нужен для апроксимации логарифмической зависимости. В чем грабли?
IAR AVR 4.12
...

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

//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();

}
Serg_greS
Логарифм натуральный, т.е. с основанием е
Old1
Цитата(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...
Serg_greS
и все равно что-то не то, даже если использовать:

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);
.....
и вроде как работало, но точность не та
proba
С по сушеству 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 .
vet
Цитата(Serg_greS)
а на float я стал грешить после того, как сделал переменную gc типа float :
Предлагаю операнды во float-point арифметике всё же приводить к правильному типу. В данном случае это будет выглядеть так:
gc = 120.0 - ((float)(0x3ff-temp))*0.48;
Serg_greS
в общем, помучал еще немного и выяснилось, что "виснет" при использовании логарифма.
если писать:
...
gc=(-log(temp/5)*3448);
...
то ругается компиллятор что нужен тип с плавающей запятой под логарифмом
если записать:
....
gc=(-log(unsigned int)(temp/5)*3448);
....
то опять "висит"
В общем что-то не ладно с логарифмом.

Про использование таблицы, я думал, но решил сначала с формулой подумать и вдобавок этож надо ~1000 значений вписать.
Serg_greS
подскажите в чем проблема при вычислении, если вот эту часть
Цитата
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
Подскажите почему не работает такая конструкция:
gc=(temp*0.5);
или
gc=(temp*(float)0.5);
тогда как
gc=(temp/2);
работает?
vet
Цитата(Serg_greS @ May 3 2006, 12:07) *
Подскажите почему не работает такая конструкция:
gc=(temp*0.5);
или
gc=(temp*(float)0.5);
тогда как
gc=(temp/2);
работает?
Потому что temp - целое.
Почитайте учебник по Си Кернигана-Ритчи или подобный, там хорошо изложено про преобразования типов в арифметике.

Применительно к данной конкретной ситуации - сделайте, как я советовал парой постов ранее. То есть, gc=((float)temp*0.5);
topkin
gc - какой тип данных?
Serg_greS
2 vet
Цитата
gc=((float)temp*0.5);

так тоже не работает в железке
не работает даже так:
float gc=0.0;
...
gc=((float)temp*(float)0.5); или gc=((float)temp*0.5);
temp=(unsigned int)gc;
long2char(temp);
...

, а в симуляторе AVR Studio пожалуйста любой вариант правильно исполняется.


2 topkin
Цитата
gc - какой тип данных?

даже перебрав все варианты в AVR Studio все работает, в железке нет.
WHALE
Имхо,что-то с выводом на ALC.У тебя динамическая индикация,а работа с флоат жрет намного больше
времени.Поковыряй код там
Old1
Цитата(Serg_greS @ May 3 2006, 16:14) *
даже перебрав все варианты в AVR Studio все работает, в железке нет.

Может быть дело в оптимизации? Когда для AVRStudio проект компилировали, был включен профиль debug и настройки оптимизации по умолчанию? т.е без оптимизации? А потом переключаемся в release, автоматически устанавливается максимальный уровень оптимизации по размеру, компилим hex-файл и ... не работает... Такое бывает... Попробуйте при создании файла для заливки в контроллер отключить оптимизацию.
Serg_greS
2 WHALE
Цитата
Имхо,что-то с выводом на ALC.У тебя динамическая индикация,а работа с флоат жрет намного больше
времени.Поковыряй код там

ALC - это имеется в виду АЛУ?
и насчет индикации: пробовал запрещать все прерывания перед началом вычислений, а после вычисления разрешать (т.к. индикация осуществляется из прерывания), все равно не помогает. Таже ситуация в AVR Studio работает и работает правильно, а в железке нет.


2 Old1
Цитата
Может быть дело в оптимизации? Когда для AVRStudio проект компилировали, был включен профиль debug и настройки оптимизации по умолчанию? т.е без оптимизации? А потом переключаемся в release, автоматически устанавливается максимальный уровень оптимизации по размеру, компилим hex-файл и ... не работает... Такое бывает... Попробуйте при создании файла для заливки в контроллер отключить оптимизацию.


Так как раз без оптимизаций всяких и компиллирую в Debug варианте.

Может это какая то особенность IAR`а v4.12 в evaluation варианте???? - косячная работа с float в реальном железе???
otrog
Цитата(Serg_greS @ May 4 2006, 08:03) *
Так как раз без оптимизаций всяких и компиллирую в Debug варианте.

А шьете тоже Debug вариант? blink.gif
Помоему надо шить Release и все заработает. cool.gif
Old1
Цитата(Serg_greS @ May 4 2006, 07:03) *
2 WHALE
Цитата
Имхо,что-то с выводом на ALC.У тебя динамическая индикация,а работа с флоат жрет намного больше
времени.Поковыряй код там

ALC - это имеется в виду АЛУ?
и насчет индикации: пробовал запрещать все прерывания перед началом вычислений, а после вычисления разрешать (т.к. индикация осуществляется из прерывания), все равно не помогает. Таже ситуация в AVR Studio работает и работает правильно, а в железке нет.


2 Old1
Цитата
Может быть дело в оптимизации? Когда для AVRStudio проект компилировали, был включен профиль debug и настройки оптимизации по умолчанию? т.е без оптимизации? А потом переключаемся в release, автоматически устанавливается максимальный уровень оптимизации по размеру, компилим hex-файл и ... не работает... Такое бывает... Попробуйте при создании файла для заливки в контроллер отключить оптимизацию.


Так как раз без оптимизаций всяких и компиллирую в Debug варианте.

Может это какая то особенность IAR`а v4.12 в evaluation варианте???? - косячная работа с float в реальном железе???

Я ради интереса запустил код в JTAGICE+M16 (правда без оптимизации), так как ни странно код выполняется: формула вычисляется и с log() и c pow() , массив print[] заполняется, перекодировка работает, перекодированные данные в PORTC выбрасываются, разряды в PORTB двигаются, все это компилирую в том же IAR 4.12 и код гоняю в C-SPY... Проверьте все ли в порядке с динамической индикацией:временно отключите вычисление формул и запишите в переменную gc число (правдоподобное), если работает, проверьте вычисляется ли формула: на свободный пин контроллеоа повесьте светодиод и зажигайте/гасите его после вычисления формулы, или просто дрыгайте этим пином, а смотрите осциллографом (заодно и время вычисления увидите)...
Serg_greS
2 Old1
Цитата
Я ради интереса запустил код в JTAGICE+M16

Добавил светодиод на PORTD7, зажигаю его на 5 сек после init() и на время вычислений + ~0.6 сек. Так вот какая интересная штука получается: если в gc записать число и даже умножить его там на 0.5 все отображается, но только такое впечатление, что это выражение вычисляет компилятор, а в проц зашивается константа. А если вычислять gc=(temp*0.5); или gc=(di*0.5); или gc=((float)temp*0.5); или gc=(unsigned int)((float)temp*0.5);
то светодиод не загорается даже после init(); (как будто проц висит и даже не проходит инициализация)

Может у меня какая-то мега битая?
ATMEGA16
16PI
0539J

Old1 не могли бы Вы прислать свой .hex файл, который работает у вас
Old1
Цитата(Serg_greS @ May 4 2006, 13:59) *
...
Добавил светодиод на PORTD7, зажигаю его на 5 сек после init() и на время вычислений + ~0.6 сек. Так вот какая интересная штука получается: если в gc записать число и даже умножить его там на 0.5 все отображается, но только такое впечатление, что это выражение вычисляет компилятор, а в проц зашивается константа.

Так оно и есть.
Цитата
А если вычислять gc=(temp*0.5); или gc=(di*0.5); или gc=((float)temp*0.5); или gc=(unsigned int)((float)temp*0.5);
то светодиод не загорается даже после init(); (как будто проц висит и даже не проходит инициализация)
Может у меня какая-то мега битая?
ATMEGA16
16PI
0539J

Маловероятно...
Цитата
Old1 не могли бы Вы прислать свой .hex файл, который работает у вас

Нет проблем, завтра на работе скомпилирую hex и прикреплю к посту. Я код гонял в ИАРовском C-SPY+ JTAGICE, там используется UBROF формат (если я правильно понял )...
Old1
2 Serg_greS
Цитата(Old1 @ May 4 2006, 22:50) *
Нет проблем, завтра на работе скомпилирую hex и прикреплю к посту...

Вот выкладываю файл с прошивкой, и на всякий случай исходник, который компилировал. Прошивайте. Для информации, основные настройки проекта: cpu - mega16; memory model - small; CSTACK - 0x80; RSTACK - 32; language- C;optimizations- high/size; output format - intel-extended. FUSы - заводские.
Serg_greS
Цитата
Вот выкладываю файл с прошивкой, и на всякий случай исходник, который компилировал.


Спасибо что откликнулись, но только похоже что напрасно
Не работает sad.gif sad.gif sad.gif
молчит не дышит.
А Jtag в фузах у меня выключен, т.к. он на порте С и светится только часть сегментов при использовании gc=temp;,
все остальные восстановил по умолчанию (у меня стоял внутренний генератор на 8МГц. Пробовал также и Jtag включить (т.е. все фузы по умолчанию)) - эффект тотже.
Пробовал откомпиллировать присланный исходник с теми же параметрами проекта, не работает, но с чудесами
у Вас hex кончается адресом 668, у меня d20, т.е. больше на n-е количество байт. Уже не знаю на что и думать wacko.gif . Тупик какой-то, или проц всетаки с брачком.
Old1
Цитата(Serg_greS @ May 5 2006, 11:40) *
Цитата
Вот выкладываю файл с прошивкой, и на всякий случай исходник, который компилировал.


Спасибо что откликнулись, но только похоже что напрасно
Не работает sad.gif sad.gif sad.gif
молчит не дышит.
А Jtag в фузах у меня выключен, т.к. он на порте С и светится только часть сегментов при использовании gc=temp;,
все остальные восстановил по умолчанию (у меня стоял внутренний генератор на 8МГц. Пробовал также и Jtag включить (т.е. все фузы по умолчанию)) - эффект тотже.
Пробовал откомпиллировать присланный исходник с теми же параметрами проекта, не работает, но с чудесами
у Вас hex кончается адресом 668, у меня d20, т.е. больше на n-е количество байт. Уже не знаю на что и думать wacko.gif . Тупик какой-то, или проц всетаки с брачком.

Странно все это...
Что за адрес 668? В моем hex последний адрес вообще-то 0хCDD... Чем прошиваете контроллер? При прошивке верификация проходит без проблем? После прошивки пробовали читать флеш и сравнивать с исходным файлом?...
Serg_greS
Цитата
Чем прошиваете

прошиваю с помощью http://avr.nikolaew.org/progr.htm
верификация проходит без проблем
Old1
Цитата(Serg_greS @ May 5 2006, 15:47) *
Цитата
Чем прошиваете

прошиваю с помощью http://avr.nikolaew.org/progr.htm
верификация проходит без проблем

Появилась мысль: если программирование и верификация FLASH проходит без проблем, код в симуляторе работает (и не в симуляторе у меня - тоже), у вас в железке работает,но только до тех пор пока в коде не появляются вычисления с плавающей точкой (при которых требуется больше оперативной памяти), то может быть в вашем контроллере какая либо область SRAM битая. Чтобы проверить ИМХО самый простой вариант взять другую М16 (если она есть), прошить и сравнить результаты, если же ее в наличии нет, тогда ради спортивного интереса и в целях самообразования стоит написать прогу для самотестирования SRAM (что-то вроде: записал байт в ячейку SRAM, прочитал, сравнил, и так по возможности проверить всю SRAM), залить ее в контроллер и посмотреть, что будет. Тут на форуме не так давно даже тема обсуждалась по поводу способов самотестирования AVR, поищите ознакомьтесь, может пригодится.
Serg_greS
Цитата
но только до тех пор пока в коде не появляются вычисления


Цитата
Добавил светодиод на PORTD7, зажигаю его на 5 сек после init() и на время вычислений + ~0.6 сек. Так вот какая интересная штука получается: если в gc записать число и даже умножить его там на 0.5 все отображается, но только такое впечатление, что это выражение вычисляет компилятор, а в проц зашивается константа. А если вычислять gc=(temp*0.5); или gc=(di*0.5); или gc=((float)temp*0.5); или gc=(unsigned int)((float)temp*0.5);
то светодиод не загорается даже после init();


ведь после init(); не загорается тоже, а ведь до вычислений с плавающей точкой не дошли еще.

а насчет самотестирования мысль хорошая, займусь этим.
Serg_greS
Old1 a14.gif огрОмный респект, все заработало. Сделал клон STK200, прошил и все заработало. Проблема как оказалось не в проце, а в программаторе, видимо что-то он не так прошивает, хоть и верификация проходит. Спасибо всем кто откликнулся.
Old1
Цитата(Serg_greS @ May 11 2006, 11:32) *
Old1 a14.gif огрОмный респект, все заработало. Сделал клон STK200, прошил и все заработало. Проблема как оказалось не в проце, а в программаторе, видимо что-то он не так прошивает, хоть и верификация проходит. Спасибо всем кто откликнулся.

Поздравляю! Кстати, рекомендую собрать девайс описанный здесь. Это клоны внутрисхемного эмулятора JTAGICE и программатора AVRISP в одном флаконе. Обладая подобным девайсом скорость запуска и отладки кода значительно увеличивается...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.