Что не так с этой арифметикой при использовании компилятора SDCC (Little Endian)?
-
24-09-2019 - |
Вопрос
Я очень новый в программировании C, и я работаю над приложением прошивки для моего MCU. Этот метод работал нормально, когда я использовал компилятор KEIL (большой Endian), но когда я переключился на компилятор SDCC (маленький Endian), он не работает должным образом. Может кто-нибудь, пожалуйста, объясните, что я делаю не так ???
Целевое устройство представляет собой кремниевые лаборатории 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 (десятичный ). Если я переключаю отладчик для отображения в Hex, t = 0x3d010300. Это как т это никогда не назначается ...
Решение
Если motorsteps = 49, то
(50 - 49) / 50 = 0.02
следующий
(1 - 0.02) = 0.98
а также
0.98 * 15 = 14.7
Скарящий это значение установлено так, как
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, конечно, переполнена unsigned Char, и вы в конечном итоге с 316-256 = 60.
Это, вероятно, нежелательное поведение независимо от компилятора.
Другие советы
Это как т это никогда не назначается ...
Для компилятора нет причин назначать значение от 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;
}
Почему вы перешли с Le? Что такое архитектура целевого устройства? И кстати, что это?
Во всяком случае, к вопросу. Я уверен, что проблема приходит, когда преобразование происходит. Попробуйте проследить вашу строку кода по линии с помощью калькулятора и попробуйте найти, когда числа становятся неожиданными.