Съхранявайте 2 байта от I2C Slave

борейки се с това, което вероятно е просто парче код за копиране на 2 байта, получени от I2C slave в масив, така че след това да мога да преобразувам в INT и да извършвам математически изчисления върху данните.

Този код успешно (според моя I2C анализатор) чете 2 последователни байта от един регистърен адрес на 16-битов ADC.

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

Така че вероятно след това имам нужда от масив (unsigned char adcarray [2] за събиране/съхранение на получените четения, така че опитах -

*buf++ = data ;

adcarray[] = data ;

adcarray[] = buf ;

„очакван израз“ вероятно означава, че имам нужда от някаква форма на for цикъл, за да попълвам масива при всяко преминаване, въпреки че редът *buf вече е вътре в цикъл count 2.

Помощта се оценява (C в IAR на MSP430 и ADS1115 ADC). Поздрави, Ралф


c i2c
person Ralph    schedule 07.08.2019    source източник
comment
Какво е adcarray или Value - пропуснали сте декларациите за тези променливи.   -  person Chris Turner    schedule 07.08.2019
comment
Здравей Крис, Стойността е 2 x 8 битови стойности, прочетени последователно от 16-битов регистър на ADC. Трябва да ги поставя в масив или в идеалния случай INT.   -  person Ralph    schedule 07.08.2019
comment
Функцията вече приема указател и стойност за дължина, където трябва да се съхраняват данните. Защо не извикате тази функция с адреса на вашия масив?   -  person Gerhardh    schedule 07.08.2019
comment
Моля, винаги предоставяйте пълна информация за съобщенията за грешка. Какъв е точният текст и за кой ред се съобщава? Фрагментът не е част от функцията по-горе. Моля, винаги предоставяйте пълна проверяема програма за възпроизвеждане на вашия проблем.   -  person Gerhardh    schedule 07.08.2019
comment
Как проверявате дали сте прочели успешно данните? Къде сравнявате отчетените стойности с I2C анализатора?   -  person Gerhardh    schedule 07.08.2019
comment
Здравей Герхард - добавих adcdata[count] = data; веднага след *buf++ = данни; но не съм сигурен, че работи правилно, масивът изглежда е празен   -  person Ralph    schedule 07.08.2019
comment
Имам анализатор на логическо състояние ZeroPlus, който ми показва, че 2-та байта се четат правилно, просто трябва да ги запазя   -  person Ralph    schedule 07.08.2019
comment
Нека продължим тази дискусия в чата.   -  person Gerhardh    schedule 07.08.2019
comment
съжалявам, ще се върна при вас, имам други големи проблеми с I2C кода   -  person Ralph    schedule 07.08.2019
comment
Ако масивът има всички нулеви стойности, тогава вашата функция I2C_SDA_IS_HIGH() изглежда е проблем. Ако искате да поставите тези данни в променлива Integer, бихте искали да разгледате реда на байтовете на мрежата и хоста. (linux.die.net/man/3/ntohl)   -  person Sunil Shahu    schedule 07.08.2019
comment
Здравейте Сунил, имайте предвид, че няма нищо лошо в I2C кода, тъй като моят анализатор показва, че 2 байта се четат последователно и те съдържат очакваните стойности. Проблемът ми е как да поставя тези 2 байта в масив или int, за да мога да извършвам математически изчисления и т.н. (числото на комплимент 2)   -  person Ralph    schedule 07.08.2019
comment
Вашият код все още е доста незавършен. Какво е Value? Трябва да съдържа 2 байта, прочетени от „I2CM_In. What's wrong with the content of Value“? Различно ли е от това, което виждате във вашия анализатор?   -  person Gerhardh    schedule 07.08.2019
comment
Да, много различни, стойностите, показани в анализатора, са 3E за първия байт и f) за втория. Стойността на стойността (според IAR) е „неизвестен или двусмислен символ“   -  person Ralph    schedule 07.08.2019
comment
Сега показах „целия код“, но това вероятно просто ще обърка хората, проблемът е, че все още не мога да разбера как да запазя байтовете, за да мога да ги int/мащабирам и т.н. Подозирам, че пропускам нещо просто.   -  person Ralph    schedule 07.08.2019
comment
unsigned char Value; Как това трябва да съдържа 2 байта?   -  person Gerhardh    schedule 07.08.2019
comment
I2C_Read_Register( ADC, 0x00) връща 2 байта (според I2C анализатора), задържането им е проблемът, за който търся решение.   -  person Ralph    schedule 07.08.2019
comment
Трябва да добавя нещо след това *buf++ = данни за съхраняване/задържане на 2-та байта, но не знам какво (масивите, целите и т.н. изглежда не работят)   -  person Ralph    schedule 07.08.2019
comment
Value е резервен вариант от предполагаемия I2C примерен код на TI, за мен не е изненада, че не работи с повече от един байт.   -  person Ralph    schedule 07.08.2019
comment
Проблемът е, че действителната променлива зад buf е Value, която разпределя само байт памет. Стойността вероятно трябва да бъде масив или 16-битово int, а функцията I2C_Read_Register трябва да върне 16-битово int. Ако поставите точка на прекъсване на *buf++ = data ;, виждате ли същото, което вижда вашия анализатор?   -  person yhyrcanus    schedule 07.08.2019
comment
Благодаря, но решено, много просто (макар и объркващо) ако count = 0 или ако count = 1 (непосредствено след *buf++ = data) тогава съхранете свързания байт в отделен символ.   -  person Ralph    schedule 07.08.2019


Отговори (1)


Ако се опитате да съхраните данните в друг масив с функцията I2CM_In, вие я използвате погрешно.

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

Получените данни вече се съхраняват в буфер: buf. Ваша работа е да осигурите буфер, който е подходящ за съхраняване на резултата.

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 бита, не можете да върнете стойността като unsigned char. Трябва да използвате тип данни, който може да съдържа (поне) 2 байта.

Като кажете на функцията, че буферът е с дължина 2 байта, вие също предизвиквате недефинирано поведение.

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

В зависимост от endiance може също да се наложи да превключите реда на байтовете:

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
Благодаря, това, което всъщност използвах (макар и доста ужасно) беше - if (count == 0) { ADC_Value2 = data; } ако (брой == 1) { ADC_Value1 = данни; } - person Ralph; 07.08.2019
comment
Разбира се, опитът за комбиниране на двата отделни знака в int (за математическа работа) не работи (използване на стандартно преместване на първия знак 8 бита вляво, добавяне на втори символ и т.н. (в IAR Workbench), но това е друга история - person Ralph; 07.08.2019
comment
Може да опитате да прехвърлите стойността към int преди преместване. - person Gerhardh; 07.08.2019