아두이노(Arduino) + DHT11 + 1602 LCD로 온습도 측정기 만들기

실생활 적용 아두이노 프로젝트! 아두이노로 다양한 프로젝트를 진행 할 수 있지만, 가장 간편하면서도 쉽게 접근할 수 있는 프로젝트는 아두이노를 활용한 온습도계를 들 수 있습니다. 물론 각 가정에는 기본적으로 온도계와 습도계는 탑재가 되어 있지만, 자기 스스로가 아두이노를 활용하여 온습도계를 만들수 있다는 것은 꽤 재밌는 일이 될꺼 같습니다. 이번 시간에는 아두이노 우노 보드에 온습도계 센서 및 1602 LCD를 붙여서 온습도계를 만드는 것에 대하여 정리해 보도록 하겠습니다.

준비물

아두이노 우노 1 EA

가장 먼저 준비해야 될 것은 아두이노 우노 보드입니다. 사진의 아두이노 우노는 정품이지만, 가격이 저렴한 아두이노 우노 호환 제품을 사용해도 됩니다. 실제 사용하는데에는 정품과 호환제품이 거의 차이가 없으므로 비교적 가격이 저렴한 호환제품을 준비해도 상관 없습니다.

온습도 센서 DHT11 1EA

온습도계를 만들기 위한 가장 필요한 부품인 DHT11 온습도계 센서입니다. DHT11은 온도와 습도의 변화에 따라서 센서의 저항이 달라지는 특성을 이용하여 온도와 습도를 측정하는 원리를 사용합니다. 측정값이 정확하지는 않지만 간단하게 가정이나 테스트 용도로 사용하기에는 괜찮은 센서이고 시중에서 1천원 정도의 가격으로 구입이 가능합니다. 

측정범위는 온도는 0~50 ºC 사이, 습도는 20~90 % 정도로 측정이 가능합니다. DHT11의 연결 핀은 총 4개인데, 1개는 NC(Not Connect)이고 VCC, GND, DATA 에 각각 연결하면 사용할 수 있습니다.

위 그림은 DHT11의 구성도인데요, VCC, GND에 연결하고 나서 DATA는 아두이노의 Digital 핀에 연결하면 됩니다.

1602 i2c LCD 1 EA

온습도계의 측정 값을 표시하는데 필요한 부품입니다. 1602는 16글자를 2 Line으로 표시할 수 있다는 의미입니다.

최근에 아두이노가 출시되면서 덩달아 i2c 인터페이스를 사용하는 캐릭터 LCD 들이 출시가 되었는데요, i2c는 SCL, SDA의 2개 버스를 사용하기 때문에 사용과 연결이 간편한 특징이 있습니다. 예전에 8개 핀으로 연결해서 쓰던 기억이 떠오르네요. 최근에 출시되는 LCD들은 Data Line을 i2c로 변환해주는 모듈이 장착되어 출시가 되기때문에 연결이 매우 편리해 졌다고 볼 수 있습니다. 

시중에는 1602 i2c LCD는 3000 ~ 4000원 정도로 구입이 가능합니다. 워낙 중국 OEM 생산된 제품이 많기 때문에 제조사를 따로 구별하지 않고 사용하면 됩니다.




아두이노 USB 케이블 1 EA

아두이노 우노와 PC를 연결할때 쓰는 USB 케이블입니다. 펌웨어 다운로드 및 시리얼 통신이 필요하니 꼭 준비하시기 바랍니다.

브레드보드 (일명 빵판) 1 EA

브레드보드는 PCB에 납땜하여 구성하는데 번거롭기 때문에 사전에 아두이노 우노와 각 부품들은 간편히 연결하여 테스트를 할 때 필요합니다. 브레드 보드 없이 연결하는것은 꽤 불편하니 시중에서 저렴하게 판매하는 작은 브레드 보드 한개정도 구입하여 사용하면 편리합니다. ( 아래 사진을 참고하세요. )

점퍼선 충분히

아두이노와 DHT11, 1602 i2c LCD를 연결하기 위한 점퍼선을 충분히 준비할 필요가 있습니다. 브레드 보드에 연결하려면 한쪽은 Male, 다른한쪽은 Female로 된 점퍼선을 충분히 준비하면 됩니다. 

7~12V 어뎁터 (옵션)

어뎁터는 온습도 소스를 컴파일 후 펌웨어를 올려논 후에 아두이노 단독으로 측정을 할 때 필요합니다. 물론 PC에서 USB 케이블을 연결하면 전원이 인가되어 아두이노가 동작하지만 PC를 껐을경우에는 아두이노에 전원이 인가가 안되겠죠? 어뎁터는 필요에 따라서 준비를 해도 되고 안해도 됩니다.

준비가 완료된 아두이노 온습도계 부품들의 모습입니다. 사진 왼쪽 상단에 브레드 보드에 아두이노 우노와 DHT11, 1602 i2c LCD를 연결한 모습입니다. 

구성도 

그럼 실제 아두이노 우노와 DHT11 온습도 모듈, 1602 i2c LCD을 어떻게 연결하는 구성도를 확인해 보겠습니다.

  • DHT11의 맨 왼쪽의 핀에는 아두이노의  3.3V VCC에 연결합니다. 2번째 핀에는 아두이노의 D2 핀에 연결합니다. 3번째 핀은 NC이고 4번째 핀에는 아두이노의 GND에 연결합니다.
  • 1602 i2c LCD의 VCC에는 아두이노의 5V에 연결합니다. GND에는 아두이노의 GND에 연결해줍니다. 1602 LCD에 따라서 핀맵이 틀릴 수 있으니 확인하고 나서 아두이노의 A4에 SDA를 연결합니다. 
  • 1602 i2c LCD의 SCL핀에 아두이노의 A5 핀에 연결합니다.

소스코드

#include <DHT11.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
 
byte i2cAddress = 0;
 
LiquidCrystal_I2C lcd(0x3f,16,2);
DHT11 dht11(2); // dht11 set pin 2
 
void initSerial() {
  Serial.begin(9600);
  while(!Serial);
 
  Serial.println("\nSerial init...");
}
 
byte getI2cDevices() {
  byte error, address, ret = 0;
  int nDevices;
  Serial.println("\ri2c device Scan...");
 
  Wire.begin(); // Start Search i2c devices
 
  nDevices = 0;
  for(address=1; address<127; address++) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    //Serial.println(error, DEC);
 
    if(error == 0) {
      Serial.print("I2c device found at address 0x");
      if(address<16) {
        Serial.print("0");      
      }
 
      Serial.print(address,HEX);
      Serial.println("!");
      nDevices++;
      ret = address;
    } else if (error == 4) {
      Serial.print("Unknown error at address 0x");
      if(address<16)
        Serial.print("0");
 
      Serial.println(address,HEX);      
    }
 
    delay(10);
  }
 
  if(nDevices == 0) {
    Serial.println("I2c devices not found");
    return 0;
  } else {
    Serial.println("Finish...");
    delay(1000);
    return ret;
  }
}
 
void initI2cDevices() {
  i2cAddress = getI2cDevices();
  if(!i2cAddress) {
    Serial.println("i2c found error! please check i2c hardware!");
  }
 
  Serial.print("I2c Device :");
  Serial.println(i2cAddress, HEX);
}
 
void initI2cLCD() {
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("System Start");
  delay(1000);
  lcd.clear();
}
 
void pLCD(char *string1, float temp, char *string2, float humi)
{
  lcd.setCursor(0,0);
  lcd.print(string1);
  lcd.print(temp);
  lcd.print(" C");
  lcd.setCursor(0,1);
  lcd.print(string2);
  lcd.print(humi);
  lcd.print(" %");
}
 
void setup() {
  initSerial();
  initI2cDevices();
  initI2cLCD();
 
}
 
void getDHT11()
{
  int err;
  float temp, humi;
 
  if((err=dht11.read(humi, temp)) == 0) {
    Serial.print("Temperature:");
    Serial.print(temp);
    Serial.print(", Humidity:");
    Serial.print(humi);
    Serial.println("%");
    pLCD("TEMP: ", temp, "HUMI: ", humi);
 
  } else {
    Serial.println("");
    Serial.print("Err no:");
    Serial.print(err);
    Serial.println("");
  }
 
  delay(DHT11_RETRY_DELAY);
}
 
void loop() {
  getDHT11();
 
}

설명(Description)

온습도계를 구현하기 위해서는 i2c, DHT11, LCD 라이브러리가 필요합니다. 아두이노 IDE에서 우선적으로 Wire 라이브러리를 추가하고, 아두이노 IDE의 라이브러리 매니저에서 DHT11과 LiquidCrystal_I2C 라이브러리를 설치하여 추가합니다.

위 예제 소스코드는 i2c Device Check 함수가 포함되어 있습니다. initI2cDevices()를 setup()에서 호출하면 아두이노 우노에 연결된 1602 i2c LCD의 Device address가 표시가 되게 됩니다. 만약에 i2c device를 찾지 못했다는 메시지가 출력되면 1602 LCD가 연결이 잘못된 것이므로 다시 연결상태를 확인해봐야 합니다. 만약 0x3f 라는 형태로 Device address가 발견되면, 아두이노에 1602 LCD가 정상적으로 연결된게 확인이 되므로, 위 소스코드의 7번째 줄의 LiquidCrystal_I2C 클래스의 변수에 i2c address를 넣어줍니다. 

DHT11은 8번째 라인에서 정의되어 있습니다. dht11(7) 이 D2 pin을 사용하겠다는 뜻입니다.

setup()에서는 시리얼 통신과 LCD를 초기화 해줍니다. loop() 함수에는 getDHT11()을 호출하고 있는데요, getDHT11() 에서는 DHT11에서 측정된 온도와 습도를 측정하면 그 값을 시리얼 화면과 LCD로 출력해주는 기능을 수행합니다. 시리얼과 LCD를 동시에 출력함으로써 LCD이 출력이 올바른지 확인할 수 있습니다. getDHT11()에서는 delay를 주고 있는데, DHT11_RETRY_DELAY는 대략 1초(1000)정도로 delay를 주면서 측정을 합니다.




출력 결과

LCD에 TEMP는 현재온도입니다. 지금이 더운 여름철이라 29 도를 가르키네요. HUMI는 현재 습도입니다. 에어콘을 켠 상태에서는 27 %를 가리키고 있는 중입니다. 비가 많이 왔던 얼마전에는 40% 정도가 측정이 되었는데, 실제 수치와는 약간 차이가 있는거 같습니다. 습도 측정 수치는 좀더 알아봐야 될꺼 같습니다.

궁금한점 있으면 댓글 남겨주세요^^

'코드도사(codedosa.com)'에는 쿠팡파트너스 등의 제휴링크가 포함되어 있으며 수수료를 제공받을 수 있습니다.