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

时间:2016-04-13 00:32:52

标签: c avr i2c

期望从设备确认并返回数据,但事实并非如此。 This is my protocolThis is my Datasheet

数据表提到“从机将通过首先发送带有MSB的字节来回答。字节0和字节1包含 预测值。所有字节都由主机确认。“

修改: 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 */
    }

4 个答案:

答案 0 :(得分:3)

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

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

如果i2c_start()不是,那么您的从属设备实际上并未被寻址,因此不会被激活。

答案 1 :(得分:2)

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

char buffer[1];

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

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

答案 2 :(得分:2)

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

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

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

如果I2C协议实现出错,那么如果没有关于错误位置的准确信息,将难以诊断。如果您有权使用逻辑分析仪,逻辑分析仪应该在这里提供帮助。

修改

我刚看了一下数据表,i2c_start(0x5A)连续i2c_read_ack()的方法似乎是正确的。但是,根据您的链接协议,您可能只是在UART上看到“错误”,因为i2c_start()返回0表示成功的启动交易,并且当您应该进行测试时检查if(i2c_start(I2C_READ)) if(! i2c_start(I2C_READ))中的getVal()

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

答案 3 :(得分:0)

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

一般情况下,在开发这样的硬件时,我建议使用逻辑分析仪。当你对硬件总线实际上做的事情视而不见时,它会有所帮助。

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