Why am I only receiving the first address byte? (I2C Protocol)

白昼怎懂夜的黑 提交于 2019-12-20 03:52:43

问题


Expecting the slave to ACKnowledge and return data, but it does not. This is my protocol. This is my Datasheet

The datasheet mentions "The slave will answer by sending bytes with MSB first. Byte0 and byte1 contain the prediction value. All bytes are acknowledged by the master."

Edit: Source Library

Also FYI I'm on an Arduino Fio but I am not inheriting the Arduino library.

    #include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <uart.h>
#include <i2c_master.h>

#define LED PB5

#define I2C_READ 0x5A

char buffer[1];

//char data[9];
uint16_t val = 0;
uint8_t status = 0;


void getVal()
{
  if(i2c_start(I2C_READ))
    {
        uart_puts("Start ");

        val = ((uint8_t)i2c_read_ack())<<8; 
        val |= i2c_read_ack();

    status = ((uint8_t)i2c_read_nack());

      i2c_stop();

    } else
  {
        uart_puts("Error");

        i2c_stop();
    }
}

int main(void)
{
  init_uart(57600);
  i2c_init();

  DDRB = _BV(5);

    for(;;)
    {



        getVal();

        itoa(status, buffer, 10); //convert decimal to string base 10
        uart_puts(buffer);

  PORTB = 0xFF;
  _delay_ms(500);
  PORTB = 0x00;
  _delay_ms(500);
}
return 0;   /* never reached */

}


Edit Revised:

#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <uart.h>
#include <i2c_master.h>

#define LED PB5

#define I2C_READ 0x5A

char buffer[10];

//char data[9];
uint16_t val = 0;
uint8_t status = 0;


{
  if(!i2c_start(I2C_READ))
    {
        uart_puts("Error");

        i2c_stop();

    } else
    {
        uart_puts("Start ");
        i2c_start((IAQ_ADDR << 1) + 1); //i2c_start(0xB5);

        val = ((uint8_t)i2c_read_ack())<<8; 
        val |= i2c_read_ack();

        status = ((uint8_t)i2c_read_nack());

        i2c_stop();
    }
}

int main(void)
{
  init_uart(57600);
  i2c_init();

  DDRB = _BV(5);

    for(;;)
    {

      getVal();

            itoa(status, buffer, 10); //convert decimal to string base 10
            uart_puts(buffer);

      PORTB = 0xFF;
      _delay_ms(500);
      PORTB = 0x00;
      _delay_ms(500);
    }
    return 0;   /* never reached */
    }

回答1:


Difficult to tell without having details of the i2c library that is being used, but the one thing I'd be checking first is the i2c_start(I2C_READ).

The i2c address provided in the datasheet is 0x5a as you've put in your macro. But the first byte also contains the read/write flag as the least significant bit. The i2c_start() function has to be putting 0xb5 onto the bus (i.e. (0x5a << 1) + 1 for a read)

If i2c_start() is not, then your slave device is not actually being addressed and so won't ack.




回答2:


Your program has undefined behaviour. You have declared buffer as:

char buffer[1];

That's an array of one single character. The only null-terminated string you can possibly store there is empty string (i.e. where buffer[0] == '\0'). But you are using it to convert integers to strings.

You need to make the buffer large enough to hold the largest string you expect to store in it, including the terminator.




回答3:


I'm not sure what your root issue is here. What are the symptoms you are having? What kind of output do you have on your UART?

As others have said, your buffer variable is too small to hold anything of value as a C string. itoa (AVR libc entry) usually provides a null-terminated string, so you'll need to be at least big enough for all the characters as well as the null value. You may be having an issue overflowing the buffer, in which case you should have a simple solution.

Your use of uin8_t means you should be allocating enough space for the representation of up to 255. You need 3 characters to represent the full range, as well as one character for the null character. Change your code to read char buffer[4]; and see if that improves the issues you are having.

If the I2C protocol implementation is in error, that will be harder to diagnose without accurate information on where the error is. A logic analyser should help here if you have access to one.

EDIT:

I just took a look at the datasheet and your method of i2c_start(0x5A) with consecutive i2c_read_ack()s seems to be correct. However, based on your linked protocol, you are probably just seeing "Error" on your UART as i2c_start() returns 0 for a successful start transaction and you check if(i2c_start(I2C_READ)) when you should be testing for if(! i2c_start(I2C_READ)) in getVal().

You also seem to have some unnecessary uint8_t casts based on your linked i2c_master.c gist. I'd suggest just using the Arduino IDE if this really is an Arduino compatible board and see if you can get a simple I2C example to work with the sensor to prove out your access methodology.




回答4:


For I2C, it is very important to have pull-up resistors on both SDA and SCL pins. If these are not present, the bus will always read low or floating voltage. I do not know the AVR hardware enough to know how it would behave, but I would expect the "// check if the start condition was successfully transmitted" to fail if this is the case.

In general when developing for hardware like this, I do recommend to have a logic analyzer. It can help when you are blind to what the hardware bus actually does.

An example of such device is https://www.saleae.com/ ,but multiple vendors and/or open projects exists.



来源:https://stackoverflow.com/questions/36586465/why-am-i-only-receiving-the-first-address-byte-i2c-protocol

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!