Stocați 2 octeți din I2C Slave

Luptându-mă cu ceea ce este probabil o bucată simplă de cod pentru a copia 2 octeți primiți de la un slave I2C într-o matrice, astfel încât să pot apoi converti la INT și să fac matematică asupra datelor.

Acest cod citește cu succes (conform analizorului meu I2C) 2 octeți consecutivi de la o adresă de registru pe un ADC de 16 biți.

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

Deci, probabil că atunci am nevoie de o matrice (unsigned char adcarray [2] pentru a colecta / stoca citirile rezultate, așa că am încercat -

*buf++ = data ;

adcarray[] = data ;

adcarray[] = buf ;

„Așteptam o expresie” înseamnă probabil că am nevoie de o formă de buclă for pentru a popula matricea la fiecare trecere, chiar dacă linia *buf este deja în interiorul unei bucle de numărare 2.

Asistență apreciată (C în IAR pe MSP430 și ADS1115 ADC). Cu respect, Ralph


c i2c
person Ralph    schedule 07.08.2019    source sursă
comment
Ce este adcarray sau Value - ați omis declarațiile pentru acele variabile.   -  person Chris Turner    schedule 07.08.2019
comment
Bună ziua Chris, Valoarea este valori de 2 x 8 biți citite consecutiv dintr-un registru de 16 biți de pe adc. Trebuie să le pun într-o matrice sau, în mod ideal, un INT.   -  person Ralph    schedule 07.08.2019
comment
Funcția preia deja un pointer și o valoare a lungimii unde urmează să fie stocate datele. De ce nu apelați acea funcție cu adresa matricei dvs.?   -  person Gerhardh    schedule 07.08.2019
comment
Vă rugăm să furnizați întotdeauna informații complete despre mesajele de eroare. Care este textul exact și pentru ce rând este raportat? Fragmentul nu face parte din funcția de mai sus. Vă rugăm să furnizați întotdeauna un program complet verificabil pentru a reproduce problema dvs.   -  person Gerhardh    schedule 07.08.2019
comment
Cum verifici dacă ai citit cu succes datele? Unde comparați valorile citite cu analizorul I2C?   -  person Gerhardh    schedule 07.08.2019
comment
Salut Gerhardh - Am adăugat adcdata[count] = data ; imediat după *buf++ = date ; dar nu sunt sigur că funcționează corect, matricea pare să fie goală   -  person Ralph    schedule 07.08.2019
comment
Am un analizor de stare logică ZeroPlus care îmi arată că cei 2 octeți sunt citiți corect, trebuie doar să-i stochez   -  person Ralph    schedule 07.08.2019
comment
Să ne continuăm această discuție în chat.   -  person Gerhardh    schedule 07.08.2019
comment
Îmi pare rău, voi reveni la tine, am alte probleme majore cu codul I2C   -  person Ralph    schedule 07.08.2019
comment
Dacă matricea are toate valorile zero, atunci funcția dvs. I2C_SDA_IS_HIGH() pare să fie o problemă. Dacă doriți să puneți aceste date în variabila Integer, ați dori să vă uitați în ordinea octeților a rețelei și a gazdei. (linux.die.net/man/3/ntohl)   -  person Sunil Shahu    schedule 07.08.2019
comment
Bună ziua Sunil, rețineți că nu este nimic în neregulă cu codul I2C, deoarece analizorul meu arată că cei 2 octeți sunt citiți în secvență și conțin valorile așteptate. Problema mea este cum pun acești 2 octeți într-o matrice sau int, astfel încât să pot efectua matematică etc. (numărul de compliment al lui 2)   -  person Ralph    schedule 07.08.2019
comment
Codul dvs. este încă destul de incomplet. Ce este Value? Ar trebui să conțină cei 2 octeți citiți de „I2CM_In. What's wrong with the content of Value”? Este diferit de ceea ce vezi în analizorul tău?   -  person Gerhardh    schedule 07.08.2019
comment
Da, foarte diferit, valorile afișate în analizor sunt 3E pentru primul octet și f) pentru al doilea. Valoarea Valoare (conform IAR) este „simbol necunoscut sau ambiguu”   -  person Ralph    schedule 07.08.2019
comment
Am arătat acum „tot codul”, dar este posibil să deruteze oamenii, problema este că încă nu îmi dau seama cum să salvez octeții, astfel încât să îi pot integra / scala etc. Bănuiesc că îmi lipsește ceva simplu.   -  person Ralph    schedule 07.08.2019
comment
unsigned char Value; Cum ar trebui să dețină 2 octeți?   -  person Gerhardh    schedule 07.08.2019
comment
I2C_Read_Register( ADC, 0x00 ) returnează 2 octeți (conform analizorului I2C), menținerea lor este problema pentru care caut o soluție.   -  person Ralph    schedule 07.08.2019
comment
Trebuie să adaug ceva după acest *buf++ = date pentru a stoca / păstra cei 2 octeți, dar nu știu ce (matrice, int etc nu par să funcționeze)   -  person Ralph    schedule 07.08.2019
comment
Valoarea este o alternativă de la presupusul cod de exemplu I2C al TI, nu este o surpriză pentru mine că nu funcționează cu mai mult de un octet.   -  person Ralph    schedule 07.08.2019
comment
Problema este că variabila reală din spatele buf este Value, care alocă doar un octet de memorie. Valoarea ar trebui să fie probabil o matrice sau un int de 16 biți, iar funcția I2C_Read_Register ar trebui să returneze un int de 16 biți. Dacă împingeți un punct de întrerupere la *buf++ = data ;, vedeți același lucru pe care îl vede analizatorul dvs.?   -  person yhyrcanus    schedule 07.08.2019
comment
Mulțumesc, dar rezolvat, un foarte simplu (deși dezordonat) dacă count = 0 sau dacă count = 1 (imediat după *buf++ = data), apoi stocați octetul asociat într-un caracter separat.   -  person Ralph    schedule 07.08.2019


Răspunsuri (1)


Dacă încercați să stocați datele într-o altă matrice cu funcția I2CM_In, o utilizați greșit.

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

Datele primite sunt deja stocate într-un buffer: buf. Este datoria ta să oferi un tampon care este potrivit pentru a stoca rezultatul.

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

Dacă doriți să citiți un registru cu 16 biți, nu puteți returna valoarea ca unsigned char. Trebuie să utilizați un tip de date capabil să dețină (cel puțin) 2 octeți.

Spunendu-i funcției că memoria tampon are 2 octeți, provocați și un comportament nedefinit.

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

În funcție de endianess, este posibil să fie necesar să comutați ordinea octeților:

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
Mulțumesc, ceea ce am folosit de fapt (deși destul de oribil) a fost - if (count == 0) { ADC_Value2 = data ; } if (număr == 1) { ADC_Value1 = data ; } - person Ralph; 07.08.2019
comment
Bineînțeles, atunci încercarea de a combina cele două caractere separate într-un int (pentru lucru la matematică) nu funcționează (folosind deplasarea standard a primului caracter 8 biți la stânga, adăugați al doilea caracter etc. (în IAR Workbench) dar asta este o altă poveste - person Ralph; 07.08.2019
comment
Ați putea încerca să turnați valoarea la int înainte de a schimba. - person Gerhardh; 07.08.2019