首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >读取I2C传感器值(比特转换)

读取I2C传感器值(比特转换)
EN

Stack Overflow用户
提问于 2017-06-22 04:20:33
回答 2查看 833关注 0票数 2

我有一个用于ATTINY85的非常简单的I2C bit-banging库。

代码语言:javascript
复制
#define PORT_SDA PB0
#define PORT_SCL PB2

#define SIGNAL_HIGH(PORT) PORTB |=  ( 1 << PORT )
#define SIGNAL_LOW(PORT)  PORTB &= ~( 1 << PORT )

void LED_ON(void);
void LED_OFF(void);

void i2c_init(void);
void i2c_start(void);
void i2c_read(void);
void i2c_stop(void);
void i2c_write(uint8_t byte);

void i2c_init()
{
    DDRB |= ( 1 << PORT_SDA );
    DDRB |= ( 1 << PORT_SCL );
}


void LED_ON( void )
{
    PORTB |= 0b00000010;
}


void LED_OFF( void )
{
    PORTB &= 0b111111101;
}


void i2c_start( void )
{
    SIGNAL_HIGH( PORT_SCL );
    SIGNAL_HIGH( PORT_SDA );
    SIGNAL_LOW(  PORT_SDA );
    SIGNAL_LOW(  PORT_SCL );
}


void i2c_stop( void )
{
    SIGNAL_LOW(  PORT_SCL );
    SIGNAL_LOW(  PORT_SDA );
    SIGNAL_HIGH( PORT_SCL );
    SIGNAL_HIGH( PORT_SDA );
}

void i2c_write(uint8_t byte)
{
    uint8_t bit;

    for ( bit = 0; bit < 0x08; bit++ )
    {
        if( ( byte << bit ) & 0x80 )
            SIGNAL_HIGH( PORT_SDA );
        else
            SIGNAL_LOW( PORT_SDA );

        SIGNAL_HIGH( PORT_SCL );
        SIGNAL_LOW( PORT_SCL );
    }

    SIGNAL_HIGH( PORT_SDA );
    SIGNAL_HIGH( PORT_SCL );
    SIGNAL_LOW( PORT_SCL );
} 

我能够成功地写入I2C,没有任何问题。我已经用SSD1306和LC2404B测试了这段代码,一切都很好,即使在VCC设置为4.2V的情况下也是如此。

代码语言:javascript
复制
i2c_init();

i2c_start();
    i2c_write( 0xA0 );
    i2c_write( 0x01 );
    i2c_write( 0x13 );
i2c_stop();

虽然写得很好,但我似乎不能用ATTINY85触发我的任何I2C模块来返回一个我以后可以读取的值。

我连接了raspberry和GY-521传感器(因为即使没有设置内部地址,它也会返回值)。我可以用raspberry检测传感器并从中读取一个值,方法如下:

代码语言:javascript
复制
i2cdetect -y 1

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --  


i2cget -y 1 0x68

0x02

这是示波器上的输出:

我可以看到传感器数据在变化。问题是,我似乎无法将相同的请求从ATTINY85复制到传感器。传感器根本不会对该值做出响应。我似乎不能理解第一个字节的最后一位是ACK还是“READ”指示符位,所以我尝试了不同的地址。

代码语言:javascript
复制
i2c_start();
i2c_write(  0b11010001 ); // address: 0xD1

i2c_start();
i2c_write(  0b11010000 ); // address: 0xD0

i2c_start();
i2c_write(  0b10100001 ); // address: 0xA1

i2c_start();
i2c_write(  0b10100000 ); // address: 0xA0

但无论我使用什么地址,传感器都不会响应(在示波器中),并且在我发送地址字节后,SDA线保持高电平。我还尝试在发送地址后添加另一个start()条件,但仍然没有成功。有没有提示我哪里错了?我只是想让传感器响应ATTINY85读取请求,以便稍后可以读取该值。谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-06-22 04:39:09

我建议阅读I2C上的一些教程,以便对协议有一个大致的了解。请参见https://learn.sparkfun.com/tutorials/i2c示例。

简而言之,I2C是一种具有时钟线和数据线的双线多主机总线。在任何通信中,无论是读取还是写入,主机都会提供时钟信号。您的i2c_write()通过SCL转换实现了这一点。

为了读回值,您还需要提供从机用来输出数据的时钟。没有时钟,就没有数据。因此,您需要实现一个类似于i2c写入的i2c_read(),它生成时钟转换,并一次移入每一位。

票数 2
EN

Stack Overflow用户

发布于 2017-06-22 12:29:29

您需要让SDA行作为输入,这样才能检测从机是否正在发送ACK。您没有任何代码来将SDA行设置为输入,因此从设备不可能向您发送任何数据;您放在SDA行上的值可能会压倒从设备正在尝试做的任何事情。要读回数据,您需要创建一个i2c_read函数,该函数在SDA作为输入时摆动SCL线。因此,您的I2C实现远未完成。您可以仔细阅读I2C spec from NXP,或者寻找更完整的I2C实现作为参考。

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

https://stackoverflow.com/questions/44685586

复制
相关文章

相似问题

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