OCFreaks!

Interfacing DHT11 & DHT22 Sensor with LPC1768

In this tutorial we learn how to interface DHT11 and DHT22 Humidity and Temperature sensor with ARM Cortex-M3 LPC1768 microcontroller. I had discussed basics of DHT11/DHT22 interfacing in my previous tutorial. Please go through it if you are new to DHTxx Humidity and Temperature sensors.

A quick recap of the communication process:

DHT11/DHT22 Data format:

Now, lets have a look at steps we need to implement for Programming DTH11/DHT22. Since only one DATA line(PIN) is used, we will use the same GPIO PIN first as OUTPUT to send START condition and then as INPUT to Receive data.

Steps required for DHT11/DHT22 Interfacing:

  1. Configure PIN to be used to communication as OUTPUT.
  2. Set the PIN O/P to LOW and wait for 18 milli-seconds.
  3. Configure the PIN as INPUT. The pull-up resistor will Pull the bus to HIGH.
  4. Wait until DHT responds and pulls the line to LOW after around 40 micro-seconds or else exit as timeout error.
  5. Next, check for 80us LOW followed by 80us HIGH from DHT. This condition denotes that DHT is ready to send data next.
  6. Now, check for 50us LOW followed by 26us to 28us HIGH denoting data bit ‘0’ or 50us LOW followed 70us HIGH denoting data bit ‘1’. Store the interpreted bit in an array. Repeat this for each of 40 bits.
  7. Extract the data bytes from array to record or display it. Optionally the checksum can be used to verify data integrity.
  8. Wait for at least 1 second before starting again to fetch new data.

Program for Interfacing DHT11/DHT22 with ARM LPC1768/LCP1769:

In this example we will use PIN P0.0 (marked as P9 on mbed board) for communication with DHT11 sensor. For DHT22 you just need to make a small change in code to display the decimal part. I leave that to the reader. If you are using the bare 4 pin sensor than make sure that DATA pin is pulled up using 4.7K or 10K resistor. If you are using PCB mounted sensor which has 3 pins then external pullup resistor is not required since it is already present on the PCB. Timer0 module is used for generating delay and measuring timing of responses given by DHTxx. You can go through LPC1768 timer tutorial for reference.

We will also use UART0 to send data back to PC and display it using software terminal. printf() has been targeted such that its output gets redirected to UART0. Checkout my tutorial on how to retarget printf() in keil and LPC1768 UART tutorial for more. The schematic for connections between DHT11 and LPC214x is as given below:

Before going through to source code, first lets go through some the functions used:

DHT11 Humidity & Temperature sensor Interfacing Source Code Snippet


/*(C) Umang Gajera - www.ocfreaks.com
DHT11 Humidity and Temperature Sensor Interfacing with LPC1768/LPC1769 Example Source Code for KEIL ARM
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
License : GPL.*/
#include <lpc17xx.h>
#include <stdio.h> //For retargeted printf() - https://www.ocfreaks.com/retarget-redirect-printf-scanf-uart-keil/
#include "ocf_lpc176x_lib.h" //contains initUART0(), initTimer0() & putc() to retarget printf()

#define LOW 0
#define HIGH 1
void printError(const char * str);
void checkResponse(unsigned int waitTimeUS, unsigned int margin, unsigned char pinValue);
char getDataBit(void);

#define DATA_PIN (1<<0) //Using P0.0 for data communication

int main(void)
{
	unsigned char dataBits[40] = {0};
	char dataBytes[5] = {0};
	
	initTimer0();
	initUART0();
	
	printf("OCFreaks.com - Interfacing DHT11 with LPC1768 Example.\n");
	
	while(1)
	{
		//STEP 1: Set pin to output HIGH which represents idle state
		LPC_GPIO0->FIODIR |= DATA_PIN;
		
		//STEP 2: Pull down pin for 18ms(min) to denote START
		LPC_GPIO0->FIOCLR |= DATA_PIN;
		delayUS(18000); //wait for 18ms
		
		//STEP 3: Pull HIGH and switch to input mode
		//pull-up will pull it HIGH after switching to input mode.
		LPC_GPIO0->FIODIR &= ~(DATA_PIN);
		
		//STEP 4: Wait between 20 to 40us for sensor to respond
		startTimer0();
		while((LPC_GPIO0->FIOPIN & DATA_PIN) != 0)
		{
			if(LPC_TIM0->TC > 40) break; //Timeout
		}
		unsigned int time = stopTimer0();
		
		if(time < 10 || time > 40) 
		{ 
			printError("Failed to communicate with sensor");
		}
		
		//STEP 5: Check for 80us LOW followed by 80us HIGH
		checkResponse(80,5,LOW);
		checkResponse(80,5,HIGH);
		
		//After this DHTxx sends data. Each bit has a preceding 50us LOW. After which 26-28us means '0' and 70us means '1'
		
		//STEP 6: Fetch data
		char data;
		for(int i=0; i < 40; i++)
		{
			data = getDataBit();
			
			if(data == 0 || data == 1)
			{
				dataBits[i] = data;
			}
			else printError("Data Error");
		}
		
		//STEP 7: Extract data bytes from array
		data = 0;
		for(int i=0; i<5; i++) // i is the BYTE counter
		{
			for(int j=0; j<8; j++) // j gives the current position of a bit in i'th BYTE
			{
				if( dataBits[ 8*i + j ] )
					data |= (1<<(7-j)); //we need to only shift 1's by ([BYTESZIE-1] - bitLocation) = (7-j)
			}
			dataBytes[i] = data;
			data = 0;
		}		
		
		printf("Humidity=%d%%, Temp=%d Deg. C\n",dataBytes[0], dataBytes[2]);
		
		//STEP8: Wait for atleast 1 second before probing again
		delayUS(1000000); 
	}
	//return 0;
}

void printError(const char * str)
{
	/*Print error and enter infinite loop to HALT program*/
	printf("%s\n",str);
	while(1);
}

void checkResponse(unsigned int waitTimeUS, unsigned int margin, unsigned char pinValue)
{
	int time = 0;
	int maxwait = waitTimeUS + margin;
	
	startTimer0();
	if(pinValue)
	{
		while(LPC_GPIO0->FIOPIN & DATA_PIN)
		{
			if(LPC_TIM0->TC > (maxwait)) break; 
		}
	}
	else
	{
		while( !(LPC_GPIO0->FIOPIN & DATA_PIN) )
		{
			if(LPC_TIM0->TC > (maxwait)) break; 
		}
	}
	time = stopTimer0();
	
	if(time < (waitTimeUS-margin) || time > maxwait) 
	{
		//printf("Error for wait=%d,margin=%d,pinVal=%d,time=%d\n",waitTimeUS,margin,pinValue,time);
		printError("checkResponse() Error"); //Out of range, including error margin
	}
}

char getDataBit(void)
{
	int time = 0;
	
	checkResponse(50,5,LOW); //Each data bit starts with 50us low
	
	startTimer0();
	while(LPC_GPIO0->FIOPIN & DATA_PIN)
	{
		if(LPC_TIM0->TC > 75)
		{
			return 2; //Error - Timeout for 50us LOW
		}
	}
	time = stopTimer0();
	
	if((time > (27-10)) && (time < (27+10))) //I am getting 21 for HIGH using my DHT11 sensor, so using higher margin
	{
		return 0;
	}
	else if((time > (70-5)) && (time < (70+5)))
	{
		return 1;
	}
	else 
	{ 
		return 2; //Error - Timeout for data pulse
	}
}

Here is a screenshot of the above example in action:

KEIL ARM uV5 Project for example given above @ DHT11 Interfacing with LPC1768 Example [Successfully tested on Keil uV5.23], Download Project Zip. You can find the HEX file inside objects folder.

Exit mobile version