スポンサーリンク

こんにちは@eaxjpです。

気圧計に湿度も表示したかったので 湿温度センサーAM2321を使う事しました。
温度と湿度データの取得に成功したら今度はLPS331を使った気象計を
作ろうと思っています。

AM2321はI2C通信と、シリアル通信がありますが、
液晶とバスを共有できるのでI2cでつくりました。

また、データシートは中国語で英語版も無いので
【参考】デジタル 温度・湿度センサー AM2321 を制御する
を参考にしました。

情報があまり無いセンサーです。
温度・湿度センサーAM2321とLPS331

I2C通信でAM2321からデータを取得する方法

AM2321の書き込み用スレーブアドレスは0xB8
AM2321の読み込み用スレーブアドレスは0xB9
です。

最初にデバイスを休眠状態から復帰させます。
スタートコンディション
スレーブアドレス(0xB8)を送信
データ(0x00)を送信
ストップコンディション
データ(0x00)は無くても良いかもしれません。
次の処理まで800μS待ちます。

次にデータの読み取り命令を出します。
スタートコンディション
スレーブアドレス(0xB8)を送信
データ(0x03)を送信 レジスター・データの読み取り
データ(0x00)を送信 レジスタの先頭アドレス
データ(0x04)を送信 読みだすレジスタの数(湿度と温度の4バイト)
ストップコンディション

1500μS待ちます。

実際にデータを読み込みます。
スタートコンディション
スレーブアドレス(0xB9)を送信
30μS待ちます。
1バイト目を受信・ACKを返送
2バイト目を受信・ACKを返送
3バイト目を受信・ACKを返送
4バイト目を受信・ACKを返送
5バイト目を受信・ACKを返送
6バイト目を受信・ACKを返送
7バイト目を受信・ACKを返送
8バイト目を受信・NACKを返送
ストップコンディション

以上でI2C通信は終了です。

湿度は(3バイト目×256)+4バイト目 / 10で計算出来ます。
温度は(5バイト目×256)+6バイト目 / 10で計算出来ますが
5バイト目が、2の補数になっていて気温は氷点下の場合
気温がおかしくなるので

if(5バイト目 & 0x80){
気温 = (((5バイト目 & 0x7F)*256 )+ 6バイト目);
}else{
気温= ((5バイト目*256 )+ 6バイト目); //??
}

で変換します。

AM2321からはチェックサムも送信されますが、
今回は利用しませんでした。
秋月にあるデータシートにはチェックサムの計算方法も
載っていました。

AM2321から符号・気温・湿度を取得するソース

//getsdts 気温の符号を取得
//リターン:1=気温がマイナス 0=気温がプラス
//先にgetsdh()で湿度を取得する事。
int getsdts(){
int temps;
if(I2cbuff[5] & 0x80){
temps = 1;
}else{
temps = 0;
}
return(temps);
}

//getsdt 気温を取得
//リターン:気温 30℃の場合は300
//先にgetsdh()で湿度を取得する事。
unsigned short long getsdt(){
unsigned short long hu;
if(I2cbuff[5] & 0x80){
hu = (((I2cbuff[5] & 0x7F)*256 )+ I2cbuff[6]);
return(hu);
}else{
hu = ((I2cbuff[5]*256 )+ I2cbuff[6]);
return(hu);
}
}

 

//getsdh 湿度を取得
//リターン:湿度 80%の場合は800
unsigned short long getsdh(){

#define ACK 0x00 // ACK Signal
#define NACK 0x01 // NACK Signal
unsigned short long hu;

//AM2321を復帰させる
I2CStart();    //スタートコンディション
I2COut(0xB8);  //書き込み用スレーブアドレスを送信
I2COut(0x00);
__delay_us(800);
I2CStop();  // ストップコンディシ

//[AM2321]データ読み取り命令
I2CStart(); //スタートコンディション
I2COut(0xB8); // //書き込み用スレーブアドレスを送信
I2COut(0x03); // 0x03レジスター・データの読み取り
I2COut(0x00); // 読み取り開始する先頭アドレス
I2COut(0x04); // 読み取るバイト数
I2CStop(); // ストップコンディシ

__delay_us(1500); //AM2321待ち

//[AM2321]データの受信
I2CStart(); //スタートコンディション
I2COut(0xB9); //読み取り用スレーブアドレスを送信
__delay_us(30);

I2cbuff[1] = I2CRcv(ACK); //1バイト目を受信・ACK
I2cbuff[2] = I2CRcv(ACK); //2バイト目を受信・ACK
I2cbuff[3] = I2CRcv(ACK); //3バイト目を受信・ACK
I2cbuff[4] = I2CRcv(ACK); //4バイト目を受信・ACK
I2cbuff[5] = I2CRcv(ACK); //5バイト目を受信・ACK
I2cbuff[6] = I2CRcv(ACK); //6バイト目を受信・ACK
I2cbuff[7] = I2CRcv(ACK); //7バイト目を受信・ACK
I2cbuff[8] = I2CRcv(NACK); //7バイト目を受信・NACK
I2CStop(); // ストップコンディション

hu = ((I2cbuff[3]*256 )+ I2cbuff[4]) ; //??
return(hu);

あとがき

このソースを作って気圧計に組み込んで見ました。
気温はAM2321からも取得出来ますが、
そんなに違いが無かったのでSCP1000からのデータを表示しています。

ただ、プログラム領域が86%と
液晶にオリジナルキャラクターを表示させようとすると
コンパイルでリンカーのエラーでビルドに失敗するので
容量としてはぎりぎりみたいです。

ピンには空きが無いのでI2Cで測定データを送信出来る様に
したいと思います。

受信側はシリアルモニタもあるのでarduinoを使おうかと思います。
その為には電圧が違いのでレベル変換が必要なので
秋月で売っているI2Cバス用双方向電圧レベル変換モジュール
を使おうかと思います。

あと、LPS331との通信はなかなかうまく行きません。