■家電制御用のデバイスをまた1つ作るつもりで、今はパーツを集めたり、制御ソフトのコーディングテストをぽつぽつと始めている状態。ターゲットにしているのは加湿器で、湿度センサの値によって加湿器をオンオフしたり、加湿器の重さから水の充填状態を把握できるようにすることが目的。湿度センサを載せたデバイスはすでに一つあるけれど、今度は加湿器の近くに置くので、また別のセンサを使う。最初に使ったのはTDKのセンサだけど、値段が高いので今回は比較的安いDHT11を使うことにした。
DHT11はデジタルセンサで、VCC, GND以外にデータ線が1本だけあればいい。ただし、クロックもないし、送受信は同一ラインで行われる。データ線はプルアップされていて、コントローラー側で電位をGNDに落とすとアサートとなり、その後センサー側から応答が40ビット戻される。ビット表現はPPMに似たやり方で、一旦データ線をGNDに落としたあと、VCCに戻し、そのVCCが続く時間で0と1を表現している。そのあたりはデータシートで。
SPIだとクロックをコントローラー側で起こせるので、読み出しタイミングは苦労しないけど、1-wireだとセンサーから返されるデータ線の状態を解析しなければならず、1手間増える。コントローラー側ではデータ線をGNDに落として一定時間たったあと、VCCに上げて、データ線の状態を読み続ける。AVRだとDDRでアウトプット、インプットを切り替えることになる。
一旦読み出した後、データ線がGNDに落ちるのを待機し、次にVCCに戻ったらVCCの状態が持続する時間を計測する。注意がいるのは、DHT11からのデータ線にあまり信用がおけない点で、データ送信の開始待ちや、終了待ちで無限ループ状態になってしまう可能性が大きいこと。だからタイムアウト動作は安全装置として必須になる。
やはり、クロックを持たないのがちょっと面倒で、コントローラーの動作クロックでタイミングは変わってしまう。とりあえず8MHzは十分なクロック数で、0と1の判別ができる。センサーからの応答を読み出すロジックは次のようにした。このロジックはコントローラーからのアサートが終わり、センサーからの信号待ちをするところから。GNDに落ちてからVCCに戻ったあと、VCCの状態がどれだけ続くかカウントしている。
ct = 0;
ctp = 0;
limit = 0;
f_loop = 0;
do{
DHT111_CHKBIT(ch);
limit++;
if(limit > 65536){
f_loop = 1;
break; //timeout
}
}while(ch != 0);
do {
do{
DHT111_CHKBIT(ch);
}while(ch == 0);
do{
DHT111_CHKBIT(ch);
ctp++;
if(ctp > 253){
f_loop = 1;
break; // timeout
}
}while(ch != 0);
slot[ct] = ctp;
ct++;
ctp = 0;
if(ct>41){
f_loop = 1;
}
}while( f_loop == 0);
データ線の状態推移を読み取った後でデータ変換する。上のロジックでカウントしたVCCの状態の数を閾値と比較して、長ければ'1'、短ければ'0'ビットにしています。データは全部で40ビット(5バイト)です。
j=0;
mask = 0b10000000;
data[0] = 0;
for(i=1;i<41;i++){
if(slot[i] > DHT111_BIT_THRESHHOLD){
data[j] |= mask;
}
mask /= 2;
if(mask == 0){
j++;
mask = 0b10000000;
data[j] = 0;
}
}
とりあえずこれで温度湿度データを取り出すことはできたのですが、DHT11から出てくるデータがなんか妙で、データシートによるとHumi(湿度)Integral 8bit, Decimal 8bit, Temp(温度)Integral 8bit, Decimal 8bit, Checksum 8bitとあるのですが、HumiもTempもDecimalは常にゼロが出てくる。Integral(整数値)だけでとりあえず役には立つので別に構わないと言えば構わないのですが、なんか今ひとつあてにならない感じが……。