Что не так с этой арифметикой при использовании компилятора SDCC (Little Endian)?

Я очень новичок в программировании на C и работаю над прошивкой для своего MCU. Этот метод работал нормально, когда я использовал компилятор KEIL (Big Endian), но когда я переключился на компилятор SDCC (Little Endian), он не работал должным образом. Может кто-нибудь объяснить, что я делаю не так???

Целевым устройством является Silicon Labs C8051F320, основанный на архитектуре 8051.

unsigned **int** MotorSteps  = 0;     //"Global" variables
unsigned **int** MotorSpeed  = 0;
bit RampUp()
{
    float t = 0;
    t = MotorSteps;
    if ( t < 51 )
    {
        t = (1-((50 - t)/50))*15;   
        t = (t * t);        
        MotorSpeed = 100 + t;           
        return 0;
    }
    else return 1;
}

ДОБАВЛЕНО: во-первых, теперь я изменил MotorSteps и MotorSpeed ​​на целые числа без знака. В моем отладчике по какой-то причине, если я устанавливаю точку останова в строке оператора function MotorSteps = 00, поэтому t также должно быть присвоено 0, но отладчик показывает, что t = 0,031497 (десятичное число). Если я переключу отладчик на отображение в шестнадцатеричном формате, t = 0x3d010300. Как будто t никогда не назначают...


person PICyourBrain    schedule 03.03.2010    source источник
comment
Было бы полезно узнать, как выглядели MotorSteps и SetSpeedHz.   -  person Justin Niessner    schedule 03.03.2010
comment
Также было бы полезно увидеть декларацию для MotorSpeed.   -  person semaj    schedule 03.03.2010
comment
В коде нет ничего, что зависит от порядка следования байтов. Так в чем проблема?   -  person AnT    schedule 03.03.2010
comment
Можете ли вы более подробно рассказать о неправильной работе. Неправильно ли он устанавливает MotorSpeed ​​(и если да, то что вы получаете по сравнению с тем, что ожидаете)?   -  person R Samuel Klatchko    schedule 03.03.2010
comment
Я думаю, вам, вероятно, придется опубликовать больше своего кода. Похоже, вы реконструировали свою проблему, опустив много кода (например, что «unsigned int s = 0» нигде не используется), что также означает, что реальная проблема, вероятно, не очевидна. Во всяком случае, на первый взгляд мне это не очевидно.   -  person Ben Collins    schedule 03.03.2010
comment
Мне было бы любопытно увидеть список asm для этой функции. Подозреваю, что что-то неправильно оптимизировано.   -  person mocj    schedule 04.03.2010


Ответы (3)


Если MotorSteps = 49, то

(50 - 49) / 50 = 0.02

следующий

(1 - 0.02) = 0.98

и

0.98 * 15 = 14.7

Возведение этого значения в квадрат установит t как

t = 14.7 * 14.7 = 216.09

Наконец, неявное преобразование из числа с плавающей запятой обратно в беззнаковый символ приводит к переполнению переменной MotorSpeed:

MotorSpeed = 100 + 216.09...// Implicitly converts the float t to an unsigned char of 216

Сумма 100 + 216 = 316, конечно, переполняет беззнаковый символ, и вы получаете 316-256 = 60.

Вероятно, это нежелательное поведение независимо от компилятора.

person semaj    schedule 03.03.2010
comment
На самом деле, присвоение float (или double) целочисленному типу, когда значение float находится за пределами диапазона целочисленного типа, приводит к неопределенному поведению, а не к четко определенному модульному переполнению, как можно было бы ожидать от unsigned int. Таким образом, результат может не быть 60, и это может объяснить, почему это ведет себя по-разному в разных компиляторах. - person Tyler McHenry; 03.03.2010

Как будто t никогда не назначают...

У компилятора нет причин присваивать t значение 0 в объявлении.

float t = 0;

так как он сразу же назначается MotorSteps на следующей строке. Я предполагаю, что оптимизатор игнорирует присваивание нулю в объявлении, а отладчик просто отображает неинициализированное значение для памяти, где t находится в стеке.

Возможно, вы захотите полностью избавиться от формулы и использовать справочную таблицу для значений рампы. Похоже, что всего 51 значение, поэтому таблица будет относительно небольшой. Код для поиска значения будет намного быстрее, чем использование библиотек с плавающей запятой на 8051.

#define NUM_RAMP_STEPS 51
unsigned char MotorSteps = 0;     //"Global" variables
unsigned char MotorSpeed = 0;
const unsigned char RampTable[NUM_RAMP_STEPS] = {...appropriate values...};
bit RampUp()
{
    if ( MotorSteps < NUM_RAMP_STEPS )
    {
        MotorSpeed = RampTable[MotorSteps];           
        return 0;
    }
    else return 1;
}

По крайней мере, вы можете проверить свое целое число, а не число с плавающей запятой, чтобы избежать библиотек с плавающей запятой, если они вам не нужны...

unsigned **int** MotorSteps  = 0;     //"Global" variables
unsigned **int** MotorSpeed  = 0;
bit RampUp()
{
    if ( MotorSteps < 51 )
    {
        float t = MotorSteps;
        t = (1-((50 - t)/50))*15;   
        t = (t * t);        
        MotorSpeed = 100 + t;           
        return 0;
    }
    else return 1;
}
person semaj    schedule 03.03.2010

почему вы перешли с BE на LE? Что такое архитектура целевого устройства? А кстати что это?

Во всяком случае, на вопрос. Я почти уверен, что проблема возникает, когда происходит преобразование. Попробуйте проследить свой код построчно с помощью калькулятора и попытаться обнаружить, когда числа становятся неожиданными.

person Andrey    schedule 03.03.2010
comment
Первоначально я использовал компилятор KEIL, но я достиг ограничений бесплатной версии и не хотел платить за лицензию, поэтому я переключился на SDCC, который является бесплатным и неограниченным... но противоположен Endian-ness. - person PICyourBrain; 04.03.2010