首页
学习
活动
专区
圈层
工具
发布

I2C不读
EN

Stack Overflow用户
提问于 2021-10-23 07:57:52
回答 1查看 254关注 0票数 2

我正在尝试与Teensy2.0中的BNO055突破板进行接口,但我在从BNO055中阅读时遇到了困难。它有不同的寄存器,您可以访问从芯片读取数据。首先,我只是尝试读取一些内部部分的I。不管我做什么,我似乎只得到了我在TWDR中的最后一个值。试着读一读似乎并不能填充它。这是我的主要内容:

代码语言:javascript
复制
    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:

代码语言:javascript
复制
#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));
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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主服务器,您永远不会像这样在开始条件下读取一个字节,因为这里总是有一个包含地址位的字节。

从代码的角度来看,您可能需要这样的内容:

代码语言:javascript
复制
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,但这是主要问题。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69686195

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档