2 votes

AVR GCC - problème de typage

J'utilise un microcontrôleur AVR pour écrire sur un diviseur de fréquence programmable via le bus I2C. A certains intervalles, j'essaie de faire en sorte que la fonction suivante soit appelée pour mettre à jour la fréquence de sortie de la puce :

void 1077WriteDiv(int16_t data)
{
    uint8_t upperByte = (uint8_t)((uint16_t)data>>2);

    i2c_start(DS1077_BASE_ADDRESS);
    i2c_write(DIVIDE_REGISTER);
    i2c_write(upperByte);
    i2c_write(0x0);
    i2c_stop();
}

J'essaie de récupérer les 8 bits supérieurs d'une valeur de 10 bits dans la variable "data" et de l'écrire. La deuxième commande "write" écrit les 8 bits inférieurs du registre "divide" de la puce, 0 dans ce cas.

En guise de test, j'incrémente la variable "data" (qui doit être signée pour certaines raisons) à partir de zéro, je la décale de 2 bits vers la gauche et j'appelle cette fonction à chaque fois. J'obtiens des déchets. Cependant, lorsque je fais ceci :

 void 1077WriteDiv(int16_t data)
    {
        //uint8_t upperByte = (uint8_t)((uint16_t)data>>2);
            static uint8_t thing = 0;     

        i2c_start(DS1077_BASE_ADDRESS);
        i2c_write(DIVIDE_REGISTER);
        i2c_write(thing++);
        i2c_write(0x0);
        i2c_stop();
    }

Tout fonctionne comme prévu. Il est évident qu'il y a un problème dans la façon dont je décale et classe la variable "data" originale, mais j'ai essayé toutes sortes de permutations avec les mêmes résultats. J'apprécierais beaucoup si quelqu'un pouvait m'indiquer où je me trompe.

1voto

Joel Spolsky Points 22686

Essayez

uint8_t upperByte = (uint8_t) ((data & 0x3FC) >> 2);

Vous ne pouvez pas compter sur le transfert vers un int plus petit pour supprimer les bits d'ordre supérieur dont vous essayez de vous débarrasser.

1voto

Guy Sirton Points 5092
i2c_write(thing++);

Ça voudrait dire que votre diviseur s'incrémente à chaque appel. Si vous incrémentez "data" et que vous le décalez de deux vers la droite, alors votre diviseur incrémente chaque quatre appels. Vos deux sections de code ne sont pas équivalentes.

À quel intervalle appelez-vous cette fonction ? Qu'est-ce que le "garbage out" ? Comment savez-vous que la valeur passée dans la fonction est correcte ? Comment savez-vous que la valeur envoyée à la DS1077 est fausse ?

Vérifiez toutes vos hypothèses.

La distribution et le décalage me semblent bons. Du moins, je pense qu'ils fonctionneraient dans tous les compilateurs C que j'ai utilisés. Du point de vue de la norme C, vous pouvez vous référer à ce projet ( ISO/IEC 9899:TC2 6.3 Conversions) :

Sinon, si le nouveau type est non signé, la valeur est convertie par en ajoutant ou en soustrayant de manière répétée une valeur supérieure à la valeur maximale qui peut être représentée dans le nouveau type jusqu'à ce que la valeur soit dans la plage de le nouveau type

Qui est le seul auquel j'ai accès en ce moment. Peut-être que quelqu'un d'autre peut intervenir sur la question du standard. Le compilateur peut ne pas être conforme au standard...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X