How to Interface DHT22 sensor with STM32
The DHT22 is a digital-output relative humidity and temperature sensor. It uses a capacitive humidity sensor and a thermistor to measure the surrounding air, and sends out a digital signal on the data pin. You can download the datasheet HERE.
We have already covered how to generate the delays in micro and nanoseconds using timer in STM32. Today we will utilise the delay in microseconds to interface the DHT22 temperature and Humidity sensor with STM32.
You can also check out the tutorial covering how to interface the DHT11 sensor with STM32.
If you are not able to get DHT11 or DHT22 values, Here is another method you can use. This one is unified for both the sensors. No setup needed for timer and all. Just select the data pin as output and you are done. you need to select the DHT TYPE in DHT.c. Download it from https://controllerstech.com/wp-content/uploads/2020/06/DHT_11_22_DWT.zip
The DHT22 uses one wire to communicate to the MCU. Therefore it is a very time sensitive device. Below are the timing diagrams from the DHT22 datasheet, used in different processes.
INITIALIZATION
Below the image shows the START condition.
Here the Black line is the signal from the microcontroller and the Grey line is the signal from the DHT22.
In order to initialise the sensor, we have to pull the data line LOW for at least 1ms, and pull it HIGH for around 20-40 us.
On receiving the start signal, DHT22 will indicate it’s presence by pulling the line low for 80us and than high for 80us.
NOTE:- You might need to connect pull-up resistance to the data line or else DHT22 will not be able to pull it HIGH.
To initialize the sensor, the steps are as follows:-
- Set the pin (data) as output.
- Pull the pin low and wait for > 1 ms.
- Pull the pin high and wait for 30 us.
- Release the pin by setting it as input.
DHT22 will now send the response as you can see in the figure above. To check the response, steps are as follows:-
- Wait for 40us.
- Check if the pin is low, than wait for 80 us. This will be a total delay of 120 us and the pin should be high now.
- Check if the pin is high. If it is, then the response is OK.
- Now wait for the pin to go LOW.
DATA Transmission
Now DHT22 will send 40 bits of data. Each bit’s transmission begins with low-voltage-level that last 50 us, the following high-voltage-level signal’s length decides whether the bit is “1” or “0“.
- If the length of high-voltage-level is around 26-28 us, the bit is “0“
- And if the length is around 70 us, than the bit is “1“
The 40 bits sent by DHT22 are as follows DATA = 8 bit integral RH data + 8 bit decimal RH data + 8 bit integral T data+8 bit decimal T data + 8 bit checksum
If the data transmission is right, checksum should be the last 8 bit of “8 bit integral RH data+8 bit decimal RH data+8 bit integral T data+8 bit decimal T data”.
Following are the steps to READ DATA from the sensor
- Wait for the pin to go HIGH.
- Wait for 40us. This is because the length of “0” bit is 26-28us, and if the pin is high after 40us, it indicates that the bit is “1”.
- write the respective values to the variable.
Connection & Configuration
Below is the image showing the connection between DHT22 and nucleo F446.
Since the DHT22 only uses 1 wire to communicate to the MCU, I have connected it to the pin PA1. The sensor is powered with 5V from the nucleo board itself.
NOTE:- You might need to connect pull-up resistor to the data line or else DHT11 will not be able to pull the line HIGH.
clock configuration
Below is the image showing the clock configuration in the cubeMX.
The system is clocked from the external 8MHz crystal and the HCLK is set to 50MHz. Note that the APB1 Timer clock is also at 50MHz. This is important because we will use the TIM6 to generate the delays in microseconds and the TIM6 is connected to the APB1 bus.
Timer Configuration
Below is the image showing the configuration of the TIM6.
Since the APB1 Timer clock is at 50MHz, we will use the prescaler of 50 to bring the TIM6 clock to 1 MHz. This is already explained in the tutorial which explains how to generate the delays in micro/nanoseconds.
The pin PA1 is set as output, this is where the DHT22 data pin is connected to.
I2C Configuration
We are using the LCD1602 to display the Temperature and Humidity data. The LCD is connected using the PCF8574 I2C extender. Below is the image showing the I2C configuration.
I am using the I2C1 to connect the LCD. The I2C is configured in the standard mode with the clock speed set to 100KHz. The pins PB8 and PB9 are configured as the SCL and SDA pins.
We have already covered how to interface the LCD via I2C with STM32. You can check out the tutorial for more details.
The CODE
INITIALIZATION
void DHT22_Start (void)
{
Set_Pin_Output(DHT22_PORT, DHT22_PIN); // set the pin as output
HAL_GPIO_WritePin (DHT22_PORT, DHT22_PIN, 0); // pull the pin low
HAL_Delay(1200); // wait for > 1ms
HAL_GPIO_WritePin (DHT22_PORT, DHT22_PIN, 1); // pull the pin high
delay (20); // wait for 30us
Set_Pin_Input(DHT22_PORT, DHT22_PIN); // set as input
}
- Set the pin (data) as output.
- Pull the pin low and wait for > 1 ms.
- Set the pin as input for receiving the data.
RESPONSE
uint8_t DHT22_Check_Response (void)
{
Set_Pin_Input(DHT22_PORT, DHT22_PIN); // set as input
uint8_t Response = 0;
delay (40); // wait for 40us
if (!(HAL_GPIO_ReadPin (DHT22_PORT, DHT22_PIN))) // if the pin is low
{
delay (80); // wait for 80us
if ((HAL_GPIO_ReadPin (DHT22_PORT, DHT22_PIN))) Response = 1; // if the pin is high, response is ok
else Response = -1;
}
while ((HAL_GPIO_ReadPin (DHT22_PORT, DHT22_PIN))); // wait for the pin to go low
return Response;
}
- Wait for 40 us.
- Check if the pin is low, than wait for 80 us. This will totally be a delay of 120 us and the pin should be high now.
- Check if the pin is high. If it is, then the response is OK.
READ DATA
uint8_t DHT22_Read (void)
{
uint8_t i,j;
for (j=0;j<8;j++)
{
while (!(HAL_GPIO_ReadPin (DHT22_PORT, DHT22_PIN))); // wait for the pin to go high
delay (40); // wait for 40 us
if (!(HAL_GPIO_ReadPin (DHT22_PORT, DHT22_PIN))) // if the pin is low
{
i&= ~(1<<(7-j)); // write 0
}
else i|= (1<<(7-j)); // if the pin is high, write 1
while ((HAL_GPIO_ReadPin (DHT22_PORT, DHT22_PIN))); // wait for the pin to go low
}
return i;
}
- Wait for the pin to go high.
- Wait for 40 us. This is because the length of “0” bit is 26-28 us and if the pin is high after 40 us, it indicates that the bit is “1”.
- Write the respective values to the variable.
The delay function used in the code above is actually the delay in microseconds. We have already covered it another tutorial and below is the function for the same.
void delay (uint16_t time)
{
/* change your code here for the delay in microseconds */
__HAL_TIM_SET_COUNTER(&htim6, 0);
while ((__HAL_TIM_GET_COUNTER(&htim6))<time);
}
The main function
int main()
{
.....
HAL_TIM_Base_Start(&htim6); // for us Delay
lcd_init();
lcd_send_string("INITIALISING>>>>");
HAL_Delay(2000);
lcd_clear ();
while (1)
{
DHT22_Start();
Presence = DHT22_Check_Response();
Rh_byte1 = DHT22_Read ();
Rh_byte2 = DHT22_Read ();
Temp_byte1 = DHT22_Read ();
Temp_byte2 = DHT22_Read ();
SUM = DHT22_Read();
TEMP = ((Temp_byte1<<8)|Temp_byte2);
RH = ((Rh_byte1<<8)|Rh_byte2);
Temperature = (float) (TEMP/10.0);
Humidity = (float) (RH/10.0);
HAL_Delay(2000);
Display_Temp(Temperature);
Display_Rh(Humidity);
}
}
- We will first send the START condition an then check for the Presence.
- The read the 40 bit data in sequence and store it in the 5 bytes.
- Then combine the Temperature data together and Humidity data together.
- To get the actual data in °C and %Rh, we need to divide the Temp and Rh data by 10.
- Finally Display the data on the LCD.
Since we are also displaying the data on the LCD, the LCD is initialised in the main function itself. We have already covered how to use the LCD1602 via I2C to display strings, numbers, floats etc. Below are the functions for displaying the data on the LCD.
void Display_Temp (float Temp)
{
char str[20] = {0};
lcd_put_cur(0, 0);
sprintf (str, "TEMP:- %.2f ", Temp);
lcd_send_string(str);
lcd_send_data('C');
}
void Display_Rh (float Rh)
{
char str[20] = {0};
lcd_put_cur(1, 0);
sprintf (str, "RH:- %.2f ", Rh);
lcd_send_string(str);
lcd_send_data('%');
}
Result
Below is the image showing the output on the LCD.
You can see the temperature and humidity data is being displayed on the LCD.
You can watch the video to see the complete working of DHT22 sensor.