2016-04-13 7 views
1

スレーブがデータを確認して返すことを期待していますが、そうではありません。 This is my protocolThis is my Datasheet最初のアドレスバイトしか受信できないのはなぜですか? (I2Cプロトコル)

は、データシートには言及し「スレーブは最初のMSBでバイトを送信することでお答えします。バイト0と 予測値を含んでいBYTE1。すべてのバイトはマスターによって確認されています。」

編集:Source Library

もFYI私は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

ハードウェア関連の問題は、ハードウェアを複製できないため、診断が不可能ではありません。また、ハードウェアが適切に動作する保証はありません。ヒント:Scope/LAを使ってバスをチェックしてください。 – Olaf

+0

データシートのローカルコピーにリンクしているようです。これは正しいか? https://ams.com/eng/content/.../file/iAQ-core_Datasheet_EN_v1.pdf –

+0

リンクを修正しました。ありがとうございます! – SensationSama

答えて

3

使用されているi2cライブラリの詳細がわからないと難しいですが、最初にチェックするのはi2c_start(I2C_READ)です。

データシートに記載されているi2cアドレスは、マクロに入力した通り0x5aです。しかし、最初のバイトには、最下位ビットとしての読み取り/書き込みフラグも含まれています。 i2c_start()でない場合i2c_start()機能(読み取り用すなわち(0x5a << 1) + 1)バスに0xb5を置く必要がある

は、その後、あなたのスレーブデバイスは、実際に取り組まれていないので、ACKではないでしょう。

+0

このシフトはいつ実装しますか?アドレスを変更するとエラーが発生します。 – SensationSama

2

あなたのプログラムの動作は未定義ました。 bufferを次のように宣言しました。

char buffer[1]; 

これは1文字の配列です。そこに格納できる可能性のあるヌル終了文字列は、空文字列(つまり、buffer[0] == '\0')です。しかし、それを使って整数を文字列に変換しています。

ターミネータを含めて、格納する予定の最大の文字列を保持するのに十分な大きさのバッファを作成する必要があります。

+0

ニースキャッチ。これは問題の最も可能性が高い部分でした。しかし、問題は解決しません。 – SensationSama

2

あなたの根本的な問題はここにありますか。あなたは何の症状がありますか? UARTにはどのような出力がありますか?

あなたのbuffer変数は、Cの文字列として価値のあるものを保持するには小さすぎます。 itoaAVR libc entry)は通常、ヌルで終了する文字列を提供するため、すべての文字とヌル値に少なくとも十分な大きさが必要です。バッファオーバーフローの問題がある可能性があります。その場合、単純な解決策が必要です。

uin8_tを使用すると、最大255の表現に十分なスペースを割り当てる必要があることを意味します。フルレンジを表すには3文字、ヌル文字には1文字が必要です。コードを変更してchar buffer[4];とし、それが問題を改善するかどうかを確認してください。

I2Cプロトコルの実装にエラーがある場合、エラーの正確な情報がないと診断が難しくなります。あなたが1つにアクセスできるなら、ロジックアナライザーがここで助けてくれるはずです。

EDIT:

私は、データシートを見ていたし、連続したi2c_read_ack() sのi2c_start(0x5A)のあなたの方法は正しいように思えます。しかし、あなたのリンクされたプロトコルに基づいて、i2c_start()0を返すので、getVal()if(! i2c_start(I2C_READ))をテストする必要があるときに、をチェックすると、UARTで「エラー」が表示されている可能性があります。

また、リンクされたi2c_master.c要点に基づいて、不要なuint8_tキャストがあるようです。私はArduino IDEを実際にArduino互換ボードにして、アクセス方法論を証明するセンサーで作業する簡単なI2Cの例が得られるかどうかを確認するだけで、Arduino IDEを使用することをお勧めします。

+0

uart_putsが90を返しています。私は「エラー」ではなく「開始」しています。 – SensationSama

+0

あなたの現在リンクされているソースライブラリは 'I2C_start(SLAVE_ADDRESS + I2C_READ);でI2Cトランザクションを開始するように指示していますので、0x5A(または90)でトランザクションを開始するには十分ではありません。 @Andrew Edgecombeに言及されているように、7ビットのアドレスを1ビット左にシフトし、読み込みに1を加える必要があります。 'I2C_start(0xB5)'を試してみてください。 0x5Aのみを使用すると、I2Cアドレス0x2D(45)に_write_しようとします。 – Sam

+0

サム、その呼び出しは機能しません。私はそれを働かせることができたが、その厄介な。最初に私はIF(i2c_start(IAQ_ADDR)){i2c_start((IAQ_ADDR << 1)+ 1);}を呼び出します。 – SensationSama

0

I2Cの場合、SDAピンとSCLピンの両方にプルアップ抵抗を付けることが非常に重要です。これらが存在しない場合、バスは常に低または浮動電圧を読み込みます。 AVRハードウェアがどのように動作するかを知るには十分ではありませんが、この場合は「//開始条件が正常に送信されたかどうかを確認してください」と期待して失敗します。

一般的に、このようなハードウェア用に開発する場合は、ロジックアナライザを使用することをお勧めします。ハードウェアバスが実際に何をするのか分からないときに役立ちます。

このようなデバイスの例はhttps://www.saleae.com/ですが、複数のベンダーやオープンプロジェクトが存在します。

+0

私はプルアップ抵抗を使用しています。ええ、ロジックアナライザが賢明かもしれません。 – SensationSama

関連する問題