Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вычисление констант в процессе компиляции
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
sonycman
Имеется IAR 5.10 и проект на С для ATmega88.
Исходник (кусок):

#define QUARTZ 10000000
#define CLOCK QUARTZ/1000000
#define Wait(mks) __delay_cycles(mks*CLOCK)

Wait(480);

При компиляции идут предупреждения на строку с функцией о выходе значения за пределы диапазона.
Но ведь итоговое значение равно 4800, а параметр __delay_cycles есть unsigned long!
Если CLOCK жестко приравнять к 10, то все нормально.
Но если ее приравнять к 100, то получаем ту-же ошибку out of range плюс еще и о смене знака... :-(

Получается, что компилятор работает с 16-ти битными данными?
Как это побороть?
И почему не работает вышеприведенный пример?
MrYuran
Цитата(sonycman @ Apr 15 2008, 15:30) *
параметр __delay_cycles есть unsigned long!

Точно?
А может всё-таки uint?
Цитата
Как это побороть?
И почему не работает вышеприведенный пример?

Я бы попробовал для начала явное приведение типа, типа:
#define Wait(mks) __delay_cycles((unsigned long)(mks*CLOCK))

А вообще изврат по-моему, отдавать паузы на откуп компилятору...
Я бы не рискнул.
VladimirYU
Цитата(sonycman @ Apr 15 2008, 16:30) *
Имеется IAR 5.10 и проект на С для ATmega88.
Исходник (кусок):

#define QUARTZ 10000000UL
#define CLOCK QUARTZ/1000000
#define Wait(mks) __delay_cycles(mks*CLOCK)

Wait(480);


Добавьте UL
YAM
Всегда делаю так:
#define OS_FSYS_MHZ 7.3728 // Системная частота [MHz]
#define DelayUs(us) __delay_cycles((u32)((us) * OS_FSYS_MHZ))

да, u32 - это unsigned long
rezident
По умолчанию (без явного объявления) к переменным и константам применяется тип int (signed int). Поскольку в стандарте Си размерность типов переменных явно не определена (определены только диапазоны в limits.h), то для надежности на 8-ми/16-и битных платформах нужно явно указывать тип больших по величине констант, добавляя к числу суффикс.
L - signed long (например, 100000L)
UL - unsigned long (например, 7372800UL)
f - float (например, 3.14159f).
Кстати, без суффикса f константа 7.3728 в примере выше
Код
#define OS_FSYS_MHZ 7.3728 // Системная частота [MHz]

может легко стать 64-и разрядной double, в зависимости от настроек проекта и/или если препроцессор посчитает это нужным. Опять же, может я конечно и ошибаюсь, но по-моему препроцессор вычисляет только целочисленные выражения в макросах. Так что макрос типа
Код
#define XMIN  1.2345
#define XMAX  2.3456
#define YMIN  3.456
#define YMAX  4.5678
#define LINE(x) ((YMAX-YMIN)/(XMAX-XMIN)*(x-XMIN)+YMIN)
при подстановке в операцию
Код
y=LINE(x);

даст только лишь удобство написания, но скорость вычисления не уменьшит.
YAM
Вы ошибаетесь. Ведь это так легко проверить. wink.gif
А результат операции y=LINE(x); будет зависеть от типа y...
Кроме того вот так: y=LINE(2.71828) увеличит и значительно wink.gif
rezident
Цитата(YAM @ Apr 15 2008, 23:00) *
Вы ошибаетесь. Ведь это так легко проверить. wink.gif
Неудачный пример. Согласен smile.gif Только подставить константы в выражение должен любой препроцессор, а вот вычислить константное выражение и подставить его значение - нет. Это уже задача оптимизации компилятора.
Цитата(YAM @ Apr 15 2008, 23:00) *
Кроме того вот так: y=LINE(2.71828) увеличит и значительно wink.gif
Увеличит? 07.gif Вы наверное хотели написать "уменьшит"? Потому, что такой оператор должен сводиться к банальной загрузке константы.
sonycman
Цитата(VladimirYU @ Apr 15 2008, 17:56) *
Добавьте UL

Спасибо, добавил, ошибки исчезли, но величина задержки всё равно вычисляется неправильно.
Вот как это выглядит:

Код
#define    QUARTZ    10000000UL            //Crystal quartz frequency
#define    CLOCKS    QUARTZ/1000000UL    //tacts in microsecond

void SomeFunc(void)
{
    volatile unsigned long    a    =    480 * CLOCKS;
}


Так вот, при просмотре отладчиком полученного кода, значение а получается равным 0x0001f9, то есть 505, когда должно быть 4800...
Чёрт, что за глупости smile3046.gif
Причём значения до 420 * CLOCKS обсчитываются правильно, а чуть побольше и пошла бредятина...

Всё, разобрался.
Оказывается эта, извиняюсь за выражение, "тупая скотина" в лице препроцессора или компилятора не вычисляет значение CLOCK, а просто тупо подставляет строку в нужное место.
Например, вышеприведённое выражение принимает вид:
Код
volatile unsigned long    a    =    480 * QUARTZ / CLOCKS

а потом уже компилятор пыжится посчитать:
Код
volatile unsigned long    a    =    480 * 10000000 / 1000000

Естественно, после умножения идёт переполнение за 32 бита, и делению подлежат уже жалкие останки гигантской цифры... 07.gif

Пришлось поставить скобки, теперь вроде всё нормально:
Код
#define    QUARTZ    10000000UL            //Crystal quartz frequency
#define    CLOCKS    (QUARTZ/1000000)    //tacts in microsecond
#define    Wait(mksec)    __delay_cycles(mksec*CLOCKS)

    Wait(480);


На первый взгляд, какого чёрта делают скобки в таком простом выражении?
Ну вот откуда знаешь поначалу такие неявные мелочи?
MrYuran
Цитата(sonycman @ Apr 16 2008, 09:25) *
Код
#define    QUARTZ    10000000UL            //Crystal quartz frequency
#define    CLOCKS    QUARTZ/1000000UL    //tacts in microsecond

А если предположить, что вместо CLOCKS (как бы 10) препроцессор подставляет QUARTZ/1000000UL?
Что получается?
Правильно,
volatile unsigned long a = 480 * QUARTZ/1000000UL;
Теперь попробуем умножить 480 на 10000000UL...
так... умножаем... опа! 0х11E1A3000
А теперь считаем количество разрядов...
Идея понятна?

Я тут вот ещё добавлю: лучше тогда уж флот использовать, может не так точно (а надо ли), зато переполнения не будет.
Да и вообще поаккуратнее с дефайнами
sonycman
Цитата(MrYuran @ Apr 16 2008, 11:45) *
А если предположить, что вместо CLOCKS (как бы 10) препроцессор подставляет QUARTZ/1000000UL?
Что получается?
Правильно,
volatile unsigned long a = 480 * QUARTZ/1000000UL;
Теперь попробуем умножить 480 на 10000000UL...
так... умножаем... опа! 0х11E1A3000
А теперь считаем количество разрядов...
Идея понятна?


Спасибо за помощь, я уже сам допёр smile.gif

ЗЫ: хороший форум, всегда помогут добрые люди! a14.gif
YAM
2 rezident
Вы писали: "даст только лишь удобство написания, но скорость вычисления не уменьшит.". Я и написал, что увеличит в плане скорости вычисления...
vet
Цитата(sonycman @ Apr 16 2008, 10:43) *
не вычисляет значение CLOCK, а просто тупо подставляет строку в нужное место.

и не будет. препроцессор не знает ничего ни об языке С, ни о формате файлов, которые он обрабатывает; его единственная задача - разворачивать макросы в строки.
MrYuran
Мне тут ещё в голову пришло...
Всегда думал : по кой в дефайнах скобочки ставить?
А вот ведь... наглядный пример!
#define CLOCKS (QUARTZ/1000000UL)
вроде то же самое, а на самом деле - одним глюком меньше
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.