秋月電子でI2Cでデータの取得が出来るAM2321というセンサーが700円で販売され始めたので試してみました。
このデバイスでぐぐると皆さんアドレスを0xB8と言っているのでてっきり10bitアドレッシングなのかと思いましたが、説明書などを読んでみると、I2C的にはどう見ても0x5Cなんじゃないかと思うんですがどうでしょう? そもそもの説明書を書いた人間がI2Cをきちんと理解していないために間違えているのではないかと思うのですが。
(という自分もきちんと理解しているかといわれるとそうではないわけですが…)
しかも、このAM2321からデータを取得する場合などには特別な手順を踏まないといけないのでかなり面倒です。
(判ってしまえばそうですか、というだけなのですが)
というのは、このAM2321、アドレッシングした場合に自分が呼ばれたとしてもACKを返さずにNACKを返すことがあるので、デバイスが接続されているのかどうかを調べる場合には、普通にデータの取得などの手順を踏まないといけないのです。
(呼ばれたことが判るならACK返せよ、まったく…)
しかも、このデバイスに対して連続してデータを要求する場合、500ms位の間隔を空けないとまともにデータの取得が出来ません。 何か特殊用途的な、とりあえず作りました的な、なんだかなぁのデバイスでした。(まぁ取得できるデータは十分すぎますが)
以下のソースはGVC Rev.2を元に、とりあえずテストとして書き起こしているもの(Rev.3にする予定)の一部です。
○I2C スレーブデバイスをスキャン(7bitアドレッシングとして実施)
// I2C スレーブデバイスをスキャン(7bitアドレッシングとして実施。10bitアドレッシングの場合、最大アドレスは0x3FF=1024)
for (slave_addr = 1; slave_addr < 0x80; slave_addr ++)
{
PORT_RESULT_LED = LED_ON;
// スレーブアドレスが0x5Cなら、AM2321が繋がっているかもしれないので独自のテストをする(美しくない…)
if (slave_addr == 0x5C)
{
// バッファを初期化
memset((void *)buff_work, 0x00, sizeof(buff_work));
// AM2321に起きるようデータを投げる
i2c_write_test(slave_addr, AM2321_WAKEUP_MSG, 1);
// AM2321に湿度と温度のデータ要求を投げる
i2c_write_test(slave_addr, AM2321_GET_MSG, 3);
// AM2321から湿度と温度ほか、合計8バイトを受信する
i2c_read(slave_addr, buff_work, 8);
// 取得したデータの値が正しいなら
if (buff_work[0] == 0x03 && buff_work[1] == 0x04)
{
// I2Cスレーブ状態格納テーブルに格納
i2c_status_num ++;
i2c_status_tbl[i2c_status_num].address = slave_addr;
i2c_status_tbl[i2c_status_num].status = 'o';
}
}
// 対象アドレスで反応があるなら
else if (i2c_slave_check(slave_addr) == 1)
{
// I2Cスレーブ状態格納テーブルに格納
i2c_status_num ++;
i2c_status_tbl[i2c_status_num].address = slave_addr;
i2c_status_tbl[i2c_status_num].status = 'o';
}
PORT_RESULT_LED = LED_OFF;
}
○実際に湿度温度のデータを計算して取得する
// バッファを初期化
memset((void *)buff_work, 0x00, sizeof(buff_work));
// AM2321に起きるようデータを投げる
i2c_write_test(0x5C, AM2321_WAKEUP_MSG, 1);
// AM2321に湿度と温度のデータ要求を投げる
i2c_write_test(0x5C, AM2321_GET_MSG, 3);
// AM2321から湿度と温度ほか、合計8バイトを受信する
i2c_read(0x5C, buff_work, 8);
// 湿度の計算
humi_data = (buff_work[2] << 8) + buff_work[3];
humi_vol = humi_data / 10;
send_strdata("HUMI = ");
send_intdata(humi_data);
send_crlf();
// 温度の計算
// マイナスなら
if (buff_work[4] & 0b10000000)
{
temp_data = ((buff_work[4] & 0b01111111) << 8) + buff_work[5];
temp_vol = temp_data / 10;
}
// プラスなら
else
{
temp_data = (buff_work[4] << 8) + buff_work[5];
temp_vol = temp_data / 10;
}
send_strdata("TEMP = ");
send_intdata(temp_data);
send_crlf();