2010-03-03 24 views
0

Je suis très nouveau en programmation C et je travaille sur une application de firmware pour mon MCU. Cette méthode fonctionnait correctement lorsque j'utilisais le compilateur KEIL (Big Endian) mais lorsque je passais au compilateur SDCC (Little Endian), il ne fonctionnait pas correctement. Quelqu'un peut-il s'il vous plaît expliquer ce que je fais mal ???Quel est le problème avec cette arithmétique lors de l'utilisation du compilateur SDCC (Little Endian)?

Le périphérique cible est un Silicon Labs C8051F320 basé sur l'architecture 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; 
} 

AJOUTÉE: D'abord, je maintenant changé les MotorSteps et MotorSpeed ​​être ints non signés. Dans mon débogueur, pour une raison quelconque, si je définissais un point d'arrêt sur la ligne if-statement, à la première entrée de cette fonction MotorSteps = 00, t devrait également être affecté à 0 mais le débogueur montre que t = 0.031497 (décimal). Si je commute le débogueur à afficher en hexadécimal, t = 0x3d010300. C'est comme si on ne l'assignait jamais ...

+1

Il serait utile de savoir à quoi ressemblaient MotorSteps et SetSpeedHz. –

+0

Il serait également utile de voir la déclaration pour MotorSpeed. – semaj

+3

Il n'y a rien dans le code qui dépend de l'endian. Alors quel est le problème? – AnT

Répondre

3

Si MotorSteps = 49 puis

(50 - 49)/50 = 0.02 

suivant

(1 - 0.02) = 0.98 

et

0.98 * 15 = 14.7 

Squaring cette valeur fixeraient t comme

t = 14.7 * 14.7 = 216.09 

Enfin, la conversion implicite du flotteur retour au unsigned char déborde la variable MotorSpeed:

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

La somme de 100 + 216 = 316, bien entendu, un unsigned char déborde et vous vous retrouvez avec 316- 256 = 60.

Ce comportement est probablement indésirable quel que soit le compilateur.

+3

En fait, affecter un flottant (ou un double) à un type intégral lorsque la valeur du flottant est en dehors de la plage du type intégral entraîne un comportement indéfini, pas un débordement modulaire bien défini comme on peut s'y attendre d'un int non signé. Le résultat peut donc ne pas être 60, et cela peut expliquer pourquoi cela se comporte différemment dans différents compilateurs. –

0

pourquoi avez-vous changé de BE à LE? Quelle est l'architecture du périphérique cible? Et au fait, qu'est-ce que c'est?

Quoi qu'il en soit, à la question. Je suis assez sûr que le problème vient quand la conversion a lieu. Essayez de tracer votre code ligne par ligne avec la calculatrice et essayez de trouver quand les nombres deviennent inattendus.

+2

J'utilisais à l'origine le compilateur KEIL mais j'ai atteint les limites de la version gratuite et je ne voulais pas payer pour la licence donc je suis passé à SDCC qui est gratuit et illimité ... mais opposé Endian-ness. – PICyourBrain

2

Il est comme t est jamais se attribué ...

Il n'y a aucune raison pour que le compilateur d'attribuer une valeur de 0 à t dans la déclaration

float t = 0; 

puisqu'il est immédiatement affecté à MotorSteps sur la ligne suivante. Je suppose que l'optimiseur ignore l'affectation à zéro dans la déclaration et le débogueur affiche simplement la valeur non initialisée pour la mémoire où t est situé sur la pile.

Vous voudrez peut-être envisager de vous débarrasser complètement de la formule et d'utiliser une table de consultation pour les valeurs de rampe. On dirait qu'il n'y a que 51 valeurs donc la table serait relativement petite.Le code pour rechercher une valeur serait beaucoup plus rapide que d'utiliser les bibliothèques à virgule flottante sur une 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; 
} 

Au moins, vous pouvez tester votre entier plutôt que le flotteur pour éviter les bibliothèques à virgule flottante, sauf si vous avez besoin eux ...

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; 
}