Raspberry Pi_Kor_25.8.3 Digital DHT11 Humidity/Temperature Sensor 활용


Published Book on Amazon


All of IOT Starting with the Latest Raspberry Pi from Beginner to Advanced – Volume 1
All of IOT Starting with the Latest Raspberry Pi from Beginner to Advanced – Volume 2


출판된 한글판 도서


최신 라즈베리파이(Raspberry

Pi)로 시작하는 사물인터넷(IOT)의 모든 것 – 초보에서 고급까지 (상)

최신 라즈베리파이(Raspberry

Pi)로 시작하는 사물인터넷(IOT)의 모든 것 – 초보에서 고급까지 (하)


Original Book Contents


25.8.3  Digital DHT11 Humidity/Temperature Sensor 활용

 

25.8.3.1    sensor의 특징

 

여기서는 아래와 같이 DHT11 sensor와 다른 필요한 부품들을 조그마한 PCB에 통합한 모듈을 사용할 것이다. DHT11 sensor는 저항 타입의 습도 측정 부품과, NTC 온도 측정 부품, 그리고 고성능의 8 bit microcontroller가 장치되어 있으며 정밀한 digital 신호 출력을 보내준다.  DHT11 sensor는 원래 4개의 선이 있지만, 이 모듈은 3개의 선으로 되어 있다

No

Pin

기능

1

-

ground

2

+

power

3

S

Digital data line


그림 25‑21 Digital DHT11 Humidity/Temperature Sensor Module

 

다음과 같은 특징을 가지고 있다.

 

항목

내용

전압 범위

3.0V to 5.5V

측정범위

Humidity 20-90%RH Temperature  0~50

Output

4 pin single row

Accuracy

Humidity +-5%RH Temperature +-2

Resolution

Humidity  1%RH Temperature  1

Interchangeability

Fully Interchangeable

Long-Term Stability

<±1%RH/year

 


 

   자료 전송 방식

 

sensor MCU(Micro-controller-Unit) DHT11 사이에 통신과 동기화를 위해서 Single bus data format을 사용한다. 각각의 통신 프로세서는 4ms 동안 유지되고, 전송자료는 다음과 같이 총 50 bit가 전송된다.

    습도자료     -- 8 bit integral RH data + 8 bit decimal RH data +

    온도자료     -- 8 bit integral T data    + 8 bit decimal T data    +

    checksum    -- 8 bit check sum.

 

자료 전송이 정확하다면 check sum은 “8 bit integral RH data + 8 bit decimal RH data + 8 bit integral T data + 8 bit decimal T data” 결과의 lower 8 bit와 동일해야 한다.   

 

아래 그림은 MCU DHT11 사이의 자료 전송을 위한 전체적인 개념도 이다

e1


 


 

아래 그림은 MCU DHT11 간에 통신을 시작하고 동기화하는 단계의 DATA Pin의 상태를 보여준다. DATA pin의 기본 상태는 "HIGH"이다. MCU DHT11 사이의 통신이 시작되면, MCU는 적어도 18ms 이상 DATA pin "LOW" 상태로 끌어내린다. 이것을 "Start Signal"이라고 하고, DHT11가 전송 절차를 시작하도록 하는데 사용된다. 그런 다음 MCU 20-40us 동안 DATA pin "HIGH" 상태로 만들고, DHT11 response를 대기하게 된다.

e2

 

일단 DHT11 "Start Signal"을 감지하면, Response Signal”를 보내기 위해 DATA pin "LOW" 상태로 끌어 내려서 80us 동안 유지한다. 그런 다음 DHT11 DATA pin "HIGH" 상태로 올려서 80us 동안 유지하여 자료 송신을 준비하고 있음을 알린다.  

 


 

자료는 bit 단위로 전송하는데, 모든 전송은 50us 동안의 "LOW" 전압 신호로 시작해서 일정시간의 "HIGH" 전압 신호로 끝난다. "HIGH" 전압 신호의 유지 시간은 전송하는 bit가 “0” 이냐 “1”이냐에 따라 달라진다. bit 0” 자료는 "HIGH" 전압이 26-28us동안 지속되고, bit 1” 자료는 "HIGH" 전압이 70us 동안 지속된다. 아래 그림에서 왼쪽은 bit "0"의 신호이고, 오른쪽은 bit "1"의 신호를 나타낸다.


 


 

25.8.3.2    <WiringPi> library를 이용한 프로그램 작성 

 

여기서는 <WiringPi> Library를 사용하여 sensor의 자료를 처리해 보도록 할 것이다. 개발 언어는 C 언어를 사용할 것이다.

 

다음과 같은 프로그램을 작성하여 "sensor_temp_DHT11.c" 파일에 저장하도록 한다.

 

/*  Simple test program to test the wiringPi functions  DHT11 test  */

#include <wiringPi.h>

#include <stdio.h>

#include <stdlib.h>

#include <stdint.h>

#define MAXTIMINGS     85

#define DHTPIN             7

int dht11_dat[5] = { 0, 0, 0, 0, 0 };

 

void read_dht11_dat()

{

           uint8_t laststate  = HIGH;

           uint8_t counter              = 0;

           uint8_t j            = 0, i;

           float      f; /* fahrenheit */

 

           dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0;

 

           /* pull pin down for 18 milliseconds */

           pinMode( DHTPIN, OUTPUT );

           digitalWrite( DHTPIN, LOW );

           delay( 18 );

 

           /* then pull it up for 40 microseconds */

           digitalWrite( DHTPIN, HIGH );

           delayMicroseconds( 40 );

 

           /* prepare to read the pin */

           pinMode( DHTPIN, INPUT );

 

           /* detect change and read data */

           for ( i = 0; i < MAXTIMINGS; i++ )

           {

                      counter = 0;

                      while ( digitalRead( DHTPIN ) == laststate )

                      {

                                  counter++;

                                  delayMicroseconds( 1 );

                                  if ( counter == 255 )

                                  {

                                             break;

                                  }

                      }

                      laststate = digitalRead( DHTPIN );

                      if ( counter == 255 )

                                  break;

                      /* ignore first 3 transitions */

                      if ( (i >= 4) && (i % 2 == 0) )

                      {

                                  /* shove each bit into the storage bytes */

                                  dht11_dat[j / 8] <<= 1;

                                  if ( counter > 16 )

                                             dht11_dat[j / 8] |= 1;

                                  j++;

                      }

           }

 

           /* check

            * we read 40 bits (8bit x 5 ) + verify checksum in the last byte

            * print it out if data is good

            */

           if ( (j >= 40) &&

                (dht11_dat[4] == ( (dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3]) & 0xFF) ) )

           {

                      f = dht11_dat[2] * 9. / 5. + 32;

                      printf( "Humidity = %d.%d %% Temperature = %d.%d *C (%.1f *F)\n",

                                  dht11_dat[0], dht11_dat[1], dht11_dat[2], dht11_dat[3], f );

           }else  {

                      printf( "Data not good, skip\n" );

           }

}

 

int main( void )

{

           printf( "Raspberry Pi wiringPi DHT11 Temperature test program\n" );

           if ( wiringPiSetup() == -1 )

                      exit( 1 );

           while ( 1 )

           {

                      read_dht11_dat();

                      delay( 1000 ); /* wait 1 sec to refresh */

           }

           return(0);

}

 

위의 프로그램의 내용을 좀 살펴보면 다음과 같다.

    프로그램이 시작되면 먼저 "wiringPiSetup( )" 함수로 GPIO를 초기화한다

    "pinMode( )" 함수를 사용하여 wiringPi 기준 DHTPIN pin output으로 설정한다..

    "digitalWrite( )" 함수를 사용하여 먼저 "HIGH" 신호를 보내고 18ms 기다린 다음, 다시 "LOW" 신호를 출력하고 40ms 대기한다

    "pinMode( )" 함수를 사용하여 DHTPIN pin을 다시 input으로 설정한다.

    "digitalRead( )" 함수를 사용하여 pin의 값을 읽어서 상태가 변경되었는지를 확인하고, 상태가 변경되면 해당 값을 "dht11_dat[ ]" 변수에 저장한다.

    자료가 정확한지를 점검하고, 문제가 없으면 화면에 출력한다


 

작성된 프로그램을 compile하여 실행 파일을 만든다. compile을 할 때는 compiler <WiringPi> library를 참조할 수 있도록 아래와 같이 반드시 <wiringPi> library를 지정하도록 한다.

 

gcc -Wall -o sensor_temp_DHT11 sensor_temp_DHT11.c -l WiringPi

 

아래와 같이 compile에서 만들어진 실행 파일을 실행하여 제대로 작동하는지 확인한다. 모든 것이 잘되면 화면에 sensor의 값이 출력될 것이다.

 

sudo ./sensor_temp_DHT11


 

 


 

25.8.3.3    <RPi.GPIO> library를 이용한 프로그램 작성 

 

여기서는 <RPi.GPIO> library를 이용하여 sensor interface하는 방법에 대해서 설명한다.

 

프로그램 개발언어는 Python 3를 사용한다. 먼저 Python 3 IDLE를 시작하고, 아래와 같은 Python 프로그램을 작성하여 "sensor_temp_DHT11.py"에 저장한다.

 

import RPi.GPIO as GPIO

import time

 

def bin2dec(string_num):

    return str(int(string_num, 2))

 

GPIO.setmode(GPIO.BCM)

 

while True :

    data = []

 

    time.sleep(0.02)

    GPIO.setup(4,GPIO.OUT)

 

    GPIO.output(4,GPIO.HIGH)

    time.sleep(0.025)

    GPIO.output(4,GPIO.LOW)

    time.sleep(0.02)

 

    GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_UP)

#   time.sleep(0.02)

 

    for i in range(0,300):

        data.append(GPIO.input(4))

 

    bit_count = 0

    tmp = 0

    count = 0

    HumidityBit = ""

    TemperatureBit = ""

    crc = ""

 

    try:

# initial -- High

#        while data[count] == 1:

#            tmp = 1

#            count = count + 1

#

#  response -- Low

#        while data[count] == 0:

#            tmp = 1

#            count = count + 1

#

#  ready -- High

while data[count] == 1:

            tmp = 1

            count = count + 1

 

#  fetch 32 bit data

        for i in range(0, 32):

            bit_count = 0

 

#  bit start -- Low

            while data[count] == 0:

                tmp = 1

                count = count + 1

 

#  bit data -- High

            while data[count] == 1:

                bit_count = bit_count + 1

                count = count + 1

 

#  determin "0" or "1" by "High" count  --count <= 2 bit "0",  count > 3 -- bit "1"

            if bit_count > 3:

                if i>=0 and i<8:                             # 0 ~ 7 bit

                    HumidityBit = HumidityBit + "1"

                if i>=16 and i<24:                           # 16 ~ 23 bit

                    TemperatureBit = TemperatureBit + "1"

            else:

                if i>=0 and i<8:                             # 0 ~ 7 bit

                    HumidityBit = HumidityBit + "0"

                if i>=16 and i<24:                           # 16 ~ 23 bit

                    TemperatureBit = TemperatureBit + "0"

 

    except:

#       print ("ERR_Fetch Measurement")

#       exit(0)

        continue

 

# Fetch CRC

    try:

        for i in range(0, 8):

            bit_count = 0

 

#  bit start -- Low

            while data[count] == 0:

                tmp = 1

                count = count + 1

 

#  bit data -- High

while data[count] == 1:

                bit_count = bit_count + 1

                count = count + 1

 

#  determin "0" or "1" by "High" count  --count <= 2 bit "0",  count > 3 -- bit "1"

            if bit_count > 3:                  # bit 1

                crc = crc + "1"

            else:                              # bit 0

                crc = crc + "0"

    except:

#       print ("ERR_Fetch CRC")

#       exit(0)

        continue

 

    Humidity = bin2dec(HumidityBit)

    Temperature = bin2dec(TemperatureBit)

Checkcrc = bin2dec(crc)

 

    if int(Humidity) + int(Temperature) - int(Checkcrc) == 0:

        print ("Humidity:"+ Humidity +"%" + "\t Temperature:"+ Temperature +" C" + "\t CRC:"+ Checkcrc)

    else:

        print ("ERR_CRC Check")

 

continue

 

exit(0)

 


 

Terminal 화면에서 "sudo" 명령으로 다음과 같이 프로그램을 실행한다. 그러면 sensor에서 측정한 온도 값이 화면에 계속적으로 표시될 것이다.  

 

sudo  python  sensor_temp_DHT11.py


 


 

25.8.3.4    Raspberry Pi와 실시간 처리(real time processing)

 

위의 두 가지 사례를 보면 자료가 소실되는 경우가 있음을 알 수 있다. 이것은 Raspberry Pi가 실시간으로 실행되는 시스템이 아니기 때문이다. 프로그램에서 발생하는 delay가 정확하지 않기 때문에, 외부기기와의 연동에서 가끔 전송 실수가 발생할 수 있는 것이다.

 

C 언어는 보다 저수준의 개발언어이기 때문에 GPIO pin을 보다 직접적으로 통제할 수 있다. 따라서 앞의 C 언어 예제에서는 상대적으로 오류의 빈도가 적은 것을 알 수 있다.

 

이러한 오류 발생에 대한 우회적인 처리방법으로는 프로그램을 수정하여 프로그램을 여러 번 실행해서 정확한 값을 잡아 내도록 것이다.  

 


 

Leave a Reply