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

期望奴隶确认并返回数据,但事实并非如此。 这是我的协议 。 这是我的数据表

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

编辑: 源库

另外,仅供我参加Arduino Fio,但我没有inheritanceArduino库。

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

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

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

如果i2c_start()不是,那么你的从设备实际上没有被寻址,所以不会确认。

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

 char buffer[1]; 

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

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

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

正如其他人所说,你的buffer变量太小,无法保存任何有价值的C字符串。 itoa ( AVR libc条目 )通常提供以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示例来使用传感器来certificate你的访问方法。

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

一般来说,在开发这样的硬件时,我建议使用逻辑分析仪。 当您对硬件总线实际执行的操作视而不见时,它可以提供帮助。

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