我正在尝试与Teensy2.0中的BNO055突破板进行接口,但我在从BNO055中阅读时遇到了困难。它有不同的寄存器,您可以访问从芯片读取数据。首先,我只是尝试读取一些内部部分的I。不管我做什么,我似乎只得到了我在TWDR中的最后一个值。试着读一读似乎并不能填充它。这是我的主要内容:
void main(void) {
CPU_PRESCALE(CPU_16MHz);
init_sensor();
char buffer[50];
sprintf(buffer, "Chip ID: %X\n", read_address(0x00));
while(1) {
_delay_ms(20);
}
}这是我的BNO055.c:
#include "BNO055.h"
#include <avr/io.h>
// The breakout board pulls COM3_state low internally
#define DEVICE_ADDR 0x29
#define READ 0
#define WRITE 1
#define F_CPU 16000000UL
#define SCL_CLOCK 400000L
inline void start(void) {
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
while ( !(TWCR & (1<<TWINT)));
}
inline void stop(void) {
TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
while(TWCR & (1 << TWSTO));
}
void send_address(uint8_t w) {
TWDR = (DEVICE_ADDR<<1) | w ;
TWCR = (1 << TWINT) | (1<<TWEN);
while(!(TWCR & (1 << TWINT)));
}
uint8_t read(void) {
TWCR = (1 << TWINT) | (1 << TWEN);
while(!(TWCR & (1 << TWINT)));
return TWDR;
}
void write(uint8_t data) {
TWDR = data;
TWCR = (1 << TWINT) | (1<<TWEN);
while(!(TWCR & (1 << TWINT)));
}
uint8_t read_address(uint8_t addr) {
start();
send_address(WRITE);
write(addr);
stop();
start();
send_address(READ);
const uint8_t value = read();
stop();
return value;
}
void write_address(uint8_t addr, uint8_t value) {
start();
send_address(WRITE);
write(addr);
write(value);
stop();
}
uint8_t status(void) {
return TWSR & 0xF8;
}
void init_sensor(void) {
// Setup I2C
DDRD &= ~((1 << 0) | (1 << 1));
PORTD |= ((1 << 0) | (1 << 1));
TWBR = ((( F_CPU / SCL_CLOCK ) - 16) / 2);
TWSR = 0;
TWCR = ((1 << TWEN) | (1 << TWIE) | (1 << TWEA));
}发布于 2021-10-26 20:56:09
这个答案是按照这个答案写的before the code in the question was updated。如果不知道这一点,你就会困惑于这个问题是如何/为什么回答的。
您所遇到的基本问题是在不属于I2C启动条件和I2C停止条件的地方发出它们。START a STOP条件位于整个I2C事务的开始和结束处,而不是围绕每个单独的字节。
事务的数据部分总是完全由要读取的数据组成,或者完全由要写入的数据组成。因此,执行典型I2C设备的寄存器读取需要两个I2C事务。一个涉及写入注册地址,另一个涉及读取登记册的数据,如下所示:
[I2C-START] [WRITE(I2C-DEVICE-WRITING-ADDRESS)] [WRITE(REGISTER-ADDRESS)] [I2C-STOP]写事务是我们通知I2C设备我们想从.读取数据的寄存器。
[I2C-START] [WRITE(I2C-DEVICE-READING-ADDESS)] [READ(REGISTER-DATA)] [I2C-STOP]传递数据本身的读取事务。
第一站的最后一站可能会被省略,以创建一个“重复启动”(您可能不需要)。为了不混淆问题,我只想采用上述方案。
你现在拥有的更像是这样的:
[I2C-START] [WRITE(I2C-DEVICE-WRITING-ADDRESS)] [I2C-STOP]您有一个空的写transaction.
[I2C-START] [WRITE(REGISTER-ADDRESS)] [I2C-STOP]现在,尝试使用设备注册地址作为address
[I2C-START]总线I2C [WRITE(I2C-DEVICE-READING-ADDRESS)] [I2C-STOP]的事务。您已经启动了一个读取事务,但是如果您发布了一个READ.
[I2C-START] [READ(?)] [I2C-STOP],则没有读取后续的任何数据当您应该写入一个transaction).地址(用于读或写I2C地址)时,尝试读取
后者可能是您遇到最大麻烦的地方,也可能是您看到一个未改变的TWDR的原因;作为一个I2C主服务器,您永远不会像这样在开始条件下读取一个字节,因为这里总是有一个包含地址位的字节。
从代码的角度来看,您可能需要这样的内容:
uint8_t read_address(uint8_t addr) {
// The first transaction
// that tell the I2C device
// what register-address we want to read
start();
send_address(WRITE);
write(addr);
stop();
// The read transaction to get the data
// at the register address
// given in the prior transaction.
start();
send_address(READ);
const uint8_t r = read();
stop();
return r;
}..。其中,send_address()、write()和read()都不包含对start()或stop()的调用。
我确实测试了上面的代码,虽然不是在ATMega32U4上;我使用的是不同的AVR,它具有相同的TWI外围设备,而且我没有您的I2C设备。将start()和stop()移到正确的位置,在我的测试平台上确实带来了从非功能性到功能性的东西。所以,当我在上面的代码中说“类似的东西”时,我的意思是很多类似的。也许还有其他的bug,但这是主要问题。
https://stackoverflow.com/questions/69686195
复制相似问题