2012-01-13 1 views
0

Pourquoi je pose cette question parce qu'il se produit:variables déclarées dans ma struct être de taille différente

en-tête Defined:

typedef struct PID 
{ 
// PID parameters 
uint16_t Kp; // pGain 
uint16_t Ki; // iGain 
uint16_t Kd; // dGain 

// PID calculations OLD ONES WHERE STATICS 
int24_t pTerm; 
int32_t iTerm; 
int32_t dTerm; 
int32_t PID; 

// Extra variabels 
int16_t CurrentError; 

// PID Time 
uint16_t tick; 

}_PIDObject; 

Dans la source C:

static int16_t PIDUpdate(int16_t target, int16_t feedback) 
{ 
     _PIDObject PID2_t; 

    PID2_t.Kp = pGain2; // Has the value of 2000 

     PID2_t.CurrentError = target - feedback; // Has the value of 57 

     PID2_t.pTerm = PID2_t.Kp * PID2_t.CurrentError; // Should count this to (57x2000) = 114000 

Qu'est-ce qui se passe quand je débogue, c'est que ce n'est pas le cas. La plus grande valeur que je peux définir (sorte de) dans pGain2 est 1140. 1140x57 donne 64980.

D'une certaine manière, il semble que le programme pense PID2_t.pTerm est un uint16_t. Mais ce n'est pas; c'est déclaré plus gros dans la structure.

a-t-PID2_t.pTerm en quelque sorte obtenu la valeur uint16_t de la première variables déclarées dans la struct ou est-il quelque chose de mal avec les calculs, j'ai uint16_t fois par int16_t? Cela n'arrivera pas si je les déclare en dehors d'une structure.

Aussi, voici mon int def (n'a jamais été un problème avant:

#ifdef __18CXX 
typedef signed char int8_t;     // -128 -> 127    // Char & Signed Char 
typedef unsigned char uint8_t;    // 0 -> 255     // Unsigned Char 
typedef signed short int int16_t;   // -32768 -> 32767   // Int 
typedef unsigned short int uint16_t;  // 0 -> 65535    // Unsigned Int 
typedef signed short long int int24_t;  // -8388608 -> 8388607  // Short Long 
typedef unsigned short long int uint24_t; // 0 -> 16777215    // Unsigned Short Long 
typedef signed long int int32_t;   // -2147483648 -> 2147483647 // Long 
typedef unsigned long int uint32_t;   // 0 -> 4294967295   // Unsigned Long 
#else 
# include <stdint.h> 
#endif 
+3

Comment 'int24_t' est-il défini? –

+1

On dirait que votre int24_t est défini comme étant de 16 bits. Voyons voir le typedef? :) –

+0

La question la plus importante: Quelle est la taille de 'int'? Pourriez-vous vérifier 'INT_MAX' /' UINT_MAX' dans 'limits.h'? –

Répondre

5

Essayez

PID2_t.pTerm = ((int24_t) PID2_t.Kp) * ((int24_t)PID2_t.CurrentError); 

commentaire de Joachim explique pourquoi cela fonctionne Le compilateur ne promeut pas les multiplicandes à. int24_t avant de se multiplier, donc il y a un débordement.Si nous faisons la promotion manuellement en utilisant des moulages, il n'y a pas de débordement

+0

Pas le problème, voir la discussion sur ma réponse. – Kevin

+0

@Kevin: ... sauf si c'est une plate-forme 16 bits (ou quelque chose de plus bizarre). –

+0

@dmc: Avec cela vous avez écrit: Cela fonctionne. Mais il ne répond pas à ma question – Christian

1

Mon système n'a pas de int24_t , comme l'ont dit certains commentaires, d'où cela vient-il?

Après le commentaire de Joachim, je l'ai écrit un court test:

#include <stdint.h> 
#include <stdio.h> 

int main() { 
     uint16_t a = 2000, b = 57; 
     uint16_t c = a * b; 
     printf("%x\n%x\n", a*b, c); 
} 

Sortie:

1bd50 
bd50 

Alors vous obtenez les 2 premiers octets, conformément à un int16_t. Donc, le problème semble être que votre int24_t n'est pas défini correctement.

+2

Je suis à peu près certain que les valeurs sont garanties avant d'être multipliées. En supposant une architecture 32 bits, le résultat devrait être correct sans moulages. –

+0

@JoachimIsaksson Si vous pouvez trouver cela dans la norme ISO, je vais modifier ou supprimer ma réponse. – Kevin

+0

Seulement trouvé un brouillon, plus clair dans http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf page 14 Exemple 2; En exécutant le fragment char c1, c2; /* ... */ c1 = c1 + c2; les '' promotions entières '' exigent que la machine abstraite fasse la promotion de la valeur de chaque variable à la taille int puis ajoute les deux nombres entiers et tronque la somme. –

-1

Comme d'autres l'ont souligné, votre int24_t semble être défini sur 16 bits. Outre le fait que c'est trop petit, vous devriez être prudent avec cette définition de type en général. stdint.h spécifie les types uint_Nt pour être exactement N bits. Donc, en supposant que votre processeur et votre compilateur n'ont pas de type de données 24 bits, vous rompez avec la convention standard. Si vous voulez finir par le définir comme un type 32 bits, il serait plus raisonnable de le nommer uint_least24_t, qui suit le modèle des types entiers au moins assez grand pour contenir N bits. La distinction est importante car quelqu'un peut s'attendre à uint24_t au-dessus de 16777215.

Questions connexes