目次

温度湿度センサー処理

 温度と湿度のセンサーを1パッケージにまとめた
 デバイスDHT11を入手しました。



 ピン配置は、以下。



 湿度、温度をどうやって取得すればよいのかを考えます。

 電源を除いて、通信するためのピンは1本だけなので
 時間で、送信と受信の役割を入れ替えているはず。

 役割が入れ替わるとわかれば、次のタイミングチャートの
 意味が理解できました。



 どういうプロトコルになっているのかを、見ていきます。

 Arduinoは、送信側となり、論理レベルの'L'を規定時間与えて
 センサー側からデータを送ってくるように指示。

 データシートでは、論理レベルを'L'にするには、最低でも
 18msとあり、20msほど'L'を与えておけばよいことに。

 次に、センサー側が送信の役目をすることになります。

 Arduinoには、指示を理解したことを返します。
 このレスポンスをもって、ピンをセンサー側が
 使うことを宣言したことになります。

 センサー側は、レスポンスを'L'を83us、'H'を87us出力で
 Arduinoに確認した旨を伝えます。

 レスポンスを返してから、40ビットのデータをArduinoに
 出力して、情報伝送します。
 この情報の内訳は、以下。



 ビットが'1'か'0'かを決めておかないと、再生できないため
 次のように'L'を54usとして、'H'の時間を変えて'1'か'0'か
 を判断できるようにしています。



 ここまで理解できれば、楽をすることを考えます。

 センサーDHT11を扱うためのライブラリがないかを探してみます。

 複数のライブラリがありましが、その中からメソッドが
 使いやすそうなTroykaDHTを選択。



 このライブラリでは、湿度、温度の値を取得するために
 次のメソッドが用意されています。

 湿度と温度を取得するためのスケッチは、以下。

#include <MsTimer2.h>
#include <TroykaDHT.h>

#define OFF 0
#define ON  OFF+1

#define LED_BIT 5

#define PIN_DHT 8

DHT dht(PIN_DHT,DHT11);

void update_trigger();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void show_help();

char cmd ;
byte sindex ;
char sbuf[8] ;

boolean tflag ;
boolean uflag ;
boolean eflag ;

byte    xcnt ;

float humidity ;
float temperature ;
  
void setup()
{
  /* initialize port values */
  PORTB = 0x01 ;
  PORTC = 0x00 ;
  PORTD = 0x00 ;
  /* initialize port direction */
  DDRB = 0xff ;
  DDRC = 0x00 ;
  DDRD = 0xfe ;
  /* */
  Serial.begin(9600);
  show_help();
  crlf();
  rs_puts("DHT11 handling");
  crlf();
  /* flags */
  tflag = OFF ;
  eflag = OFF ;
  /* others */
  xcnt = 0 ;
  /* enable DHT */
  dht.begin();
  /* 500ms period */
  MsTimer2::set(500,update_trigger);
  /* enable */ 
  MsTimer2::start();
}

void loop()
{
  int hh ;
  int tt ;
  /* serial handler */
  if ( uflag == ON ) {
    /* clear flag */
    uflag = OFF ;
    /* get command */
    cmd = *(sbuf+0) ;
    /* help */
    if ( cmd == '?' ) { show_help(); }
    /* enable */
    if ( cmd == 'G' ) { eflag = ON ; }
    /* disable */
    if ( cmd == 'g' ) { eflag = OFF; }
    /* new line */
    crlf() ;
  }
  /* timer handler */
  if ( tflag == ON ) {
    tflag = OFF ;
    if ( eflag == ON ) {
      dht.read();
      if ( dht.getState() == DHT_OK ) {
        /* get values from sensor */
        humidity = dht.getHumidity();
        temperature = dht.getTemperatureC();
        /* convert */
        hh = (int)humidity ;
        tt = (int)temperature ;
        /* show */
        rs_puts("H => ");
        Serial.print(hh);
        rs_puts(" % : ");
        rs_puts("T => ");
        Serial.print(tt);
        rs_puts(" celcius");
        /* new line */
        crlf();
      }
    }
  }
}

void update_trigger()
{
  /* set flag */
  if ( (xcnt & 3) == 3 ) { tflag = ON ; }
  /* inrement */
  xcnt++ ;
  /* flashing */
  PORTB &= ~(1 << LED_BIT) ;
  if ( xcnt & ON ) { PORTB |= (1 << LED_BIT) ; }
}

void rs_putchar(char x)
{
  Serial.write(x);
}

void rs_puts(char *ptr)
{
  while ( *ptr ) {
    rs_putchar( *ptr );
    ptr++;
  }
}

void crlf()
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void show_help()
{
  rs_puts("? help")    ; crlf();
  rs_puts("G enable")  ; crlf();
  rs_puts("g disable") ; crlf();
}

/* receive interrupt */
void serialEvent()
{
  char ch;
  if ( Serial.available() > 0 ) {
    /* get 1 character */
    ch = Serial.read();
    /* store */
    *(sbuf+sindex) = ch ;
    /* increment */
    sindex++ ;
    /* judge */
    if ( ch == '\r' ) {
      sindex = 0 ; 
      uflag  = ON ;
    }
  }
}

 コマンドインタプリタを用意し、コマンドで
 湿度温度を2秒ごとに取得し、表示する動作
 を開始か停止させています。

 TeraTermでは、次のようになります。



 スケッチを描いて、端末で表示できたのではなく
 ライブラリ特有の作法を理解するまで時間がかかり
 ました。

 TroykaDHTライブラリでは、情報40ビットをreadで取得後
 湿度、温度に変換するメソッドを使い、浮動小数点形式
 に変換しています。

 作成スケッチの中では、次の部分がライブラリ特有の
 作法に従った処理。

      dht.read();
      if ( dht.getState() == DHT_OK ) {
        /* get values from sensor */
        humidity = dht.getHumidity();
        temperature = dht.getTemperatureC();
        /* convert */
        hh = (int)humidity ;
        tt = (int)temperature ;
        /* show */
        rs_puts("H => ");
        Serial.print(hh);
        rs_puts(" % : ");
        rs_puts("T => ");
        Serial.print(tt);
        rs_puts(" celcius");
        /* new line */
        crlf();
      }

 湿度は、小数点以下が0になっていますが
 温度は、小数点以下もあり有効数字をどこ
 にするのか考えるのが面倒なので、整数で
 表示しています。

 データシートでは、回路例も掲載されて
 いますが、プルアップ抵抗は不要。




 Arduinoは、ATmega168を使っているので
 入力に設定すると、内蔵プルアップ抵抗
 を使うことができるため、敢えて外部に
 プルアップ抵抗を用意しないで済みます。

 Arduinoで扱いやすいように、3ピンの
 ヘッダ、コネクタをつけました。




目次

inserted by FC2 system