#freeze [[FrontPage]] 2008/10/20 からのアクセス回数 &counter; #contents エレキジャックNo.8の第2部ではI2Cを使って温度を測る例がありました。 ここでは、AVRlibを使ってこの例題を試してみることにします。 ** 回路 [#t1ae4edd] 今回テストする回路は、137Pの図2-1 #ref(I2C_cirkit.jpg); のMC9S08QG8CPBEをATmega88に置き換えた回路です。 ATmega88のデータシートから、各ピン番号は以下の通りです。 - TxDは、3番(左上から3番目) - RxDは、2番(左上から2番目) - SCLは、28番(右上から1番目) - SDAは、27番(右上から2番目) - VCCは、7番 - GNDは、8番 です。 温度ICであるLM73は、 - GNDは、2番 - VDDは、3番 - SCLは、4番 - SDAは、6番 です。 これをブレッドボードで配置したのが以下の写真です。 #ref(3.jpg); ISPの線も一緒にセットしたので、ちょっと見にくいですね! ** プログラム [#fb97dc41] I2Cのプログラムも、examples/i2cからコピーして、作ります。 メインのi2ctest.cは、以下のようになります。 #pre{{ #include "global.h" // include our global settings #include "uart.h" // include uart function library #include "rprintf.h" // include printf function library #include "i2c.h" // include i2c support #define I2C_ADDRS_LM73 (0x4C) #define CB_W (0) // send from master #define CB_R (1) // read by master int cmd=0; static u08 buf[2]; void initSensor(void) { rprintf("enter initSensor\r\n"); i2cInit(); buf[0] = 4; buf[1] = 0x60|0x80; i2cMasterSend(I2C_ADDRS_LM73<<1 | CB_W, 2, buf); buf[0] = buf[1] = 0; i2cMasterSend(I2C_ADDRS_LM73<<1 | CB_W, 2, buf); } void cmdTempRead(void) { long temp10; buf[0] = buf[1] = 0; i2cMasterReceive(I2C_ADDRS_LM73<<1 | CB_R, 2, buf); temp10 = buf[0]*256 + buf[1]; temp10 = temp10 * 10 / 128; rprintf(".M=%d\r\n", temp10); } void serCmdProc(char ch) { switch (ch) { case '\b': rprintf("\b \b"); break; case '\r': rprintf("\r\n"); if (cmd == 'M') cmdTempRead(); cmd = 0; rprintf("Command> "); break; case '\n': break; default: uartSendByte(ch); cmd = ch; } } int main(void) { int c=0; uartInit(); uartSetBaudRate(9600); rprintfInit(uartSendByte); rprintf("Hello World\n"); initSensor(); rprintf("Command> "); while(1) { while(!c) uartReceiveByte(&c); serCmdProc(c); c = 0; } return 0; } }} ここで、i2cMasterSend、i2cMasterReceiveのI2Cアドレスには、左に1ビットシフトした値を セットしていることに注意してください。 もし、インタラプトを使用しないのなら、i2cMasterSendNI、i2cMasterReceiveNIに置き換えて ください。 ** makefileの変更点 [#e1b12224] makefileは、以下の点を変更します。 - MCU = atmega88 - TRG = i2ctest - SRC = $(AVRLIB)/buffer.c $(AVRLIB)/uart.c $(AVRLIB)/rprintf.c $(AVRLIB)/i2c.c $(TRG).c の3カ所です。 ** 最初のつまずき [#a472a868] 最初、2cMasterSend、i2cMasterReceiveのI2Cアドレス指定を間違えており、 I2C_ADDRS_LM73をそのままアドレスとして渡していたので、何の値も帰ってきませんでした。 *** 問題の切り分け [#pfc71f21] そこで、何がわるいのか問題を切り分けることにしました。 - LM73の使い方 - I2Cの信号が正しくでているか 使用したLM73ははじめて使うデバイスなので正しく動作しているのかをMC9S08QG8CPBEを使った 例題でチェックすることにしました。 #ref(6.jpg); MC9S08QG8CPBEの開発環境であるUSBSPYDER08には、オンチップデバッグ機能があり、ステップ毎に 動作を確認することができます。 この結果LM73は正しく動いていることが確認できました。 次に、I2Cの信号がでているのかどうかです。 そこで、最後の手段としてオシロスコープで波形を見ることにしました。 #ref(5.jpg); のように1バイトの信号がでています。 しかし、LM73からは何も返ってきません。 *** 別のライブラリを使ってみる [#rb537065] 今度は、別のライブラリを使うことにしました。 http://www.eleki-jack.com/mycom2/avr/avri2c/ この結果、16進数で990Dの2バイトが返ってきますが、値は正しくありません。 そこで、再びオシロスコープでみると #ref(I2C_recieve_data.jpg); となり、最初の99は、LM73のアドレス(R)でその次に0D(温度の最初の1バイト)が 返ってきていることが分かりました。 *** 頭を冷やして! [#ea0063cc] そこで、最初のオシロスコープの画像と2番目の画像を比べてみるとアドレスビットが1ビット シフトしていることが分かります。 ''i2cMasterSend、i2cMasterReceiveのI2Cアドレスには、左に1ビットシフトした値をセットしなくてならない'' ことに気づきました。 ** 結論 [#g6735c51] AVRlibを使ってI2Cも非常に簡単に使えることが確認できました。 ** コメント [#u143c54a] この記事は、 #vote(おもしろかった[29],そうでもない[0],わかりずらい[0]) #vote(おもしろかった[29],そうでもない[0],わかりずらい[1]) 皆様のご意見、ご希望をお待ちしております。 #comment_kcaptcha