This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How do I use DHT11 sensor on TM4C123GH6PM?

Other Parts Discussed in Thread: ENERGIA

Hi, I'm new to TM4C123G series and I'tm having a lot of trouble to read serial data from a sensor

I bought a DHT11 sensor because I need to measure umidity and temperature and its output is a 40bit serial data. In fact, I don't know how to set a pin to read the 40bit output and then separe it in 5 bytes or read 1 byte a time. I've tried to use the UART library, but it gives me an error saying that "identifier 'bool' is undefined" and I can't find anything about this sensor on these boards over the internet.

Any help is welcome. Thanks

  • Perhaps your method of, "Diving directly into an application" but without the normal/customary "build-up" of required experience & MCU skills - proves an issue?

    Looking downstream - once you've successfully "transacted" with your remote device - what then?    Surely you'll want to display the sensor's results.    Maybe even, "take some actions" based upon those results.    What then?

    These MCUs are complex - usually new users have to "really commit" - expend serious time/effort to gain "reasonable" competence.

    Starting with an application - too often - "short circuits" the normal learning process - leading to posts nearly identical to yours.

    This vendor has produced extensive "learning aids" - manuals, videos, rich & extensive code examples - even this forum.  

    I'd bet that a better (i.e. some) search of this forum may reveal code to your objective.    But I don't recommend that - "Frankenstein" may have (from a distance) looked human - but up close - not so much.     And that's exactly "true" for "quick/dirty" code finds - if you don't properly understand - you'll soon ship-wreck - wash ashore - that's a promise...    And (then) what?    Real learning - understanding - is your answer...

  • DHT11... well I have to say you are screwed if have no experience with a MCU.
    The data transmission is not standard with anything (it's a nightmare!!)
    I think the DHT22 has the same interface and data packets so you could use the tutorials for it.
    There's a lot of info related with arduino but usually it's a library that does it all for you.
    You will need to use bit-banging. You can check the datasheet for the timings but I will tell you, you will need quite a bit of work!
    www.micropik.com/.../dht11.pdf

    I advise you to first get comfortable with the Tiva.
    If you want sample codes ready to go like in Arduino your not gonna have luck with that. It would be easier to use Energia and adapt some arduino libraries (sometimes it's drop in, no adaptation needed).


    Using the UART is not what you should be using for this for sure.
    But about your error it's because you forgot to include stdbool.h
    That type of error shows that you really need to get to the basics like cb1 said.
    I think starting with that sensor I would call the equivalent of getting a bad beating (will probably make you hate the whole process and the MCU)
  • I managed to solve the bool error, it was because I wrote <stdbool.h> instead of "stdbool.h".
    Actually, I know the basics of this MCU, the problem is I've never used such sensor and I really had no idea on how to read its data. I was going for UART because I've seen the Arduino code for this sensor and it was using serial communication.
    About the datasheet, the problem is I didn't understand this part:
    "Data Single-bus free status is at high voltage level. When the communication between MCU and DHT11 begins, the programme of MCU will set Data Single-bus voltage level from high to low and this process must take at least 18ms to ensure DHT’s detection of MCU's signal, then MCU will pull up voltage and wait 20-40us for DHT’s response."
    Does that mean I should send a +Vcc signal to the data pin and then send GND for 18ms to request the data or should I send some signal through serial?
  • Good luck here, Luis...
  • Doesn't matter through what you send the signal... You just need to follow those timings.
    I used a similar interface IC with either the PWM module, the SPI module or the GPIO. You have to chose the best option

  • I found a datasheet for the device and Luis is correct. It uses a non-standard interface that would require a fair amount of work to be sure you have it working correctly.

    It comes from a Chinese company (Aosong) who appears to have no distribution or representation in North America or Europe. That raises questions about supply reliability. I did not have any luck finding datasheets on their site either.

    The only source I've seen is hobby sites. I suspect there was a surplus that was reduced by sending the extras to the hobbyist market.

    I think you would be better off by choosing a sensor with a standard interface. Digikey lists several with analog, iic or spi interfaces.

    "Data Single-bus free status is at high voltage level. When the communication between MCU and DHT11 begins, the programme of MCU will set Data Single-bus voltage level from high to low and this process must take at least 18ms to ensure DHT’s detection of MCU's signal, then MCU will pull up voltage and wait 20-40us for DHT’s response."

    Unfortunately, the prose does not get clearer. What they are saying is that you need to drive the line low and let it float high to let the ic respond.

    Robert
  • Robert Adsett72 said:
    What they are saying is that you need to drive the line low and let it float high to let the ic respond.  

    This reporter is far from the accomplished translating/interpreting skills of o.p. and friend Robert.

    Yet - can, "Let it float high" be correct?    Firm's instruction, "then MCU will pull up" indicates not so much a "float" as a pull-up - so that a known signal level is established.

    I've not read this device's data - this sounds like some variant of, "One wire bus" where the single communication line proves bi-directional.    Thus - poster's use of UART - which neither enables fine tuning (& quick alteration of bit timing) & which is unable to quickly/easily switch from output to input - appears very flawed...

    Forum cannot - and should not - serve the "bottom of the barrel - sensor du jour" - "This x@#$! sensor don't work!" - endless series of requests...  

  • let it float high... that's a way to say it I guess... that data line requires a pull-up, to let it float you should switch the pin to input
  • Thanks, that was what i wasnt understanding. I managed to get the signal from it, although I still have to verify if the values are correct to have sure i have set the proper timing.
  • Yep, another one wire bus. Doesn't appear as resilient as the Dallas bus.

    I was assuming there would be a pull-up on the bus. I think the datasheet explicitly calls for it. I would normally put a pull-up on all digital lines unless there was an overriding reason not to.

    Robert
  • Luis Afonso said:
    to let it float you should switch the pin to input

    Should you (really) let an input, "float?"    Of course you know that's not correct/proper - and as you've said (often) here - GPIO inputs should always be graced with a suitable logic level.  (which never is "float")

  • A better way to phrase what I said:

    The data line requires a pull up, to "let the pin float" you should switch the GPIO from output to input. The pin will not actually float, it will be pulled high by the pull-up when left floating.
  • Luis - very, very difficult to, "defend the indefensible!"

    Look again at your newest writing, "it (data line) will be pulled high by the pull-up when left floating."    While that's technically possible (to pull up a pin switched to an input - after that "switch to input" has occurred) such "signal level sequencing" proves, "in the noise."    Most always - pull up is present/accounted for - thus the GPIO - even when switched to input - is "never" floating!   (it may float if the pull up does not directly attach to 3V3 - but instead to a GPIO output - or other controlled voltage source - but this is outside, "normal/customary" as it "eats" MCU resources)

    Simply put - the bi-di data pin - in focus here - is "never" floating...

  • While I was lazy and should not have left out the mention of the pull-up I do think floating is correct in this context. It is a matter of terminology and a fuzzy area but the input is switched between low impedance drive output and high impedance input. The line should be/must be pulled high by (quite a strong) pull-up resistor but the input is indeed set to a floating high impedance state, it does not drive the line.

    Robert
  • Thank you, I got it working using GPIO and some timing logic.
  • Great!

    GPIO + timing is probably the simplest and best way to do interface with those weird interfaces.

    Consider maybe getting a DHT22 latter if you require better precision. Should be easy to use since they seem to have the exact same interface.
    A compaction of the 2 + another sensor: www.kandrsmith.org/.../calib_dht22_dht11_sht71.html
  • Below is driver for DHT11 and DHT22 (just enable #define in header). To use on main() first call dht_init() and then call dht_readTH(&th); where th is a struct defined in driver header.

    this is the driver header:

    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_types.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_timer.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "driverlib/timer.h"
    
    
    #ifndef __DHT22_H
    #define __DHT11_H
    
    // default is DHT22 = RHT03
    #define DHT11_DISABLED
    
    #define DHT_PORT_PERIPH SYSCTL_PERIPH_GPIOF
    #define DHT_PORT GPIO_PORTF_BASE
    #define DHT_PIN GPIO_PIN_4
    
    #define DHT_TIM_PERIPH	SYSCTL_PERIPH_TIMER5
    #define DHT_TIM_BASE	TIMER5_BASE
    #define DHT_TIM			TIMER_A
    
    #define MCU_CLOCK SysCtlClockGet()
    #define DHT_WAIT_18ms ((MCU_CLOCK*18)/3000)
    #define DHT_WAIT_20us ((MCU_CLOCK*2)/300000)
    
    #define DHT_TIMEOUT ((MCU_CLOCK*9)/100000) // 90us
    #define DHT_TIME_BIT_1 ((MCU_CLOCK*7)/100000) // 70us
    
    #define DON()		GPIOPinTypeGPIOOutput(DHT_PORT, DHT_PIN)
    #define DIN()		GPIOPinTypeGPIOInput(DHT_PORT, DHT_PIN)
    
    #define DHT_DATA(__DATA__)	GPIOPinWrite(DHT_PORT, DHT_PIN, (__DATA__))
    #define DHT_READ	GPIOPinRead(DHT_PORT, DHT_PIN)
    
    
    typedef struct {
        float celsius_temp;
        float humidity;
    } DHT_TypeDef;
    
    
    // Interface
    void dht_init(void);
    uint8_t dht_readTH(DHT_TypeDef *);
    
    
    
    #endif
    

    and this is the actual driver

    #include "ms_dht11.h"
    
    
    // Private methods
    static float dht_readTemperature(void);
    static float dht_readHumidity(void);
    static uint8_t dht_read(void);
    static void DHTIntHandler(void);
    
    
    // Private data
    uint8_t data_buffer[6];
    uint32_t dht_timing;
    bool quit_timing = false;
    
    
    
    void dht_init() {
    
    	SysCtlPeripheralEnable(DHT_PORT_PERIPH);
    	SysCtlPeripheralEnable(DHT_TIM_PERIPH);
    
        TimerConfigure(DHT_TIM_BASE, TIMER_CFG_ONE_SHOT_UP);
        TimerLoadSet(DHT_TIM_BASE, DHT_TIM, DHT_TIMEOUT+1000);
    
        // set interrupt for counter
        GPIOIntEnable(DHT_PORT, DHT_PIN);
    	GPIOIntTypeSet(DHT_PORT, DHT_PIN, GPIO_BOTH_EDGES); // config interrupt both edges
    	GPIOIntRegister(DHT_PORT, DHTIntHandler);
    
    	DON();
        DHT_DATA(DHT_PIN);
    
    }
    
    
    // RETURN:
    // 1 = success reading from sensor;
    // 0 = error on reading from sensor;
    // also return T and H
    
    uint8_t dht_readTH(DHT_TypeDef *values) {
    
        if (dht_read() == 1) {
            // temperature
            values->celsius_temp = dht_readTemperature();
    
            // humidity
            values->humidity = dht_readHumidity();
    
            return 1;
        }
    
        return 0;
    }
    
    
    float dht_readTemperature() {
    
        float t;
    
    #ifdef DHT11
        t = data_buffer[2];
    #else
    
        t = data_buffer[2] & 0x7F;
        t *= 256;
        t += data_buffer[3];
        t /= 10.0;
    
        if (data_buffer[2] & 0x80)
            t *= -1.0;
    
        if (t > 80.0) {
        	t = 80.0;
        }
        if (t < -40.0) {
        	t = -40.0;
        }
    
    
    #endif
    
        return t;
    }
    
    
    float dht_readHumidity() {
    
        float h;
    
    #ifdef DHT11
        h = data_buffer[0];
    #else
        h = data_buffer[0];
        h *= 256;
        h += data_buffer[1];
        h /= 10.0;
    
        if (h > 100.0) {
        	h = 100.0;
        }
        if (h < 0.0) {
        	h = 0.0;
        }
    
    #endif
    
        return h;
    }
    
    
    
    uint8_t dht_read(void) {
        uint8_t ii, byteIdx, bitCounter;
    
    
        // clear data
        for (ii=0; ii< 5; ii++)
            *(data_buffer + ii) = 0;
    
    
        // send start signal low and wait 1-18 ms
        DON();
        DHT_DATA(0x00);
        SysCtlDelay(DHT_WAIT_18ms);
    
        // send pull up signal high and wait 20-40 us
        DHT_DATA(DHT_PIN);
        // wait at least 20us
        SysCtlDelay(DHT_WAIT_20us);
        DIN();
        while(GPIOPinRead(DHT_PORT, DHT_PIN) == DHT_PIN);
    
        // acknowledge ~80us low
        while(GPIOPinRead(DHT_PORT, DHT_PIN) == 0x00);
        // acknowledge ~80us high
        while(GPIOPinRead(DHT_PORT, DHT_PIN) == DHT_PIN);
    
        // gets data 5 bytes, 40 bits
        // every bit start with low level for 50us then high level last
        // 0 = 26-28us
        // 1 = 70us
        byteIdx = 0;
        bitCounter = 7;
        for (ii=0; ii<40; ii++) {
        	quit_timing = false;
        	//SysCtlDelay(DHT_WAIT_50us);
    
            // do elaboration
        	while(!quit_timing) {
        		if (dht_timing > DHT_TIMEOUT) {
        			UARTprintf("timeout\r\n");
        			return 0;
        		}
    
        	}
    
            // check bit (timing is 1us) 26-28 -> 0 - 70us -> 1
            if (dht_timing > DHT_TIME_BIT_1) {
                data_buffer[byteIdx] |= (1 << bitCounter);
            }
    
            if (bitCounter == 0) {
                bitCounter = 7;
                byteIdx++;
            } else
                bitCounter--;
    
        }
    
        // check we read 40 bits and that the checksum matches
        if ((byteIdx == 5) && (data_buffer[4] == ( (data_buffer[0] + data_buffer[1] + data_buffer[2] + data_buffer[3]) & 0xFF) ) ) {
            return 1;
        }
    
    
        return 0;
    
    }
    
    
    void DHTIntHandler()
    {
    
    	volatile int32_t start_timer;
    
    
    	GPIOIntClear(DHT_PORT, DHT_PIN); // clear interrupt flag
    	if (GPIOPinRead(DHT_PORT, DHT_PIN) == DHT_PIN) { // check low to high
    		TimerEnable(DHT_TIM_BASE, DHT_TIM);
    		start_timer = TimerValueGet(DHT_TIM_BASE, DHT_TIM);
    		quit_timing = false;
    	} else { // check high to low, finish
    	    TimerDisable(DHT_TIM_BASE, DHT_TIM);
    	    dht_timing = TimerValueGet(DHT_TIM_BASE, DHT_TIM);
    	    dht_timing -= start_timer;
        	quit_timing = true;
        	HWREG(DHT_TIM_BASE + TIMER_O_TAV) = 0;
    	}
    
    }
    

    Hope this helps

  • Thanks, I'm gonna give it a try
  • Well, maybe you should just comment lines about timeout:

    while(!quit_timing) {
    // if (dht_timing > DHT_TIMEOUT) {
    // UARTprintf("timeout\r\n");
    // return 0;
    }

    This is not production code ;-)
  • Not sure why, but the code wont compile after I call dht_init() on main().
  • First of all I assume you have included the header file in your main file. Then, if program does not compiles, CCS gives you an error. Can you please post the compiler error?

  • Hi, I have the same problem with that code. When I call dht_init() on main.
    Did you solve it?
    If yes, could you help me?
    thks!
  • EK_TM4C123GXL.cmd", line 65: error #10099-D: program will not fit into available memory. run placement with alignment fails for section ".vtable" size 0x26c , overlaps with ".vecs", size 0x360 (page 0)
  • For me the driver works well. For your error please see this link  or this threads  Basically the issue had something to do with the version of the ARM compiler. Do you have compiled other projects ?

  • Yes, I had compile another project fine, when I insert into that project this code it compile too. However, when I call this function "dht_init()" into the main, more specifically occur error when this line is called "GPIOIntRegister(DHT_PORT, DHTIntHandler);"
  • Hello Hermes,

    What is the value of DHT_PORT being used?

    Regards
    Amit
  • Hi Amit,

    Thanks for your reply!

    DHT_PORT is defined as GPIO_PORTB_BASE         0x40005000  // GPIO Port B and the value is the same 0x40005000.

    do have any idea for change this value?


    BR

    Hermes

  • DHT_PORT is defined as GPIO_PORTF_BASE. 

    Ok, attached is a complete CCS project for DHT11. If you use DHT22 read ms_dht11.h comments.

    Hope this helps

    MicheleDHT.zip

  • Thks Michele for you reply.

    I´ll to try it.

    Hermes

  • Hello Michele.

    I built the original project that you sent without errors. But, when I debugged in my board, the Temperature (T) and Humidity (H) always returned 0.

    I realized that the dht_readTH() always return zero, so, the variable didn´t return the T and H values. I tried to follow the code and see where does it crash, but, I couldn´t recognize the error. I printed it and attached here to you in a zip file (3 photos). 

    Did you have these problem too?

    Thank you Michele.

    Hermes

    dht_readTH() returning problem.rar

  • Hi Hermes,

    first check in ms_dht11.h this lines:

    // default is DHT11, comment this define for DHT22 = RHT03
    #define DHT11

    Then, are you sure your module is 3.3V compatible? I hope so.

    After that I suspect there are timing issues. I've used a DHT11 with a 1K resistor (I do not use a module like the ones I see in the photos you sent me). So I suggest tweaking with thiis values

    #define DHT_TIMEOUT ((MCU_CLOCK*9)/100000) // 90us

    #define DHT_TIME_BIT_1 ((MCU_CLOCK*7)/100000) // 70us

    and myabe with 

    #define DHT_WAIT_18ms ((MCU_CLOCK*18)/3000)
    #define DHT_WAIT_20us ((MCU_CLOCK*2)/300000)

    If you have a logic analyzer things are more simple.

    Otherwise you can sent me the schematics of your module and I'll try to figure out what's the problem.

    Regards

    Michele

  • Hi Michele,

    I used the ms_dht11.h and ms_dht11.c from the above zip file in my code . In the main code I've written this:
    void main(void) {

    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |SYSCTL_XTAL_16MHZ);

    dht_init();
    while(1)
    {
    dht_readTH(&values);
    THValue[0]=values.celsius_temp;
    THValue[1]=values.humidity;

    }

    I've used a 4.7K resistor to pull up the data pin on DHT22.
    The problem is however sometimes the code returns the correct values from DHT22 and sometimes it returns 0.

    Can you please tell why it's returning zero.

    Regards
    Praveen
  • Hello Praveen

    You can connect a scope probe to see what is happening on the bus w.r.t. to the data being read.
  • Well,
    I think the problem is that your loop has no some kind of delay. The datasheet of the sensor says that "Sampling period at intervals should be no less than 1 second" (and for DHT22 should be beyond 2 sec.). So my suggestion is to put a delay in the loop and see if happens again.

    Regards
    Michele
  • Hello!

    How did you manage to get the correct values?

    I'm stuck getting only zeros


    I'm using the project that Michele SCAFOGLIERI uploaded

    Thanks!!
  • Hello,

    It was some time ago, but if I remember correctly, you should adjust timers to be in sync with the sensor. Take a look at the DHT11 datasheet and set interrupts to the intervals specified there, if it doesn't work (you may get wrong readings, like I did), try changing these intervals to a little longer or a little smaller till you get the correct values. Pay attention when converting the sensors data, since it is a bit strange.

    I would share the code, but I really have no ideia where are the files...

  • Hey!

    First of all, thanks for your quick reply

    Do you remember by any chance if you just needed to adjust the timers in the dht_read function or if it was necessary to adjust the interrupt's timers as well?

    I'll try changing the timing intervals,

    thanks!

    PS: I connected a scope probe to the data channel and for what I can tell, I'm getting a response back but I'm reading it wrong with the code used
  • I didn't use this function, just created a new one. It was something like a interruption to send a request to the sensor and then the timer interruptions to read the bits recieved (add a bit counter to control it). But I think it could work if you try to adjust the dht_read function, just don't forget that you have to wait some time between readings.

    If you are getting a wrong response, it is likely that you are losing sync during reading (a bit counter with some timing adjustments may solve it) or the conversion is wrong.
  • Thanks! I got it to work properly now.

    Following your advice, I adjusted the timing intervals and it worked!

    Thanks again.