O que há de errado com esta aritmética ao usar o compilador SDCC (Little Endian)?
-
24-09-2019 - |
Pergunta
Sou muito novo na programação C e estou trabalhando em um aplicativo de firmware para o meu MCU. Esse método estava funcionando bem quando eu estava usando o compilador Keil (Big Endian), mas quando mudei para o compilador SDCC (Little Endian), ele não está funcionando corretamente. Alguém pode explicar o que estou fazendo de errado ???
O dispositivo de destino é um Silicon Labs C8051F320, que é baseado na arquitetura 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;
}
Adicionado: Primeiro, agora mudei os motociclistas e o Motorspeed para ser Ints não assinado.No meu depurador, por algum motivo, se eu definir um ponto de interrupção na linha de estatuto IF, na primeira entrada desta função Motorsteps = 00, então T deve ser atribuído a 0 também, mas o depurador mostra que t = 0,031497 (decimal ). Se eu mudar o depurador para exibir em hexadecimal, t = 0x3d010300. É como se t estivesse sendo designado ...
Solução
Se motores = 49 então
(50 - 49) / 50 = 0.02
próximo
(1 - 0.02) = 0.98
e
0.98 * 15 = 14.7
Squaring esse valor definiria t como
t = 14.7 * 14.7 = 216.09
Finalmente, a conversão implícita do flutuador de volta para o char não assinado transborda da variável MotorsPeed:
MotorSpeed = 100 + 216.09...// Implicitly converts the float t to an unsigned char of 216
A soma de 100 + 216 = 316, é claro, transborda de um char não assinado e você acaba com 316-256 = 60.
Provavelmente, esse é um comportamento indesejado, independentemente do compilador.
Outras dicas
É como se t estivesse sendo designado ...
Não há razão para o compilador atribuir um valor de 0 a t na declaração
float t = 0;
uma vez que é imediatamente atribuído a motores na próxima linha. Meu palpite é que o otimizador está ignorando a atribuição a zero na declaração e o depurador está simplesmente exibindo o valor não inicializado para a memória em que T está localizado na pilha.
Você pode considerar se livrar completamente da fórmula e usar uma tabela de pesquisa para os valores da rampa. Parece que existem apenas 51 valores para que a tabela seja relativamente pequena. O código para procurar um valor seria Muito de Mais rápido do que usar as bibliotecas de ponto flutuante em um 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;
}
Pelo menos você pode testar seu número inteiro em vez do flutuador para evitar as bibliotecas de pontos flutuantes, a menos que você precise deles ...
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;
}
Por que você mudou de ser para le? O que é a arquitetura do dispositivo de destino? E a propósito, o que é?
Enfim, para questionar. Tenho certeza de que o problema ocorre quando a conversão ocorre. Tente rastrear sua linha de código por linha com a calculadora e tente encontrar quando os números se tornam inesperados.