2017-06-21 28 views
2

私はATTINY85用の非常に単純なI2Cビットバンギングライブラリーを持っています。I2Cセンサーの値を読み取る(ビットバンギング)

#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に設定されていれば、タイミングも非常に優れています。

i2c_init(); 

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

足すには完璧に動作している間、私は私が後で読むことができる値を返すためにATTINY85と私のI2Cモジュールのいずれかを誘発することができるように見えることはできません。

ラズベリーとGY-521センサーを接続しました(内部アドレスが設定されていなくても値を返すので)。私は、センサデータの変化を見ることができます

Raspberry I2C output

:これは、オシロスコープで出力され

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'インジケータビットであるかどうかわからないので、別のアドレスを試しました。

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 

関係なく、私が使用しているもののアドレスに、センサーは単純に(oscioloscopeで)応答しないと、私はアドレスバイトを送信した後、SDAラインが高いまま。私は住所を送った後に別のstart()条件を追加しようとしましたが、運がまだありません。私が間違っているところのヒント?センサーをATTINY85読み取り要求に応答させたいので、後で値を読み取ることができます。ありがとう!

答えて

2

I2Cのチュートリアルを読んで、プロトコルの一般的な理解を得ることをお勧めします。たとえば、https://learn.sparkfun.com/tutorials/i2cを参照してください。つまり、I2Cはクロック線とデータ線を備えた2線マルチマスタバスです。どの通信でも、それが読取りであろうと書込みであろうと、マスタはクロック信号を供給します。あなたのi2c_write()はこれをSCLの遷移で実装します。

値を読み取るには、スレーブがデータを出力するために使用するクロックも供給する必要があります。時計なし、データなし。したがって、i2c書き込みと同様のi2c_read()を実装し、クロック遷移を生成し、各ビットを1つずつシフトさせる必要があります。

+0

"スレーブがデータを出力するためのクロックも供給する必要があります。それだった!どうもありがとうございました! – Kristian

2

スレーブがACKを送信しているかどうかを検出できるように、SDAラインを入力にする必要があります。 SDAラインを入力に設定するコードがないので、スレーブデバイスがデータを返すことはできません。あなたがSDAラインに乗せている価値は、スレーブが何をしようとしているのかを圧倒するかもしれません。また、データを読み戻すには、SDAが入力である間にSCLラインを動かすi2c_read関数を作成する必要があります。したがって、I2Cの実装は完全ではありません。 I2C spec from NXPを慎重に読んだり、より完全なビットバンギングI2C実装を参照として使用することができます。

+0

ありがとう、素晴らしい情報源!問題は私がスレーブにクロックを戻さないことであった。これでオシロスコープの値がわかりました。今問題があるのは、スレーブがSDAラインを「十分に硬い」状態にするのではなく、〜50%だけですが、プルダウン/プルアップ抵抗を使用して理解する限り、これを修正する必要があります。 – Kristian

+1

もしそれが50%だけ下に引っ張っているなら、おそらくあなたのコードがラインを高くしていると思われ、スレーブとマスターが戦っていることを意味します。私が私の答えで言ったように、あなたは* SDAラインをリリースしなければならず、スレーブがあなたに話を戻すことを可能にするためには、それを一定の時間に入力する必要があります。 –

+0

ヒントありがとうございました。私はSDAを入力として設定していませんでしたが、奇妙なことにPINBを使用して読み取ることができ、オシロスコープの値と比較することができました。あなたが50%の問題を解決することを示唆したように、それを入力として設定することによって! – Kristian

関連する問題