Stocker 2 octets de l'esclave I2C

aux prises avec ce qui est probablement un morceau de code simple pour copier 2 octets reçus d'un esclave I2C dans un tableau afin que je puisse ensuite les convertir en INT et effectuer des calculs sur les données.

Ce code lit avec succès (selon mon analyseur I2C) 2 octets consécutifs à partir d'une adresse de registre sur un ADC 16 bits.

void ADC_Initialise( void )
{
    _DINT() ;                              // disable all maskable interrupts

    I2C_SCL_HIGH() ;
    I2C_SCL_OUTPUT() ;
    I2C_SDA_HIGH() ;
    I2C_SDA_OUTPUT() ;

    I2C_Write_Register_3B( ADC, 0x01, 0xC0, 0x83) ;  // Write 2 bytes to ADC Config Register

    for(i=0; i < 10000; i++);

    I2C_Read_Register( ADC, 0x00 );      // Read the 2 byte ADC value

    for(i=0; i < 10000; i++);
    _EINT() ;                             // re-enable the interrupts
}

static unsigned char I2C_Read_Register( char Device_Address, char Register_Address )

{
    unsigned char Value ;

    I2CM_Start( ) ;

    if( I2CM_Out( Device_Address << 1 ) )    //send write control byte + chip address
        return 0 ;

    else if( I2CM_Out( Register_Address ) )  //send register number
        return 0 ;

    I2CM_Start( ) ;                          // Restart

    if( I2CM_Out(( Device_Address << 1 ) | 0x01 ))      //send read control byte + chip address
    return 0 ;

    I2CM_In( &Value, 2 ) ;                    //RJ  6.8.19 input 2 byte ADC value to 'buf'

//      return Value ;                          //rj placed after IC2M_In
    I2CM_Stop( ) ;

    return Value ;                              //rj placed after IC2M_Stop
}


static void I2CM_In( unsigned char* buf, int count )
{
    unsigned char data ;

    for( ; count--; )  // How do I store these 2 bytes in a char[] or INT
    {
            data = 0 ;
            I2C_SDA_INPUT() ;

        volatile unsigned int i = 0 ;

        for( ; i < 8 ; ++i )
        {
            //Set Clock High
            I2C_SCL_HIGH() ;              

            //shift the bit over
            data <<= 1 ;

            if( I2C_SDA_IS_HIGH() )
            {
                data |= 0x01 ;
            }
            //Set Clock Low
            brief_pause( 0x04 ) ;
            I2C_SCL_LOW() ;
        }
        //put the input data byte into the buffer, inc buffer pointer
        *buf++ = data ;

        //take sda to output ack
        I2C_SDA_OUTPUT() ;

        //Set Clock High
        I2C_SCL_HIGH() ;

        //Set Clock Low
        brief_pause( 0x04 ) ;
        I2C_SCL_LOW() ;
    }
}

Donc, j'ai probablement besoin d'un tableau (unsigned char adcarray [2] pour collecter/stocker les lectures résultantes, alors j'ai essayé -

*buf++ = data ;

adcarray[] = data ;

adcarray[] = buf ;

« attendu une expression » signifie probablement que j'ai besoin d'une forme de boucle for pour remplir le tableau à chaque passage, même si la ligne *buf est déjà dans une boucle de compte 2.

Assistance appréciée (C en IAR sur MSP430 et ADS1115 ADC). Cordialement, Ralph


c i2c
person Ralph    schedule 07.08.2019    source source
comment
Qu'est-ce que adcarray ou Value - vous avez omis les déclarations de ces variables.   -  person Chris Turner    schedule 07.08.2019
comment
Bonjour Chris, La valeur est constituée de valeurs de 2 x 8 bits lues consécutivement à partir d'un registre 16 bits sur l'adc. Je dois les mettre dans un tableau ou idéalement un INT.   -  person Ralph    schedule 07.08.2019
comment
La fonction prend déjà un pointeur et une valeur de longueur où les données doivent être stockées. Pourquoi ne pas appeler cette fonction avec l'adresse de votre tableau ?   -  person Gerhardh    schedule 07.08.2019
comment
Veuillez toujours fournir des informations complètes sur les messages d'erreur. Quel est le texte exact et pour quelle ligne est-il rapporté ? L'extrait ne fait pas partie de la fonction ci-dessus. Veuillez toujours fournir un programme complet vérifiable pour reproduire votre problème.   -  person Gerhardh    schedule 07.08.2019
comment
Comment vérifier si vous avez réussi à lire les données ? Où comparer les valeurs lues avec l'analyseur I2C ?   -  person Gerhardh    schedule 07.08.2019
comment
Bonjour Gerhardh - J'ai ajouté adcdata[count] = data ; immédiatement après le *buf++ = data ; mais je ne suis pas sûr que cela fonctionne correctement, le tableau semble vide   -  person Ralph    schedule 07.08.2019
comment
J'ai un analyseur d'état logique ZeroPlus qui me montre les 2 octets en train d'être lus correctement, il me suffit de les stocker   -  person Ralph    schedule 07.08.2019
comment
Laissez-nous poursuivons cette discussion dans le chat.   -  person Gerhardh    schedule 07.08.2019
comment
désolé je reviens vers vous, j'ai d'autres problèmes majeurs avec le code I2C   -  person Ralph    schedule 07.08.2019
comment
Si le tableau a toutes les valeurs nulles, votre fonction I2C_SDA_IS_HIGH() semble poser problème. Si vous souhaitez mettre ces données dans une variable entière, vous souhaitez examiner l'ordre des octets du réseau et de l'hôte. (linux.die.net/man/3/ntohl)   -  person Sunil Shahu    schedule 07.08.2019
comment
Bonjour Sunil, notez qu'il n'y a rien de mal avec le code I2C car mon analyseur affiche les 2 octets lus en séquence et ils contiennent les valeurs attendues. Mon problème est de savoir comment mettre ces 2 octets dans un tableau ou un entier pour pouvoir effectuer des calculs, etc. (numéro de complément de 2)   -  person Ralph    schedule 07.08.2019
comment
Votre code est encore assez incomplet. Qu'est-ce que Value ? Il doit contenir les 2 octets lus par 'I2CM_In. What's wrong with the content of Value` ? Est-ce différent de ce que vous voyez dans votre analyseur ?   -  person Gerhardh    schedule 07.08.2019
comment
Oui, très différent, les valeurs affichées dans l'analyseur sont 3E pour le premier octet et f) pour le second. La valeur de Value (selon IAR) est « symbole inconnu ou ambigu »   -  person Ralph    schedule 07.08.2019
comment
J'ai maintenant montré "tout le code", mais cela risque de dérouter les gens, le problème est que je n'arrive toujours pas à comprendre comment enregistrer les octets afin de pouvoir les intégrer/les mettre à l'échelle, etc. Je soupçonne qu'il me manque quelque chose de simple.   -  person Ralph    schedule 07.08.2019
comment
unsigned char Value; Comment est-ce censé contenir 2 octets ?   -  person Gerhardh    schedule 07.08.2019
comment
I2C_Read_Register( ADC, 0x00 ) renvoie 2 octets (selon l'analyseur I2C), les conserver est le problème pour lequel je cherche une solution.   -  person Ralph    schedule 07.08.2019
comment
Je dois ajouter quelque chose après cela *buf++ = data pour stocker/conserver les 2 octets, mais je ne sais pas quoi (les tableaux, les entiers, etc. ne semblent pas fonctionner)   -  person Ralph    schedule 07.08.2019
comment
La valeur est une solution de secours par rapport au supposé exemple de code I2C de TI, ce n'est pas une surprise pour moi qu'elle ne fonctionne pas avec plus d'un octet.   -  person Ralph    schedule 07.08.2019
comment
Le problème est que la variable réelle derrière buf est Value, qui n'alloue qu'un octet de mémoire. La valeur devrait probablement être un tableau ou un entier de 16 bits, et la fonction I2C_Read_Register devrait renvoyer un entier de 16 bits. Si vous placez un point d'arrêt à *buf++ = data ;, voyez-vous la même chose que votre analyseur ?   -  person yhyrcanus    schedule 07.08.2019
comment
Merci mais résolu, très simple (bien que compliqué) si count = 0 ou si count = 1 (immédiatement après *buf++ = data), puis stockez l'octet associé dans un caractère séparé.   -  person Ralph    schedule 07.08.2019


Réponses (1)


Si vous essayez de stocker les données dans un autre tableau avec la fonction I2CM_In, vous l'utilisez mal.

static void I2CM_In( unsigned char* buf, int count )
{
    unsigned char data ;

    for( ; count--; )
    {
        ....
        //put the input data byte into the buffer, inc buffer pointer
        *buf++ = data ;
    }
}

Les données reçues sont déjà stockées dans un tampon : buf. Il est de votre devoir de fournir un tampon adapté pour stocker le résultat.

static unsigned char I2C_Read_Register( char Device_Address, char Register_Address )
{
    unsigned char Value ;
...
    I2CM_In( &Value, 2 ) ;  // << Value is 1 byte!
...
  return Value ;
}

Si vous souhaitez lire un registre de 16 bits, vous ne pouvez pas renvoyer la valeur sous forme de unsigned char. Vous devez utiliser un type de données capable de contenir (au moins) 2 octets.

En indiquant à la fonction que le tampon fait 2 octets, vous provoquez également un comportement indéfini.

static uint16_t I2C_Read_Register( char Device_Address, char Register_Address )
{
    uint16_t Value ;
...
    I2CM_In( &Value, 2 ) ;
...
    return Value ;
}

En fonction du caractère final, vous devrez peut-être également changer l'ordre des octets :

static uint16_t I2C_Read_Register( char Device_Address, char Register_Address )
{
    uint8_t tmp_Value[2] ;
...
    I2CM_In( tmp_Value, 2 ) ;
    uint16_t Value;

#if MSB_FIRST
    Value = ((uint16_t)tmp_Value[0]) << 8 || tmp_Value[1];
#else // LSB_FIRST
    Value = ((uint16_t)tmp_Value[1]) << 8 || tmp_Value[0];
#endif
...
    return Value ;
}
person Gerhardh    schedule 07.08.2019
comment
Merci, ce que j'ai réellement utilisé (bien qu'assez horrible) était - if (count == 0) { ADC_Value2 = data ; } if (count == 1) { ADC_Value1 = data ; } - person Ralph; 07.08.2019
comment
Bien sûr, tenter de combiner les deux caractères séparés en un int (pour les travaux de mathématiques) ne fonctionne pas (en utilisant le décalage standard du premier caractère de 8 bits à gauche, ajoutez le deuxième caractère, etc. (dans IAR Workbench), mais c'est une autre histoire. - person Ralph; 07.08.2019
comment
Vous pouvez essayer de convertir la valeur en int avant de la décaler. - person Gerhardh; 07.08.2019