I2C Slave-dən 2 bayt saxlayın

I2C qulundan alınan 2 baytı seriala köçürmək üçün yəqin ki, sadə kod parçası ilə mübarizə aparıram ki, mən daha sonra INT-yə çevirə və verilənlər üzərində riyaziyyat həyata keçirə bilim.

Bu kod uğurla (I2C analizatoruma görə) 16 bitlik ADC-də bir registr ünvanından 2 ardıcıl baytı oxuyur.

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

Beləliklə, ehtimal ki, nəticədə oxunanları toplamaq / saxlamaq üçün bir sıra (imzasız char adcarray [2]) lazımdır, ona görə də cəhd etdim -

*buf++ = data ;

adcarray[] = data ;

adcarray[] = buf ;

'gözlənilən ifadə', ehtimal ki, hər keçiddə massivi doldurmaq üçün for loopunun hansısa formasına ehtiyacım olduğunu bildirir, baxmayaraq ki, *buf xətti artıq count 2 dövrəsinin içərisindədir.

Yardım yüksək qiymətləndirildi (MSP430 və ADS1115 ADC-də IAR-da C). Hörmətlə, Ralf


c i2c
person Ralph    schedule 07.08.2019    source mənbə
comment
adcarray və ya Value nədir - siz bu dəyişənlər üçün bəyannamələri tərk etmisiniz.   -  person Chris Turner    schedule 07.08.2019
comment
Salam Chris, Dəyər adc-də 16 bitlik registrdən ardıcıl olaraq oxunan 2 x 8 bit dəyərdir. Mən onları sıraya və ya ideal olaraq INT-yə yerləşdirməliyəm.   -  person Ralph    schedule 07.08.2019
comment
Funksiya artıq verilənlərin saxlanacağı bir göstərici və uzunluq dəyərini alır. Niyə həmin funksiyanı massivinizin ünvanı ilə çağırmırsınız?   -  person Gerhardh    schedule 07.08.2019
comment
Zəhmət olmasa həmişə səhv mesajları haqqında tam məlumat verin. Dəqiq mətn nədir və hansı sətir üçün məlumat verilir? Parça yuxarıdakı funksiyanın bir hissəsi deyil. Zəhmət olmasa probleminizi təkrar etmək üçün həmişə tam yoxlanıla bilən proqram təmin edin.   -  person Gerhardh    schedule 07.08.2019
comment
Məlumatları uğurla oxuduğunuzu necə yoxlayırsınız? I2C analizatoru ilə oxunan dəyərləri harada müqayisə edirsiniz?   -  person Gerhardh    schedule 07.08.2019
comment
Salam Gerhardh - Mən əlavə etdim adcdata[count] = data ; *buf++ = datadan dərhal sonra; lakin onun düzgün işlədiyinə əmin deyiləm, massiv boş görünür   -  person Ralph    schedule 07.08.2019
comment
Məndə 2 baytın düzgün oxunduğunu göstərən ZeroPlus məntiq vəziyyəti analizatorum var, sadəcə onları saxlamalıyam   -  person Ralph    schedule 07.08.2019
comment
bu müzakirəni söhbətdə davam etdirək.   -  person Gerhardh    schedule 07.08.2019
comment
üzr istəyirik, mən sizə qayıdacağam, I2C kodu ilə bağlı digər əsas problemlərim var   -  person Ralph    schedule 07.08.2019
comment
Massivin bütün sıfır dəyərləri varsa, I2C_SDA_IS_HIGH() funksiyanız problem kimi görünür. Bu məlumatları Tam dəyişənə qoymaq istəyirsinizsə, şəbəkə və hostun bayt sırasına baxmaq istərdiniz. (linux.die.net/man/3/ntohl)   -  person Sunil Shahu    schedule 07.08.2019
comment
Salam Sunil, qeyd edin ki, I2C kodunda səhv bir şey yoxdur, çünki mənim analizatorum 2 baytın ardıcıl olaraq oxunduğunu göstərir və onlar gözlənilən dəyərləri ehtiva edir. Mənim problemim odur ki, mən bu 2 baytı massiv və ya int-ə necə yerləşdirim ki, riyaziyyat və s. yerinə yetirə bilim (2-nin tərif nömrəsi)   -  person Ralph    schedule 07.08.2019
comment
Kodunuz hələ də natamamdır. Value nədir? O, 'I2CM_In. What's wrong with the content of Value' tərəfindən oxunan 2 baytdan ibarət olmalıdır? Analizatorunuzda gördüyünüzdən fərqlidirmi?   -  person Gerhardh    schedule 07.08.2019
comment
Bəli, çox fərqlidir, analizatorda göstərilən dəyərlər birinci bayt üçün 3E və ikinci üçün f) təşkil edir. Dəyərin dəyəri (IAR-a görə) "naməlum və ya qeyri-müəyyən simvoldur"   -  person Ralph    schedule 07.08.2019
comment
Mən indi "bütün kodu" göstərdim, lakin bu, insanları çaşdıra bilər, məsələ ondadır ki, baytları necə saxlamağı hələ də başa düşə bilmirəm ki, mən onları miqyaslandıra bilərəm və s. Mən sadə bir şeyi əldən verdiyimdən şübhələnirəm.   -  person Ralph    schedule 07.08.2019
comment
unsigned char Value; Bu necə 2 bayt tutmalıdır?   -  person Gerhardh    schedule 07.08.2019
comment
I2C_Read_Register( ADC, 0x00 ) 2 bayt qaytarır (I2C analizatoruna görə), onları saxlamaq mənim həll yolu axtardığım problemdir.   -  person Ralph    schedule 07.08.2019
comment
Mən bundan sonra bir şey əlavə etməliyəm *buf++ = 2 baytı saxlamaq/tutmaq üçün data, lakin nə bilmirəm (massivlər, ints və s. işləmir)   -  person Ralph    schedule 07.08.2019
comment
Dəyər TI-nin ehtimal edilən I2C misal kodundan bir geri dönüşdür, onun bir baytdan çox işləməməsi mənim üçün təəccüblü deyil.   -  person Ralph    schedule 07.08.2019
comment
Problem ondadır ki, buf arxasındakı faktiki dəyişən dir Value, yalnız bir bayt yaddaş ayırır. Dəyər yəqin ki, massiv və ya 16 bit int olmalıdır və I2C_Read_Register funksiyası 16 bit int qaytarmalıdır. Əgər kəsmə nöqtəsini *buf++ = data ; nöqtəsinə itələsəniz, analizatorunuzun gördüyü eyni şeyi görürsünüzmü?   -  person yhyrcanus    schedule 07.08.2019
comment
Təşəkkürlər, lakin həll olundu, çox sadə (qarışıq olsa da) əgər count = 0 və ya count = 1 (dərhal *buf++ = datadan sonra) olarsa, əlaqəli baytı ayrıca simvolda saxlayın.   -  person Ralph    schedule 07.08.2019


Cavablar (1)


Əgər məlumatı I2CM_In funksiyası ilə başqa massivdə saxlamağa cəhd etsəniz, ondan səhv istifadə edirsiniz.

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

Alınan məlumatlar artıq buferdə saxlanılır: buf. Nəticəni saxlamaq üçün uyğun bir tampon təmin etmək sizin işinizdir.

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

16 bitlik registr oxumaq istəyirsinizsə, dəyəri unsigned char kimi qaytara bilməzsiniz. Siz (ən azı) 2 bayt tuta bilən məlumat növündən istifadə etməlisiniz.

Funksiyaya buferin 2 bayt uzunluğunda olduğunu söyləməklə siz həm də qeyri-müəyyən davranışa səbəb olursunuz.

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

Endilikdən asılı olaraq bayt sırasını dəyişmək də tələb oluna bilər:

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
Təşəkkür edirəm, əslində istifadə etdiyim (kifayət qədər dəhşətli olsa da) - if (count == 0) { ADC_Value2 = data ; } əgər (count == 1) { ADC_Value1 = data ; } - person Ralph; 07.08.2019
comment
Əlbəttə ki, sonra iki ayrı simvolu bir int-ə birləşdirməyə cəhd etmək (riyaziyyat işi üçün) işləmir (standart yerdəyişmənin birinci simvolundan 8 bit istifadə edərək, ikinci simvolu və s. əlavə edin (IAR Workbench-də), lakin bu başqa hekayədir. - person Ralph; 07.08.2019
comment
Köçürməzdən əvvəl dəyəri int-ə köçürməyə cəhd edə bilərsiniz. - person Gerhardh; 07.08.2019