为什么我只收到第一个地址字节? (I2C 协议)

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

期望从机确认和return数据,但它没有。 This is my protocol. This is my Datasheet

数据表提到“从机将通过先发送 MSB 字节来应答。Byte0 和 byte1 包含 预测值。所有字节均由主机确认。"

编辑: Source Library

另外,仅供参考,我使用的是 Arduino Fio,但我没有继承 Arduino 库。

    #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 */

}


编辑修订:

#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 */
    }

您的程序有未定义的行为。您已将 buffer 声明为:

char buffer[1];

这是一组单个字符。您可以存储的唯一以 null 结尾的字符串是 空字符串 (即 buffer[0] == '[=12=]' 的位置)。但是您正在使用它来将整数转换为字符串。

您需要使缓冲区足够大以容纳您希望在其中存储的最大字符串,包括终止符。

如果没有正在使用的 i2c 库的详细信息,很难判断,但我首先要检查的一件事是 i2c_start(I2C_READ)

数据表中提供的 i2c 地址是您在宏中输入的 0x5a。但是第一个字节还包含 read/write 标志作为最低有效位。 i2c_start() 函数必须将 0xb5 放到总线上(即 (0x5a << 1) + 1 用于读取)

如果 i2c_start() 不是,那么您的从属设备实际上没有被寻址,因此不会确认。

我不确定您的根本问题是什么。你有什么症状?你的 UART 有什么样的输出?

正如其他人所说,您的 buffer 变量太小,无法将任何有价值的东西保存为 C 字符串。 itoa (AVR libc entry) 通常提供一个以 null 结尾的字符串,因此您至少需要足够大以容纳所有字符以及 null 值。您可能遇到缓冲区溢出问题,在这种情况下,您应该有一个简单的解决方案。

您使用 uin8_t 意味着您应该分配足够的 space 来表示最多 255 个。您需要 3 个字符来表示整个范围,以及一个字符来表示空值特点。更改您的代码以阅读 char buffer[4]; 并查看是否可以改善您遇到的问题。

如果 I2C 协议实现有误,如果没有关于错误位置的准确信息,将很难诊断。如果您可以使用逻辑分析仪,应该会有所帮助。

编辑:

我刚看了数据表,你的 i2c_start(0x5A) 与连续 i2c_read_ack() 的方法似乎是正确的。但是,根据您的链接协议,您可能只是在 UART 上看到 "Error" 作为 i2c_start() returns 0 成功启动事务,然后检查 if(i2c_start(I2C_READ))当你应该在 getVal().

中测试 if(! i2c_start(I2C_READ))

根据您链接的 i2c_master.c 要点,您似乎还有一些不必要的 uint8_t 转换。我建议只使用 Arduino IDE 如果这真的是一个 Arduino 兼容板,看看你是否可以获得一个简单的 I2C 示例来使用传感器来证明你的访问方法。

对于I2C,在SDA和SCL引脚上都有上拉电阻是非常重要的。如果这些不存在,总线将始终读取低电压或浮动电压。我对 AVR 硬件的了解不足以了解它的行为方式,但如果是这种情况,我希望“//检查启动条件是否已成功传输”失败。

一般像这样的硬件开发时,我还是建议有一个逻辑分析仪。当您对硬件总线的实际功能视而不见时,它可以提供帮助。

此类设备的一个示例是 https://www.saleae.com/,但存在多个供应商 and/or 开放项目。