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

为什么我只收到第一个地址字节?(I2C协议),c,avr,i2c,C,Avr,I2c,期望从机确认并返回数据,但它没有 数据表中提到,从机将首先发送带有MSB的字节进行应答。字节0和字节1包含 预测值。所有字节都由主机确认 编辑: 另外,我在Arduino Fio上,但我没有继承Arduino库 #include <avr/io.h> #include <util/delay.h> #include <stdlib.h> #include <uart.h> #include <i2c_master.h> #de

期望从机确认并返回数据,但它没有

数据表中提到,从机将首先发送带有MSB的字节进行应答。字节0和字节1包含 预测值。所有字节都由主机确认

编辑:

另外,我在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 */
    }

您的程序具有未定义的行为。您已将缓冲区声明为:

这是一个由单个字符组成的数组。您可以存储的唯一以null结尾的字符串是空字符串,即缓冲区[0]='\0'。但您正在使用它将整数转换为字符串


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

您的程序具有未定义的行为。您已将缓冲区声明为:

这是一个由单个字符组成的数组。您可以存储的唯一以null结尾的字符串是空字符串,即缓冲区[0]='\0'。但您正在使用它将整数转换为字符串


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

如果没有正在使用的i2c库的详细信息,很难判断,但我首先要检查的是i2c_startI2C_READ


数据表中提供的i2c地址是您在宏中输入的0x5a。但第一个字节还包含读/写标志作为最低有效位。i2c_启动功能必须将0xb5放到总线上,即0x5a如果没有正在使用的i2c库的详细信息,很难判断,但我首先要检查的是i2c_开始读取


数据表中提供的i2c地址是您在宏中输入的0x5a。但第一个字节还包含读/写标志作为最低有效位。i2c_启动功能必须将0xb5放到总线上,即0x5a我不确定您的根本问题是什么。你有什么症状?您的UART上有什么样的输出

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

使用uin8_t意味着您应该分配足够的空间来表示多达255个。您需要3个字符来表示整个范围,空字符需要一个字符。将代码更改为读取字符缓冲区[4];看看这是否能改善你的问题

如果I2C协议的实现出现错误,如果没有关于错误位置的准确信息,就很难进行诊断。如果您可以访问逻辑分析器,那么逻辑分析器应该在这里提供帮助

编辑:

我刚刚看了一下数据表,您的i2c_start0x5A连续i2c_read_acks的方法似乎是正确的。然而,根据您的链接协议,您可能只是在UART上看到了错误,因为i2c_start为成功启动事务返回0,并且您应该在测试if时检查ifi2c_startI2C_READ!i2c_开始读取getVal中的i2c_


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

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

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

使用uin8_t意味着您应该分配足够的空间来表示多达255个。您需要3个字符来表示整个范围,空字符需要一个字符。将代码更改为读取字符缓冲区[4];看看这是否能改善你的问题

如果I2C协议的实现出现错误,如果没有关于错误位置的准确信息,就很难进行诊断。如果您可以访问逻辑分析器,那么逻辑分析器应该在这里提供帮助

编辑:

我刚刚看了一下数据表,您的i2c_start0x5A连续i2c_read_acks的方法似乎是正确的。然而,根据您的链接协议,您可能只是在UART上看到了错误,因为i2c_start为成功启动事务返回0,并且您在执行以下操作时检查ifi2c_startI2C_READ 我正在测试如果!i2c_开始读取getVal中的i2c_


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

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

一般来说,在为这样的硬件开发时,我建议使用逻辑分析仪。当您对硬件总线的实际功能视而不见时,它会有所帮助


此类设备的一个例子是,但存在多个供应商和/或开放项目。

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

一般来说,在为这样的硬件开发时,我建议使用逻辑分析仪。当您对硬件总线的实际功能视而不见时,它会有所帮助



此类设备的一个例子是,但存在多个供应商和/或开放项目。

抱歉,由于我们无法复制硬件,因此很难诊断与硬件相关的问题。此外,也不能保证您的硬件工作正常。提示:使用Scope/LA检查总线。看起来您已经链接到数据表的本地副本。这个看起来对吗?我修复了链接,谢谢!缓冲区大小为1,因此您的itoa溢出了缓冲区。很抱歉,硬件相关问题很难诊断,因为我们无法复制硬件。此外,也不能保证您的硬件工作正常。提示:使用Scope/LA检查总线。看起来您已经链接到数据表的本地副本。这个看起来对吗?我修复了链接,谢谢!缓冲区大小为1,所以您的itoa溢出了缓冲区。捕捉得不错。这很可能是问题的一部分。但问题依然存在。接得好。这很可能是问题的一部分。问题依然存在,尽管.uart\u put返回90。我得到的是“开始”而不是“错误”。您现在链接的源代码库要求使用I2C_startSLAVE_地址+I2C_READ;,启动I2C事务;,因此,0x5A或90不足以启动事务。正如@Andrew Edgecombe所提到的,您需要将7位地址左移1位,然后添加1进行读取。试试I2C_start0xB5,看看是否有帮助。仅使用0x5A会导致尝试写入I2C地址0x2D 45。Sam,该调用无效。我设法让它工作起来,但很尴尬。首先,我将IFi2c_startIAQ_ADDR{i2c_startIAQ_ADDR}称为IFi2c_start0x5A{i2c_start0xB5;}。这之所以有效,是因为回到我的初始点,i2c_start0x5A调用失败,返回值1,并导致您在C中输入if语句1 evalutes为true。这样就允许调用i2c_start0xB5,并且该调用实际起作用。如果要测试成功,则需要否定if条件i2c_启动函数。Sam,非常感谢您让我注意到这一点。但是,i2c_start0xb5本身不起作用。uart_puts返回90。我得到的是“启动”而不是“错误”。您现在链接的源库说使用i2c_startSLAVE_地址+i2c_READ;启动i2c事务,因此您的0x5A或90不足以启动事务。正如@Andrew Edgecombe所述,您需要将7位地址左移1位,然后添加1进行读取。请尝试I2C_start0xB5,看看是否有帮助。仅使用0x5A会导致尝试写入I2C地址0x2D 45。Sam,该调用不起作用。我成功地使其工作,但很尴尬。首先,我调用IFi2c_startIAQ_ADDR{i2c_startIAQ_ADDR所以你基本上已经完成了ifi2c_start0x5A{i2c_start0xB5;}。这之所以有效,是因为回到我的初始点,i2c_start0x5A调用失败,返回值1,并导致您在C中输入if语句1 evalutes为true。这样就允许调用i2c_start0xB5,并且该调用实际起作用。如果要测试成功,则需要否定if条件i2c_启动功能。Sam,非常感谢您提醒我这一点。但是,i2c_start0xb5本身不工作。我使用的是上拉电阻器。是的,逻辑分析仪可能是明智的。我使用的是上拉电阻器。是的,逻辑分析仪可能是明智的。我什么时候实现这个移位?更改地址会导致错误。我什么时候实现是否执行此移位?更改地址会导致错误。
char buffer[1];