Fred Barnes / lib_dht22

Fork of lib_dht22 by Jodie Perry

Files at this revision

API Documentation at this revision

Comitter:
co657_frmb
Date:
Thu Nov 03 11:08:45 2016 +0000
Parent:
2:02cbaab7c6cd
Child:
4:30a98da09c59
Commit message:
fixed up some things, still need a touch more tidying.

Changed in this revision

dht22.cpp Show annotated file Show diff for this revision Revisions of this file
dht22.h Show annotated file Show diff for this revision Revisions of this file
--- a/dht22.cpp	Wed Nov 02 16:29:53 2016 +0000
+++ b/dht22.cpp	Thu Nov 03 11:08:45 2016 +0000
@@ -1,5 +1,6 @@
 /*
  * (C) The University of Kent and Simon Cooksey 2015.
+ * Proddled a bit by Fred
  */
 
 #include "mbed.h"
@@ -12,142 +13,222 @@
  * of the HIGH time on the signal pin.
  */
 
-/*
- * Wait for a rising or falling edge on the sense pin.
- *
- * Returns: the number of uS elapsed before the transition
- */
-int DHT22::wait_for_edge(edge_type_t type)
+/* delay for approx 2 microseconds */
+void DHT22::wait_2us (void)
 {
-    //__disable_irq ();
-    dht22_s.input();
+    int i;
+    
+    /* 16 * 14 nops, plus loopend */
+    for (i=0; i<16; i++) {
+        __asm__ __volatile__ ("         \n" \
+            "   nop                     \n" \
+            "   nop                     \n" \
+            "   nop                     \n" \
+            "   nop                     \n" \
+            "   nop                     \n" \
+            "   nop                     \n" \
+            "   nop                     \n" \
+            "   nop                     \n" \
+            "   nop                     \n" \
+            "   nop                     \n" \
+            "   nop                     \n" \
+            "   nop                     \n" \
+            "   nop                     \n" \
+            "   nop                     \n");
+
+    }
+    return;
+}
+
 
-    // Timing is done by increasing this number, as the Timer class appears to
-    // be super slow.
-    int time = 0;
-    do {
-        wait_us(2);
-        time+=2;
-    } while(dht22_s != (int)type);
+/* ensure the comms pin is set for input */
+void DHT22::setinput (void)
+{
+    if (!isinput) {
+        dht22_s.input ();
+        isinput = 1;
+    }
+}
+
+/* ensure the comms pin is set for output */
+void DHT22::setoutput (void)
+{
+    if (isinput) {
+        dht22_s.output ();
+        isinput = 0;
+    }
+}
+
 
-    // wait for the edge to transition properly
-    wait_us(2);
-    //__enable_irq ();
-    return time;
+int DHT22::wait_for_level (int lvl, const int max)
+{
+    int time;
+
+    setinput ();
+    
+    for (time=0; ((max == -1) || (time < max)) && (dht22_s != lvl); time += 2) {
+        wait_2us ();
+    }
+    if ((max > 0) && (time >= max)) {
+        /* timed out */
+        return -1;
+    }
+    
+    if (time) {
+        /* means we saw a transition, so let it settle */
+        wait_2us ();
+        time += 2;
+    }
+    
+    return time;            
 }
 
+
 /*
  * Send a start bit to the DHT22
  */
-void DHT22::send_start()
+void DHT22::send_start (void)
 {
+    int dly;
+    
     //__disable_irq ();
-    dht22_s.output();
+    setoutput ();
     dht22_s = 0;
-    wait_us(DHT22_START_BIT_TIME);
+    /* drag low for 1ms */
+    for (dly=0; dly<(DHT22_START_BIT_TIME >> 1); dly++) {
+        wait_2us ();
+    }
+    // wait_us (DHT22_START_BIT_TIME);
     dht22_s = 1;
-    dht22_s.input();
+    setinput ();
     //__enable_irq ();
 }
 
 /*
  * Wait for the DHT22 to send the start bit ACK, after this we can read data.
  */
-void DHT22::await_start_response()
+int DHT22::wait_start (void)
 {
-    dht22_s.input();
-    wait_for_edge(EDGE_TYPE_FALLING); // 20-40 uS
-    wait_for_edge(EDGE_TYPE_RISING);  // 80 uS
-    wait_for_edge(EDGE_TYPE_FALLING); // 80 uS
+    /* level should be 1 */
+    if (dht22_s == 0) {
+        return -1;
+    }
+    if (wait_for_level (0, 500) < 0) {
+        /* should respond in 20-200 us, it didn't in 500 */
+        return -2;
+    }
+    if (wait_for_level (1, 100) < 0) {
+        /* only for 80 us (max 85 in datasheet) */
+        return -3;
+    }
+    if (wait_for_level (0, 100) < 0) {
+        /* only for 80 us (max 85 in datasheet) */
+        return -4;
+    }
+    /* at this point we're about to start seeing the MSB of data [39-0] */
+    
+    return 0;    
 }
 
 /*
- * Reads 16 bits of data from the DHT22
- *
- * Returns: the signed value read. dht22_t.
- * NB. the DHT22 uses a sign bit to do -ve and positive, but this is
- * incompatible with signed numbers in C, so the conversion is done here.
+ * reads 8 bits of data, returns value [0-255] on success, -1 on error (timeout)
  */
-int16_t DHT22::read_word()
+int DHT22::read_byte (void)
 {
-    dht22_s.input();
-    int32_t duration;
-    int16_t word = 0x00;
-    for(char bit = 0; bit < 16; bit++)
-    {
-        /*       /-----------\
-         *      /   duration  \    50us
-         * ----/               \-------
-         */
-        wait_for_edge(EDGE_TYPE_RISING);
-        duration = wait_for_edge(EDGE_TYPE_FALLING);
+    int d, bit;
+    int v = 0;
+    
+    /* should be zero already */
+    if (dht22_s == 1) {
+        return -1;
+    }
+    
+    for (bit=7; bit>=0; bit--) {
+        /* expect it to stay low for 50us (max 55) */
+        if (wait_for_level (1, 100) < 0) {
+            /* timed out after 100us */
+            return -2;
+        }
+
 
-        if(duration > DHT22_SIGNAL_HIGH_LOW_BOUNDARY)
-        {
-            word |= (1 << 15-bit);
+        d = wait_for_level (0, 100);
+        if (d < 0) {
+            /* timed out after 100us */
+            return -3;
         }
-        else
-        {
-            word |= (0 << 15-bit);
+
+
+        if (d > DHT22_SIGNAL_HIGH_LOW_BOUNDARY) {
+            v |= (1 << bit);
+            debug = 1;
+    } else {
+            debug = 0;
         }
+
     }
-    if(word & 0x8000)
-        return 1 - (word ^ 0x8000);
-    return word;
+    return v;
 }
 
-/*
- * Reads 8 bits of data from the DHT22
- *
- * Returns: the unsigned checksum value read. dht22_t.
- */
-uint8_t DHT22::read_checksum()
-{
-    dht22_s.input();
-    uint32_t duration;
-    uint8_t word;
-    for(char bit = 0; bit < sizeof(uint8_t)*8; bit++)
-    {
-        /*       /-----------\
-         *      /   duration  \    50us
-         * ----/               \-------
-         */
-        wait_for_edge(EDGE_TYPE_RISING);
-        duration = wait_for_edge(EDGE_TYPE_FALLING);
-
-        if(duration > DHT22_SIGNAL_HIGH_LOW_BOUNDARY)
-        {
-            word |= (1 << 7-bit);
-        }
-        else
-        {
-            word |= (0 << 7-bit);
-        }
-    }
-    return word;
-}
 
 /*
  * Reads a packet of DHT22 data.
  *
- * Param data: the packet to fill.
+ * Param data: the packet to fill.  returns 0 on success, < 0 on error (timeout of some kind)
  */
-void DHT22::read(DHT22_data_t * data)
+int DHT22::read (DHT22_data_t *data)
 {
+    uint8_t buf[5];
+    uint16_t u_hum, u_tmp;
+    int i;
+    
+    debug = 0;
+    __disable_irq ();
     // Send start bits
     send_start();
 
-    // Wait for device to respond
-    await_start_response();
-
-    // Read data bits (16+16)
-    int16_t humidity = read_word();
-    int16_t temp = read_word();
+    if (wait_start () < 0) {
+        __enable_irq ();
+        return -1;              /* timed out waiting for start response */
+    }
+    /* read 40 bits worth -- MSB first */
+    for (i=4; i>=0; i--) {
+        int v = read_byte ();
+        
+        if (v < 0) {
+            /* timed out waiting for data */
+            __enable_irq ();
+            return -2;
+        }
+        buf[i] = (uint8_t)v;
+    }
 
-    // Read checksum  (8)
-    uint8_t checksum = read_checksum();
+    /* yay, got here! -- sensor should release the wire in 50us (max 55) */
+    if (wait_for_level (1, 100) < 0) {
+        /* timed out at this point, but still fill the buffer */
+        i = -3;
+    } else {
+        i = 0;
+    }
+    __enable_irq ();
+    
+    /* unscramble */
+    u_hum = ((uint16_t)buf[4] << 8) | buf[3];
+    u_tmp = ((uint16_t)buf[2] << 8) | buf[1];
+    
+    if (u_hum & 0x8000) {
+        data->humidity = 1 - (int)(u_hum ^ 0x8000);
+    } else {
+        data->humidity = (int)u_hum;
+    }
+    if (u_tmp & 0x8000) {
+        data->temp = 1 - (int)(u_tmp ^ 0x8000);
+    } else {
+        data->temp = (int)u_tmp;
+    }
 
-    data->humidity = (humidity);
-    data->temp = (temp);
-    data->checksum = checksum;
-}
\ No newline at end of file
+    data->checksum = buf[0];
+    debug = 0;
+    
+    return i;
+}
+
--- a/dht22.h	Wed Nov 02 16:29:53 2016 +0000
+++ b/dht22.h	Thu Nov 03 11:08:45 2016 +0000
@@ -6,33 +6,40 @@
 #define __DHT22_h_
 
 // We'll pick a point to decide if a signal is 1 or 0 from. 
-#define DHT22_SIGNAL_HIGH_LOW_BOUNDARY      50   // uS
-#define DHT22_START_BIT_TIME                500  // uS
+#define DHT22_SIGNAL_HIGH_LOW_BOUNDARY      40   // uS
+#define DHT22_START_BIT_TIME                1000  // uS
 #define DHT22_START_BIT_RESPONSE            80   // uS
 
-typedef enum {
-    EDGE_TYPE_FALLING,
-    EDGE_TYPE_RISING,
-} edge_type_t;
 
 typedef struct {
     int temp;
     int humidity;
     uint8_t checksum;
+    char dummy[3];
 } DHT22_data_t;
 
 class DHT22 {
 public:
-    DHT22(PinName pin)  : dht22_s(pin) { }
-    void read(DHT22_data_t * data);
+    DHT22 (PinName pin) : dht22_s (pin), debug (PTB19)
+    {
+        dht22_s.input ();
+        isinput = 1;
+    }
+    
+    int read (DHT22_data_t *ptr);
 private:
     DigitalInOut dht22_s;
+    int isinput;
+    DigitalOut debug;
 
-    int wait_for_edge(edge_type_t type);
-    void send_start();
-    void await_start_response();
-    int16_t read_word();
-    uint8_t read_checksum();
+    void wait_2us (void);
+    void setinput (void);
+    void setoutput (void);
+    
+    int wait_for_level (int lvl, const int max);
+    void send_start (void);
+    int wait_start (void);
+    int read_byte (void);
 };
 
 #endif // __DHT22_h_