期望从设备确认并返回数据,但事实并非如此。 This is my protocol。 This 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 */
}
答案 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字符串。 itoa
(AVR 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/,但存在多个供应商和/或开放项目。