エレキジャックNo.8に、ナショナルセミコンダクタの温度センサーLM73が載った基板が付録についてきました。マイコンとはI2Cで通信します。
LM73基板です。

足とパスコン(0.1uF)をつけています。パスコンはつけなくても、基板の外(2pinと3pinの間)につけてもいいです。穴が開いているのでチップコンデンサでなくてもいいのですが、チップ部品のはんだづけの練習もかねてつけてみました。ちょっとななめってます。
pin配置です。エレキジャックにpin配置が載っていなかったので、データシートから写しました。
1 ADDR I2Cのslave addressを決めるpin。openで0b1001100になる
2 GND
3 Vdd 2.7~5.5V
4 SMBCLK I2CのSCL (要pull up)
5 #ALERT 範囲外出力
6 SMBDAT I2CのSDA (要pull up)
つなぐ必要があるのはGND(2pin)、Vdd(3pin)、SMBCLK(4pin)、SMBDAT(6pin)の4本です。内部レジスタに設定した範囲を超えるとALERT信号を出すことができますが、使わなければつながなくていいです。SMBCLKとSMBDATのpull up抵抗はエレキジャックのミッション2第1章では3.3kΩ、第2章では1kΩです。ちなみに第1章ではLM73をPICに、第2章ではHCS08につないでいます。
このところAVRづいているので、AVRにつないでみます。
I2C通信の参考にしたサイトです。
趣味の電子工作の部屋 by すん I2Cコントロール実験
AVR試用記 I2C通信
エレキジャック 1、2、3線シリアル・インターフェース
I2Cでマスターからスレーブにデータを送るには以下の手順になります。
(1) スタートビットを送る
(2) スレーブのアドレスとWを送る(SLA+Wといいます)。
(3) ACK/NAKをもらう
(4) データを送る
(5) ACK/NAKをもらう。必要なだけ(4)と(5)を繰り返す
(6) ストップビットを送る
I2Cでマスターからスレーブのデータを受け取るには以下の手順になります。
(1) スタートビットを送る
(2) スレーブのアドレスとRを送る(SLA+Rといいます)。
(3) ACK/NAKをもらう
(4) データを受信する
(5) ACKを返して、さらにデータをもらうために(4)に戻るか
NAKを返して、もうデータがいらないことを伝える
(6) ストップビットを送る
上の2つを組み合わせたパターンもあります。そのときは、受信時のスタートビットはリピーテッド・スタートと名前が変わります。また、上の手順ではエラーチェックをしていませんが、やたら細々とエラーチェックが必要になります。
ATMega88はTWIというI2Cのハードがついているので、レジスタをいじることでI2C通信ができます。全部ソフトで書くのよりは随分と楽になります。
実験している様子です。

上に見えているのがライター代わりの78K0付録基板(トラ技8月号)です。左側がRS232C通信用の秋月製FT232RL USBシリアル変換モジュールです。中央がAVR ATMega88で、右側が今回のLM73付録基板です。秋月で売っている小型温度計モジュール(通販番号M-01063)で温度を測っています。温度計の影になっていますが電源は3.3VのACアダプタです(実測3.5V)。
0.5秒毎に、LM73で測った温度データはI2CでATMega88に読み込まれてUSBシリアル変換モジュール経由でPCに送られます。
ソースです。<と>は全角になっています。
USART関連(usart_init、getch、putch)は前回と同じなので省略しました。
i2c関係は以下です。
i2c_init(初期化)、
i2c_start(スタートビットを送る)、
i2c_stop(ストップビットを送る)、
i2c_write(1バイト、マスター→スレーブ通信)、
i2c_read_ack(マスター←スレーブ通信とack返答)、
i2c_read_nak(マスター←スレーブ通信とack返答)
エラーを見つけたらi2c_errorに飛んで無限ループになります。
i2c_startは厳密には4種類考えられます(R/Wとstart, repeat start)が、たいへんなので1つにまとめています。
TeraTermで受信している様子です。

左側が受け取った生データで右側が換算した値です。27℃くらいです。
受信データは、16ビット中最上位が符号ビット、8ビットが整数部、7ビットが小数部になっています。11ビット精度のときは、符号1 + 整数部8 + 小数部2です。14bitだと小数部が5ビットに伸びます。
I2Cは、今回初めて使いました。なかなか複雑でデバッグがたいへんでした。
LM73基板です。

足とパスコン(0.1uF)をつけています。パスコンはつけなくても、基板の外(2pinと3pinの間)につけてもいいです。穴が開いているのでチップコンデンサでなくてもいいのですが、チップ部品のはんだづけの練習もかねてつけてみました。ちょっとななめってます。
pin配置です。エレキジャックにpin配置が載っていなかったので、データシートから写しました。
1 ADDR I2Cのslave addressを決めるpin。openで0b1001100になる
2 GND
3 Vdd 2.7~5.5V
4 SMBCLK I2CのSCL (要pull up)
5 #ALERT 範囲外出力
6 SMBDAT I2CのSDA (要pull up)
つなぐ必要があるのはGND(2pin)、Vdd(3pin)、SMBCLK(4pin)、SMBDAT(6pin)の4本です。内部レジスタに設定した範囲を超えるとALERT信号を出すことができますが、使わなければつながなくていいです。SMBCLKとSMBDATのpull up抵抗はエレキジャックのミッション2第1章では3.3kΩ、第2章では1kΩです。ちなみに第1章ではLM73をPICに、第2章ではHCS08につないでいます。
このところAVRづいているので、AVRにつないでみます。
I2C通信の参考にしたサイトです。
趣味の電子工作の部屋 by すん I2Cコントロール実験
AVR試用記 I2C通信
エレキジャック 1、2、3線シリアル・インターフェース
I2Cでマスターからスレーブにデータを送るには以下の手順になります。
(1) スタートビットを送る
(2) スレーブのアドレスとWを送る(SLA+Wといいます)。
(3) ACK/NAKをもらう
(4) データを送る
(5) ACK/NAKをもらう。必要なだけ(4)と(5)を繰り返す
(6) ストップビットを送る
I2Cでマスターからスレーブのデータを受け取るには以下の手順になります。
(1) スタートビットを送る
(2) スレーブのアドレスとRを送る(SLA+Rといいます)。
(3) ACK/NAKをもらう
(4) データを受信する
(5) ACKを返して、さらにデータをもらうために(4)に戻るか
NAKを返して、もうデータがいらないことを伝える
(6) ストップビットを送る
上の2つを組み合わせたパターンもあります。そのときは、受信時のスタートビットはリピーテッド・スタートと名前が変わります。また、上の手順ではエラーチェックをしていませんが、やたら細々とエラーチェックが必要になります。
ATMega88はTWIというI2Cのハードがついているので、レジスタをいじることでI2C通信ができます。全部ソフトで書くのよりは随分と楽になります。
実験している様子です。

上に見えているのがライター代わりの78K0付録基板(トラ技8月号)です。左側がRS232C通信用の秋月製FT232RL USBシリアル変換モジュールです。中央がAVR ATMega88で、右側が今回のLM73付録基板です。秋月で売っている小型温度計モジュール(通販番号M-01063)で温度を測っています。温度計の影になっていますが電源は3.3VのACアダプタです(実測3.5V)。
0.5秒毎に、LM73で測った温度データはI2CでATMega88に読み込まれてUSBシリアル変換モジュール経由でPCに送られます。
ソースです。<と>は全角になっています。
#include <avr/io.h> #include <util/twi.h> #include <util/delay.h> typedef unsigned char byte; // USART関連は省略 // 16進1桁出力 void puthex1(byte d) { d += '0'; if(d > '9') d += 'a' - '9' - 1; putch(d); } // 16進2桁出力 void puthex2(byte d) { puthex1(d >> 4); puthex1(d & 0x0f); } // 10進2桁出力 (x < 100のみ可) void putdec2(byte x) { putch('0' + x / 10); putch('0' + x % 10); } // エラー void i2c_error(void) { putch('['); puthex2(TWSR); putch(']'); // TWSRの内容 putch(0x0d); putch(0x0a); // 改行 PORTB = 0x01; // LED点灯 while(1) ; } // 通信速度の初期化 void i2c_init(void) { TWSR = 0b00000000; // 1分周 TWBR = 32; // 100k = 8MHz / (16 + 2 * TWBR * 1) } // master 1byte送信 void i2c_write(byte d) { TWDR = d; // 送信データ TWCR = _BV(TWINT) | _BV(TWEN); while( !(TWCR & _BV(TWINT)) ) ; // データの送出完了待機 if((TWSR & TW_STATUS_MASK) != TW_MT_DATA_ACK) i2c_error(); } // master 1byte受信(ackを返す) byte i2c_read_ack(void) { TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWEA); while( !(TWCR & _BV(TWINT)) ) ; // 受信完了待ち if((TWSR & TW_STATUS_MASK) != TW_MR_DATA_ACK) i2c_error(); return TWDR; // データを返す } // master 1byte受信(noackを返す) byte i2c_read_nak(void) { TWCR = _BV(TWINT) | _BV(TWEN); while( !(TWCR & _BV(TWINT)) ) ; // 受信完了待ち if((TWSR & TW_STATUS_MASK) != TW_MR_DATA_NACK) i2c_error(); return TWDR; // データを返す } // master送信開始、IDはslave address << 1 void i2c_start(byte id) { byte s; // 開始条件を送る TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); while( !(TWCR & _BV(TWINT)) ) ; // 開始条件の送出完了待機 s = TWSR & TW_STATUS_MASK; if(s != TW_START && s != TW_REP_START) i2c_error(); // アドレスを送る TWDR = id; TWCR = _BV(TWINT) | _BV(TWEN); while( !(TWCR & _BV(TWINT)) ) ; // アドレスの送出完了待機 s = TWSR & TW_STATUS_MASK; if(s != TW_MT_SLA_ACK && s != TW_MR_SLA_ACK) i2c_error(); } // master送信終了 void i2c_stop(void) { TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); while( !(TWCR & _BV(TWSTO)) ) ; // statusはTW_NO_INFOになる } #define LM73 (0x4c << 1) // LM73のslave address int main() { byte th, tl; DDRB = 0x01; PORTB = 0x00; usart_init(); i2c_init(); // LM73設定 i2c_start(LM73 | TW_WRITE); i2c_write(0x04); // register 4 i2c_write(0x60); // 14bit resolution i2c_stop(); // ポインタを0にしておく(readするだけで温度が読めるようになる) i2c_start(LM73 | TW_WRITE); i2c_write(0x00); // register 0 i2c_stop(); while(1){ // 温度受信 i2c_start(LM73 | TW_READ); th = i2c_read_ack(); // 上位読み込み tl = i2c_read_nak(); // 下位読み込み(最後はNAKを返す) i2c_stop(); // 結果出力 (マイナスは考えない) puthex2(th); puthex2(tl); putch(' '); putdec2(th << 1 | tl >> 7); // 結果出力 整数部 putch('.'); putdec2(((tl & 0x7f) * 200) >> 8); // 結果出力 小数部 putch(0x0d); // 改行 putch(0x0a); _delay_ms(500); // 0.5秒待つ } }
USART関連(usart_init、getch、putch)は前回と同じなので省略しました。
i2c関係は以下です。
i2c_init(初期化)、
i2c_start(スタートビットを送る)、
i2c_stop(ストップビットを送る)、
i2c_write(1バイト、マスター→スレーブ通信)、
i2c_read_ack(マスター←スレーブ通信とack返答)、
i2c_read_nak(マスター←スレーブ通信とack返答)
エラーを見つけたらi2c_errorに飛んで無限ループになります。
i2c_startは厳密には4種類考えられます(R/Wとstart, repeat start)が、たいへんなので1つにまとめています。
TeraTermで受信している様子です。

左側が受け取った生データで右側が換算した値です。27℃くらいです。
受信データは、16ビット中最上位が符号ビット、8ビットが整数部、7ビットが小数部になっています。11ビット精度のときは、符号1 + 整数部8 + 小数部2です。14bitだと小数部が5ビットに伸びます。
I2Cは、今回初めて使いました。なかなか複雑でデバッグがたいへんでした。
たまにサーミスタやLM35DZとか使って温度センサーを作りますが、そこいらじゅうの温度計を持って来ると、どれ一つとして同じ値を示さない(笑)。
http://hamayan.blog.so-net.ne.jp/2008-01-14
確かに何を測っているのか分からなくなってきます。測定器の一番大変な所は校正ですね。氷とか沸騰水といかホットプレート(!)なんて話もあるみたいですが、チップ形状になっていると、そういうわけにもいかないです。秋月の温度計より、ちょっと高めの数字が出ています。
とりあえずI2Cができるようになったので、何か他のアイテムも試してみようと思っています。その前にSPIかも。