Сохраните 2 байта от I2C Slave

борюсь с тем, что, вероятно, является простым фрагментом кода для копирования 2 байтов, полученных от подчиненного устройства I2C, в массив, чтобы затем я мог преобразовать его в INT и выполнить математические операции с данными.

Этот код успешно (согласно моему анализатору I2C) считывает 2 последовательных байта с одного адреса регистра на 16-битном АЦП.

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-битного регистра на АЦП. Мне нужно поместить их в массив или, в идеале, в 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++ = data ; но я не уверен, что он работает правильно, массив кажется пустым   -  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() кажется проблемной. Если вы хотите поместить эти данные в целочисленную переменную, вам нужно посмотреть порядок байтов сети и хоста. (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) для второго. Значение Value (согласно IAR) — «неизвестный или неоднозначный символ».   -  person Ralph    schedule 07.08.2019
comment
Теперь я показал «весь код», но это, вероятно, просто запутает людей, проблема в том, что я до сих пор не могу понять, как сохранить байты, чтобы я мог их вводить/масштабировать и т. д. Я подозреваю, что упускаю что-то простое.   -  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-битным целым числом, а функция I2C_Read_Register должна возвращать 16-битное целое число. Если поставить точку останова на *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 ;
}

В зависимости от порядков байтов вам также может потребоваться переключить порядок байтов:

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
Конечно, тогда попытка объединить два отдельных символа в целое число (для математической работы) не работает (используя стандартный сдвиг первого символа на 8 бит влево, добавление второго символа и т. д. (в IAR Workbench), но это уже другая история - person Ralph; 07.08.2019
comment
Вы можете попытаться привести значение к типу int перед сдвигом. - person Gerhardh; 07.08.2019