I noticed a lot of people had issues with the DHT sensors and I could not get the Adafruit library working myself. The Adafruit code https://github.com/adafruit/DHT-sensor-library is pretty iffy, requires higher timing resolution than necessary and doesn’t support the internal pullup resistor. Here is my simple version that uses the internal pullup resistor:
int dht = D0;
int rh = 0;
int temp = 0;
void setup()
{
Spark.variable("rh", &rh, INT);
Spark.variable("temp", &temp, INT);
pinMode(dht, INPUT_PULLUP);
}
void loop()
{
delay(10000);
rh = read_dht(dht, &temp);
}
int read_dht(int pin, int *temperature)
{
uint8_t data[5] = {0, 0, 0, 0, 0};
noInterrupts();
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delay(20);
pinMode(pin, INPUT_PULLUP);
while (digitalRead(pin) == HIGH) {
delayMicroseconds(10);
}
while (digitalRead(pin) == LOW) {
delayMicroseconds(10);
}
while (digitalRead(pin) == HIGH) {
delayMicroseconds(10);
}
for (uint8_t i = 0; i < 40; i++) {
uint8_t counter = 0;
while (digitalRead(pin) == LOW) {
delayMicroseconds(10);
}
while (digitalRead(pin) == HIGH) {
delayMicroseconds(10);
counter++;
}
data[i/8] <<= 1;
if (counter > 4) {
data[i/8] |= 1;
}
}
interrupts();
if (data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
*temperature = -254;
return -1;
}
*temperature = data[2];
return data[0];
}
rigtorp, you are right about the CRC! I had my mind on the 18B20 temperature sensor. However, disabling interrupts was specifically left out due to the sensitive nature of interrupts on the Spark, especially for the duration of the DHT22 read. I worked on an interrupt-based version but after consideration of the Spark “backend”, I decided that DHT22 readings are not critical. Besides, I tend to sample slowly (every 1 to 5 mins) and average them anyway.
This is a nice a simple way to read DHT sensors… nice work!
Agreed with the delay(10000); is a no-no.
If you want some super simple bad code that will let you hard delay that long…
delay(5000);
SPARK_WLAN_Loop();
delay(5000);
A more proper way:
uint32_t lastRead = 0; // last known read time
bool s = true;
int dht = D0;
int rh = 0;
int temp = 0;
void setup()
{
lastRead = millis(); // We just powered up
pinMode(D7, OUTPUT);
Spark.variable("rh", &rh, INT);
Spark.variable("temp", &temp, INT);
pinMode(dht, INPUT_PULLUP);
}
void loop() {
// Run some test code so we know the core is running!
digitalWrite(D7,s);
s = !s; // toggle the state
delay(100); // makes it blinky
// Is it time to read our sensor?
if( tenSecondsElapsed() ) {
// Read sensor
rh = read_dht(dht, &temp);
}
} // End main loop (currently runs every 5-6 ms)
uint8_t tenSecondsElapsed() {
if( (millis()-lastRead) > (10*1000) ) {
lastRead = millis();
return 1; // 10 seconds has elapsed
} else {
return 0; // nope, not yet be patient!
}
}
int read_dht(int pin, int *temperature)
{
uint8_t data[5] = {0, 0, 0, 0, 0};
__disable_irq();
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delay(20);
pinMode(pin, INPUT_PULLUP);
while (digitalRead(pin) == HIGH) {
delayMicroseconds(10);
}
while (digitalRead(pin) == LOW) {
delayMicroseconds(10);
}
while (digitalRead(pin) == HIGH) {
delayMicroseconds(10);
}
for (uint8_t i = 0; i < 40; i++) {
uint8_t counter = 0;
while (digitalRead(pin) == LOW) {
delayMicroseconds(10);
}
while (digitalRead(pin) == HIGH) {
delayMicroseconds(10);
counter++;
}
data[i/8] <<= 1;
if (counter > 4) {
data[i/8] |= 1;
}
}
__enable_irq();
if (data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
*temperature = -254;
return -1;
}
*temperature = data[2];
return data[0];
}
FYI: That use of nointerrupts()/interrupts() will only disable user created interrupts such as attachInterrupt(); To really disable the background ones you need to use __disable_irq(); and __enable_irq();.
elapsedMillis tenSecondTimer;
const unsigned long TenSeconds = 10000L;
in loop():
// Is it time to read our sensor?
if (tenSecondTimer >= TenSeconds) {
tenSecondTimer = 0;
// Read sensor
rh = read_dht(dht, &temp);
}