Skip to content

Commit

Permalink
feat: first version
Browse files Browse the repository at this point in the history
  • Loading branch information
andrea-deri committed Dec 8, 2022
1 parent 6d1ed52 commit 3ec5e03
Show file tree
Hide file tree
Showing 5 changed files with 319 additions and 1 deletion.
Binary file added DHT11-Temperature-Sensor.pdf
Binary file not shown.
159 changes: 159 additions & 0 deletions DHT11Reader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#include "HardwareSerial.h"
#include "DHT11Reader.h"

byte DHT11Reader::read(int pin) {

byte result = DHT11READER_OK;

uint8_t extractedData[5] = {0, 0, 0, 0, 0};

/*
Clearing the buffer
*/
//extractedData[0] = extractedData[1] = extractedData[2] = extractedData[3] = extractedData[4] = 0;

/*
Setting the pin mode to output in order to send the start signals from MCU to DHT11
*/
pinMode(pin, OUTPUT);

/*
MCU send a low signal for starting the communication with DHT11.
It must send a 18ms low-pulse in order to let the DHT11 sensor to detect
the activation signal. The duration value will be set to 20ms for approximation.
*/
digitalWrite(pin, LOW);
delay(STARTSIGNAL_DHTDETECTION_DELAY);

/*
MCU send an high signal in order to tell to DHT11 that it is awaiting
the sensor response. It must send a 20us to 40us high-pulse in order to permits
the effective starts of the communication from the DHT11 sensor. The duration value
will be set to 50us for approximation.
*/
digitalWrite(pin, HIGH);
delayMicroseconds(STARTSIGNAL_WAITINGDHT_DELAY);

/*
Set the pin mode to input in order to receive the data signal from DHT11 to MCU.
*/
pinMode(pin, INPUT);

/*
The DHT11 sensor send a low signal in order to tell to MCU that is ready to communicate.
It must send a 80us low-pulse in order to starts the communication. Several manufacturer
can define the pulse duration with different values, so the value is defined as an approximation
of an hypotetical high-speed IO's Arduino-based MCU (1us for complete the digitalRead operation)
for a signal duration of at least of 100us.
*/
unsigned int leftCycles = ACKNOWLEDGEDHT_CYCLE_DURATION;
while(result == DHT11READER_OK && digitalRead(pin) == LOW) {
if (leftCycles-- == 0) {
result = DHT11READER_TIMEOUT;
}
}

/*
The DHT11 sensor send an high signal in order to tell to MCU that is ready to communicate.
It must send a 80us high-pulse in order to starts the communication. Several manufacturer
can define the pulse duration with different values, so the value is defined as an approximation
of an hypotetical high-speed IO's Arduino-based MCU (1us for complete the digitalRead operation)
for a signal duration of at least of 100us.
*/
leftCycles = ACKNOWLEDGEDHT_CYCLE_DURATION;
while(result == DHT11READER_OK && digitalRead(pin) == HIGH) {
if (leftCycles-- == 0) {
result = DHT11READER_TIMEOUT;
}
}

uint8_t measurementIdx = 0;
uint8_t bitIdx = 7;
short i = 0;

while(result != DHT11READER_OK || i < TRANSMITTED_BITS) {

/*
The DHT11 sensor send a low signal in order to tell to MCU that is sending a new bit of data.
It must send a 50us low-pulse in order to syncronize the sending.
*/
leftCycles = STARTTRANSMISSION_DHT_DURATION;
while(result == DHT11READER_OK && digitalRead(pin) == LOW) {
if (leftCycles-- == 0) {
result = DHT11READER_TIMEOUT;
}
}

/*
Tracing the start of the transmission for the data bit.
*/
unsigned long bitTransmissionStart = micros();

/*
The DHT11 sensor send a high signal in order to send a new bit of data to MCU.
The value of the bit is defined with the duration of the pulse: is the pulse lasts about 30us,
it is a 0 value, if the pulse lasts 70us it is a 1 value. The paragon for the cycles will be
calculated on the most long pulse, i.e. the one for the 1 data.
*/
leftCycles = TRANSMISSION_DHTBIT1_DURATION;
while(digitalRead(pin) == HIGH) {
if (result == DHT11READER_OK && leftCycles-- == 0) {
result = DHT11READER_TIMEOUT;
}
}

if (result == DHT11READER_OK) {
/*
In order to set a 0 or 1 value to the bit, it is defined to find if the pulse signal has a duration
for more than 70us-30us=40us: if so, the bit cannot certainly be with value 0, for exclusion it will be 1.
For calculating the final value, the extracted 1-bit will be shifted for the cardinal position on which it
was sent by DHT11 sensor: a bit that was sent before another will have a more significant bit value, so will be
shifted by more position than the next one.
*/
if ((micros() - bitTransmissionStart) > TRANSMISSION_DHTSENTBITDIFFERENCE_DURATION) {
extractedData[measurementIdx] = extractedData[measurementIdx] | (1 << bitIdx);
}

/*
Move the bit index towards right if greater than zero. If equals to zero, it means that all the previous bit were
inserted in the final float value, so the bit index will be reset to MSB bit and the measurement index (i.e. the single
value extracted from sensor) will be incremented.
*/
if (bitIdx != 0) {
bitIdx--;
} else {
bitIdx = 7;
measurementIdx++;
}
i++;
}

}

if (result == DHT11READER_OK) {
/*
Calculating the value of the humidity for the integer part and the decimal one.
*/
humidity = extractedData[0] + (extractedData[1] * 0.1);

/*
Calculating the value of the temperature for the integer part and the decimal one. If the decimal part is equals to 0x80=10000000,
it means that the value is negative, due to the fact that the last bit define the sign value. Also, the decimal part will be pruned
by eventual excedeed bits (and the max value will be 0x0f) and will be moltiplied by 0.1 and sum to the final value.
*/
temperature = extractedData[2];
if (extractedData[3] & 0x80) {
temperature = -1 - temperature;
}
temperature += (extractedData[3] & 0x0f) * 0.1;
/*
If the checksum value is different from the extracted elements, an error during the transmission is occurred.
*/
if (extractedData[4] != (extractedData[0] + extractedData[1] + extractedData[2] + extractedData[3])) {
result = DHT11READER_CHECKSUM_FAIL;
}
}

return result;
}

109 changes: 109 additions & 0 deletions DHT11Reader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#ifndef DHT_11
#define DHT_11

#include <Arduino.h>

/*
The number of transmitted bits from DHT11 sensor. This value is calculated as follows:
8 bits for humidity integer part +
8 bits for humidity decimal part +
8 bits for temperature integer part +
8 bits for temperature decimal part +
8 bits for checksum, equals to the 8 bits of the sum of the previous four measurations
*/
#define TRANSMITTED_BITS 40

/*
The state related to the correct execution of the measurement.
*/
#define DHT11READER_OK 0x00

/*
The state related to the termination of the measurement due to timeout during acknowledgement or communication.
*/
#define DHT11READER_TIMEOUT 0x01

/*
The state related to the error of the measurement after the calculation of the checksum.
*/
#define DHT11READER_CHECKSUM_FAIL 0x02

/*
The value of the duration for the start low-pulse signal that the
MCU made to DHT11 to start the communication. This is a delay value that
is imposed to MCU in order to execute the next step.
*/
#define STARTSIGNAL_DHTDETECTION_DELAY 20

/*
The value of the duration for the start high-pulse signal that the
MCU made to DHT11 to start the communication. This is a delay value that
is imposed to MCU in order to execute the next step.
*/
#define STARTSIGNAL_WAITINGDHT_DELAY 50

/*
---------------------------------------------------------------------------------------------------------------------------
The following values are the number of read cycles to be executed to wait the responses from DHT11 sensor.
They are calculated as an approximation of an hypotetical high-speed IO's Arduino-based MCU (1us for complete
the digitalRead operation). So, if a digitalRead operation is made, a reading cycle means that is passed 1us. If the
DHT11 send a pulse signal that has a certain duration (for example 50us), the MCU must execute 50 reading cycles.
Obviously. if the IO operation needs more time to be executed, the cycles will be the sames but it doesn't matter,
as this library is not made for critical missions.
*/
/*
The value of the duration for either the low-pulse and the high-pulse signals that the DHT11 send to MCU in order to
execute a sort of "acknowledgement" that the MCU will interpretate as "the DHT11 is read to send data".
*/
#define ACKNOWLEDGEDHT_CYCLE_DURATION 100


/*
The value of the duration for for the low-pulse signal that the DHT11 send to MCU before the single bit transmission.
*/
#define STARTTRANSMISSION_DHT_DURATION 50

/*
The value of the duration for for the high-pulse signal that the DHT11 send to MCU for transmit a 0-value bit.
*/
#define TRANSMISSION_DHTBIT0_DURATION 30

/*
The value of the duration for for the high-pulse signal that the DHT11 send to MCU for transmit a 1-value bit.
*/
#define TRANSMISSION_DHTBIT1_DURATION 70

/*
The value of the difference between the duration of the transmission of 0-bit and the transmission of 1-bit.
This value will be used for calculating that the DHT11 sensor has sent a 0 bit instead of 1 bit.
*/
#define TRANSMISSION_DHTSENTBITDIFFERENCE_DURATION TRANSMISSION_DHTBIT1_DURATION - TRANSMISSION_DHTBIT0_DURATION

/*
This class permits to read the values of termperature and humidity from the DHT11 sensor.
*/
class DHT11Reader {

public:

/*
This method permits to read the value of the temperature and humidity from the sensor connected to MCU
in the passed pin. The calculated values of temperature and humidity can be retrieved simply calling them in the instance.
The returned value is the state of the communication and measurement.
*/
byte read(int pin);

/*
The value of the temperature (in °C) calculated from the read() operation.
If you read this value before the calculation can lead to wrong values.
*/
float temperature;

/*
The value of the humidity (in %RH) calculated from the read() operation.
If you read this value before the calculation can lead to wrong values.
*/
float humidity;
};

#endif
41 changes: 41 additions & 0 deletions DHT11Reader.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "DHT11Reader.h"

#define DHT_PIN 2

DHT11Reader dhtSensor;

const char VALUES_SEPARATOR[] = ";";
const short VALUES_SIZE = 3;

void setup() {
Serial.begin(9600);
}

void loop() {
float values[VALUES_SIZE];
values[0] = dhtSensor.read(DHT_PIN);
values[1] = dhtSensor.humidity;
values[2] = dhtSensor.temperature;
sendData(values, VALUES_SEPARATOR);
delay(5000);
}

/*
The method permits to send the calculated data to the serial channel
in a stringfied form.
*/
void sendData(const float* data, const char separator) {
char tempBuffer[6];
char buffer[150];
strcpy(buffer, dtostrf(data[0], 3, 1, tempBuffer));
for (int i = 1; i < VALUES_SIZE; i ++) {
strcat(buffer, VALUES_SEPARATOR);
strcat(buffer, dtostrf(data[i], 3, 1, tempBuffer));
}
strcat(buffer, VALUES_SEPARATOR);
Serial.println(buffer);
}




11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
# DHT11Reader
A bare-bone library for retrieve data from DHT11 sensor.
A bare-bone library for retrieve data from DHT11 sensor, without all the cumbersome stuff related to complex computation.
Useful for that projects where you need only a simple measuration of temperature and humidity.

## Description
The library behaviour is adapted to the protocol of the DHT11 sensor, described in the PDF file included in this repo.
The measured values can be read as floating point values directly from the class instance.
See DHT11Reader.ino file for a working example.

## References
Strongly inspired by Adi Dax's work on DHT11 library (https://github.com/adidax/dht11).

0 comments on commit 3ec5e03

Please sign in to comment.