Что не так с этой арифметикой при использовании компилятора SDCC (Little Endian)? - PullRequest
0 голосов
/ 03 марта 2010

Я очень новичок в программировании на 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 ​​на беззнаковые целые. В моем отладчике по какой-то причине, если я устанавливаю точку останова в строке оператора if, при первом входе в эту функцию MotorSteps = 00, так что t также должен быть присвоен 0, но отладчик показывает, что t = 0.031497 (десятичное ). Если я переключаю отладчик для отображения в шестнадцатеричном формате, t = 0x3d010300. Как будто никогда не назначают ...

Ответы [ 3 ]

3 голосов
/ 03 марта 2010

Если 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.

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

2 голосов
/ 04 марта 2010

Это как никогда назначен ...

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

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;
}
0 голосов
/ 03 марта 2010

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

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

...