-
Notifications
You must be signed in to change notification settings - Fork 3
DHT22
http://www.adafruit.com/datasheets/DHT22.pdf
(Using wiringPi)
Data-bus's free status is high voltage level. When communication between MCU and AM2303 begin, program of MCU will transform data-bus's voltage level from high to low level and this process must beyond at least 18ms to ensure AM2303 could detect MCU's signal, then MCU will wait 20-40us for AM2303's response
So, we need to set the pin to HIGH, then to LOW within a window of 18ms maximum, then wait 40 micro seconds (maximum) to the DHT22 to be ready :
pinMode(iPin, OUTPUT);
digitalWrite(iPin, LOW);
delay(18);
digitalWrite(iPin, HIGH);
delayMicroseconds(40);
This will do the job, and we will be able to read our values from the sensor.
Data is comprised of integral and decimal part, the following is the formula for data. AM2303 send out higher data bit firstly! 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"
So we learn that the DHT22 will output, bit per bit, 40 bits of data :
Bits | Data |
---|---|
0 - 7 | Humidity integer part |
8 - 15 | Humidity decimal part |
16 - 23 | Temperature integer part |
24 - 31 | Temperature decimal part |
32 - 40 | Checksum |
But, how much read will we need ? More than 40, because we can learn that in the data sheet:
When AM2303 detect the start signal, AM2303 will send out low-voltage-level signal and this signal last 80us as response signal, then program of AM2303 transform data-bus's voltage level from low to high level and last 80us for AM2303's preparation to send data.
That means that the first three reads will be start-up signal from the sensor, which we will ignore. I currently don't know why the really first value must be ignored, I suspect that this is our own signal. Hopefully the checksum is here to validate the values.
And then:
When AM2303 is sending data to MCU, every bit's transmission begin with low-voltage-level that last 50us, the following high-voltage-level signal's length decide the bit is "1" or "0".
So that means that 1 over 2 read will be a control signal from the sensor, indicating that the sensor will send data, not the data itself. So, again, we will ignore it.
So our workflow looks like this now:
Bit read | Info | Data ? |
---|---|---|
1 | Low level voltage signal | No |
2 | High level voltage signal | No |
3 | Low level : bit incoming | No |
4 | Data itself | Yes |
... | ... | ... |
n%2 == 0 | Data | Yes |
... | ... | ... |
That's 40 time two reads, plus 3 first reads.
When AM2303 is sending data to MCU, every bit's transmission begin with low-voltage-level that last 50us, the following high-voltage-level signal's length decide the bit is "1" or "0".
If signal from AM2303 is always high-voltage-level, it means AM2303 is not working properly, please check the electrical connection status.
This is the length of the signal which allow us to know if its a '0' or a '1'. But how ? The 0 length is 26-28 microseconds, and the 1 length 70 microseconds. The easiest way is to simply check every microsecond. If it's HIGH for 26/28 microsecond, it's 0; if it's HIGH for 70 microseconds it's 1, and more means an error with the sensor.
static int wait_for_state_change(int iPin, uint8_t* laststate) {
struct timeval start, stop;
gettimeofday(&start, NULL);
int counter = 0;
while (sizecvt(digitalRead(iPin)) == *laststate) {
delayMicroseconds(1);
counter++;
if (counter == 255) {
return -1;
}
}
gettimeofday(&stop, NULL);
*laststate = sizecvt(digitalRead(iPin));
return time_diff(start, stop);
}
This function will wait for a state change on the given pin, according to the previous given value. When the change occurs, the function will send back the time, or -1 if the sensor is 'locked'. time_diff is only computing in microseconds the time difference between start and stop.
Then, we need to find an easy way to store our data. The easiest way is to use an array of five bits, and to shift left at every value on the right table cell:
pinMode(iPin, OUTPUT);
digitalWrite(iPin, LOW);
delay(18);
digitalWrite(iPin, HIGH);
delayMicroseconds(40);
pinMode(iPin, INPUT);
// Ignore first three values
for (i = 0; i < 3; i++) {
if(getTime(iPin, &laststate) < 0)
return 0;
}
for (i = 0; i < 40; i++) {
int timer = getTime(iPin, &laststate);
if(timer < 0)
break;
timer = getTime(iPin, &laststate);
if(timer < 0)
break;
dht22_dat[i/8] <<= 1;
if (timer > 28)
dht22_dat[i/8] |= 1;
}
After retrieving the data, and checking with the checksum that everything is right, we need to make them human readable.
*piHumidity = ((int)dht22_dat[0] << 8) + (int)dht22_dat[1];
*piTemp = ((int)dht22_dat[2] << 8 ) + dht22_dat[3];
We simply store our two 8 bit values into a 16 bit value, one after another.