본문 바로가기
대한상공회의소 스마트팩토리 교육/IoT 디바이스 개발

[IoT 디바이스 개발] AVR(ATmega128A)«수업-22» : 온습도 센서(DHT11)

by 나는영하 2022. 3. 3.

※ 주의사항 

본 블로그는 수업 내용을 바탕으로 제가 이해한 부분을 정리한 블로그입니다.
본 내용을 참고로만 보시고, 틀린 부분이 있다면 지적 부탁드립니다!

감사합니다😁

 

안녕하세요!!

오늘은 아래와 같은 내용을 확인해보겠습니다.

 

온습도 센서

DHT11


1. 온습도 센서(DHT11) 

1-1. 온습도 센서 사양 및 특이사항

온습도 센서(좌) / 온습도 센서 회로도(우)

1) 사양

- 동작 전원 : DC 3.3V ~ 5.5V

- Data Value : 습도 16bit, 온도 16bit, CheckSum 8bit

- 오차 범위 : 습도 ±5%, 온도 ±2

※ 자세한 스펙은 해당 센서의 DataSheet 참고 요망

 

2) 특이사항 : 풀업저항

- 온습도 센서의 관련 회로도를 보면 센서의 신호핀과 MCU의 핀 사이에 풀업저항 존재

- 풀업저항으로 데이터나 신호를 전송할때는 LOW가 되고, 대기중일때는 HIGH 상태 유지

- 센서의 종류마다 내부에 풀업저항이 달려있을수도 있고, 외부적으로 사용자가 별도로 풀업저항을 결선해주어야 할 수 도 있음. (실습에 사용되는 센서는 위의 그림처럼 풀업저항이 부착되어 있다.)

 

3) 특이사항 : Data Format

- 온습도센서는 Single bus를 통해 한번에 40bit의 데이터를 전송한다.

- 40bit의 데이터 형식은 다음과 같다

→ 8bit 습도 정수형, 8bit 습도 소수형, 8bit 온도 정수형, 8bit 온도 소수형, 8bit 패리티 비트

- 습도 정수형 + 습도 소수형 + 온도 정수형 + 온도 소수형 = 패리티 비트(8bit)

→ ex) 0011 0101 + 0000 0000 + 0001 1000 + 0000 0000 = 0100 1110

 

1-2. 온습도 센서타임 차트(timing diagram)

Data Timing Diagram

- Host signal은 MCU에서 DHT11(센서)로 보내는 신호를 의미한다.

즉, 프로그래밍을 할때 해당 핀을 OUTPUT으로 주고 LOW와 HIGH의 신호를 주어야 함

- Signal from the machine은 DHT11에서 MCU로 보내는 신호를 의미하고, 풀업저항에 의해 신호가 없으면 HIGH, 신호가 있으면 LOW가 된다.

 

1) MCU의 START 신호

- 동기식 통신의 경우 HOST에서 보내는 신호가 길든 짧든 CLOCK 신호가 있어서 CLOCK 신호 이내에 신호만 존재하면

인식을 하는데, 비동기식 통신일 경우에는 해당 센서가 요구하는 정확한 시간을 맞추어 주어야 한다. (주기 중요!!)

- DHT-11에서는 18ms의 시작 신호를 요구한다. 

- DDR 명령어를 통해 OUTPUT으로 설정하고 LOW의 값을 18ms간 전송한 후 HIGH로 바꾸어 준다.

 

2) 응답 신호

- DHT-11이 MCU로부터 Start 신호를 받으면 위와 같은 주기를 가지는 신호를 다시 MCU로 보낸다.

- 80μs라는 주기가 정해져있기 때문에 MCU는 해당 주기만큼의 신호가 들어오는지 인식해야 한다.

- 아래의 실습 코드는 80μs의 정확한 주기를 측정하지 않았고, 신호가 LOW → HIGH → LOW가 되는지만 인식을 한다.

 

3) 데이터 전달 

- HIGH의 주기에 따라 Bit Data의 전송 값이 '0'과 '1'로 나뉜다.

- '0' : 26 ~ 28μs HIGH 신호

- '1' : 70μs HIGH 신호

- 한번에 5바이트(40비트)의 신호를 전송한다.

 

4) END 신호

- 50ms의 신호를 출력한다.

 

※ MCU에서 신호를 보낼때(START SIGNAL)는 해당 핀을 OUTPUT으로 설정하고, 신호를 받을때는 INPUT모드로 설정해야 한다.

 

 


 

2. 온습도 센서(DHT11) 동작 실습

2-1. 코드 설명 (오픈 소스)

1) 전처리문

#define F_CPU 16000000UL
#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
#include "clcd.h"
#include "i2c.h"

uint8_t RH_integral, RH_decimal, T_integral, T_decimal, CheckSum;
#define DDR_DHT11 DDRF
#define PORT_DHT11 PORTF
#define PIN_DHT11 PINF
#define DHT11_PIN 0

- F포트의 0번핀을 DHT-11의 신호를 받는 핀으로 사용한다.

- 5바이트(40비트)의 데이터를 1바이트씩 따로 저장하기 위해 5개의 변수를 선언한다.

 

2) 시작 신호, 응답 신호 함수부

void Request()
{
	DDR_DHT11 |= (1<<DHT11_PIN);
	PORT_DHT11 &= ~(1<<DHT11_PIN);
	_delay_ms(20);
	PORT_DHT11 |= (1<<DHT11_PIN);
}

void Response()
{
	DDR_DHT11 &= ~(1<<DHT11_PIN);
	while(PIN_DHT11 & (1<<DHT11_PIN));
	while((PIN_DHT11 & (1<<DHT11_PIN)) ==0);
	while(PIN_DHT11 & (1<<DHT11_PIN));
}

- 시작 신호는 DDR에서 OUTPUT모드로 설정하였고, 응답 신호는 INPUT모드로 설정하였다.

- 시작 신호는 LOW의 신호를 주고 20ms 딜레이 후 HIGH신호를 준다. 

- 응답 신호 부분은 DHT-11센서로 부터 신호를 받아야 하기 때문에 while문을 통해 해당 신호가 LOW와 HIGH가 될때 각각 while문을 탈출하도록 설정하였다.

- while(PIN_DHT11 & (1 << DHT11_PIN)); == while(PINF0)

즉, F포트의 0번 핀으로 들어오는 신호가 LOW일때 while문을 탈출한다.

(풀업저항에 의해 평상시에는 HIGH 신호가 들어오는것을 명심할 것!!)

 

3) 8비트 데이터 수신 함수부

uint8_t Receive_data()
{
	int data =0;
	for(int i =0; i < 8; i++)
	{
		while((PIN_DHT11 &(1<<DHT11_PIN))==0);
		_delay_us(30);
		if(PIN_DHT11 & (1<<DHT11_PIN))
		data = (data<<1) + 1;
		else
		data = (data <<1);
		while(PIN_DHT11 & (1<<DHT11_PIN));
	}
	return data;
}

- DHT-11에서 받는 5바이트의 신호중 8비트씩 끊어서 data라는 변수에 저장하는 함수부

- DHT-11에서 들어오는 신호의 HIGH 주기가 30μs보다 길면 '1' 짧으면 '0'을 저장한다.

 

4) Main 함수부

int main(void)
{
	char str[16];
	
	i2c_lcd_init();
	i2c_lcd_write_string("DHT11 Test...");
	_delay_ms(2000);
	i2c_lcd_goto_XY(0,0);
	i2c_lcd_write_string("Temp.   : ");
	i2c_lcd_goto_XY(1,0);
	i2c_lcd_write_string("Humidity: ");
	while(1){
		Request();
		Response();
		RH_integral = Receive_data();
		RH_decimal = Receive_data();
		T_integral = Receive_data();
		T_decimal = Receive_data();
		CheckSum = Receive_data();
		if((RH_integral + RH_decimal + T_integral + T_decimal) == CheckSum)
		{
			sprintf(str,"%d.%d C",T_integral, T_decimal);
			i2c_lcd_goto_XY(0,9);
			i2c_lcd_write_string(str);
			sprintf(str,"%d.%d %%",RH_integral, RH_decimal);
			i2c_lcd_goto_XY(1,9);
			i2c_lcd_write_string(str);
		}
		else
		{
			i2c_lcd_goto_XY(0,0);
			i2c_lcd_write_string("DHT11 ERROR");
		}
	}
	return 0;	
}

- 8비트의 데이터를 수신하는 함수부를 5개의 변수에 각각 저장한다.

(RH_integral, RH_decimal, T_integral, T_decimal, CheckSum)

- 4개의 변수를 더한 값과 1개의 패리티 비트를 저장한 변수를 비교해서 같으면 LCD에 습도와 온도를 출력하고, 다르면 오류가 발생했다는 문구를 출력한다.

- sprintf 함수를 통해 정수형 데이터를 문자열로 저장한다.

댓글