How to use DHT11 sensor with STM32
DHT11 digital temperature and humidity sensor is a composite Sensor contains a calibrated digital signal output of the temperature and humidity. The sensor uses only one wire to communicate to the microcontrollers. Today in this tutorial we interface this DHT11 sensor with STM32.
This CODE works with the TIMER Delay. If you want to know how to create delay in microsecond using timer, first go to https://controllerstech.com/create-1-microsecond-delay-stm32/
You can also check out the tutorial covering how to interface the DHT22 sensor with STM32.
For those, whose code Runs only 1 time, Give at least 3 second delay in the while loop, before reading the temperature again. 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
INITIALIZATION
- As shown above, in order to initialise the sensor, we have to first pull the data line LOW for around 18 ms.
- After this DHT11 will pull the line LOW for 80 us ,and than HIGH for 80 us.
- Once this is done, the sensor will be initialized and start transmitting
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.
Below are the Steps for initialising the DHT11 sensor.
- Set the pin (data) as output
- Pull the pin low for 18ms
- Release the pin by setting it as input
DHT11 will now send the response as you can see in the figure above.
Response
In order to indicate it’s presence, after receiving the start signal, DHT11 will send a response signal. To do so, it will pull the data line low for 80 us, and than high for another 80 us. To read this response, we will do the following
- Wait for 40 us.
- Read the pin, it must be low at this point.
- Wait for 80 us.
- Read the pin, this time it should be HIGH.
If the above conditions are satisfied, that means the sensor is present, and we can proceed with reading the data.
DATA Transmission
After sending the response signal, the DHT11 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 DHT11 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, check-sum 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 DHT11 and nucleo F446.
Since the DHT11 only uses 1 wire to communicate to the MCU, I have connected it to the pin PA1. The sensor is powered with 3.3V 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 DHT11 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.
Some Insight into the CODE
INITIALIZATION
- Set the pin (data) as output.
- Pull the pin low and wait for 18ms.
- set the pin as input for receiving the data.
void DHT11_Start (void)
{
Set_Pin_Output (DHT11_PORT, DHT11_PIN); // set the pin as output
HAL_GPIO_WritePin (DHT11_PORT, DHT11_PIN, 0); // pull the pin low
delay (18000); // wait for 18ms
Set_Pin_Input(DHT11_PORT, DHT11_PIN); // set as input
}
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, than the response is OK.
uint8_t Check_Response (void)
{
uint8_t Response = 0;
delay (40);
if (!(HAL_GPIO_ReadPin (DHT11_PORT, DHT11_PIN)))
{
delay (80);
if ((HAL_GPIO_ReadPin (DHT11_PORT, DHT11_PIN))) Response = 1;
else Response = -1;
}
while ((HAL_GPIO_ReadPin (DHT11_PORT, DHT11_PIN))); // wait for the pin to go low
return Response;
}
READ DATA
- 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.
uint8_t DHT11_Read (void)
{
uint8_t i,j;
for (j=0;j<8;j++)
{
while (!(HAL_GPIO_ReadPin (DHT11_PORT, DHT11_PIN))); // wait for the pin to go high
delay (40); // wait for 40 us
if (!(HAL_GPIO_ReadPin (DHT11_PORT, DHT11_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 (DHT11_PORT, DHT11_PIN))); // wait for the pin to go low
}
return i;
}
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)
{
DHT11_Start();
Presence = DHT11_Check_Response();
Rh_byte1 = DHT11_Read ();
Rh_byte2 = DHT11_Read ();
Temp_byte1 = DHT11_Read ();
Temp_byte2 = DHT11_Read ();
SUM = DHT11_Read();
TEMP = Temp_byte1;
RH = Rh_byte1;
Temperature = (float) TEMP;
Humidity = (float) RH;
HAL_Delay(3000);
}
}
- 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 just need to Read the 1st byte of the Temp and RH data. The DHT11 does not send the decimal data, so 2nd bytes are irrelevant.
- 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 above the Temperature and RH values are being displayed on the LCD.
You can watch the video below for the detailed working.