DHT11 in hardware

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

I have a few DHT11 sensors and a couple psoc 4's and a psoc 3 030 dev kit.  I found some discussions, questions, and posted projects on this forum which did not work and finally I found this project online.  I need to build it and test it and will soon.

   

I'm trying to get the DHT11 to work with either / both my psoc 4 and psoc 3 devices.  There are a couple approaches to do this.  The first is to do it all in code like the arduino guys do and the online project mentioned above where you set the chip to "CYEnterCriticalSection()" for timing and increment a variable as a reference count and compare the chip signals to that reference and determine if it is a 1 or a 0 and build the bytes.  I think that is a pretty clever solution, but it defeats the purpose of psoc which is to use the analog and digital peripheral capabilities.  

   

My intent here with this post isn't to get you to do work for me.  I want to understand how to make the chip do my bidding and right now I simply "don't get it."  I'm not going to post a complete project at first for you to fix and send back.  I'd really like a description of how I should approach the problem so next time I'm not running back here for someone to do it for me again.

   

Specifics:  DHT11 uses a 1 wire communication that is pulled high.  The user pulls the data pin low for 18 ms, then releases it and the chip responds with a 80 uSec low pulse, an 80 uSec high pulse and then a 40 bit data stream.  Each bit is prefaced with a 50 us low section followed by a "high" bit of either 26 us or 70 us to indicate a 0 or 1 respectively.  

   

My attempt with the timer component:  

   
    

measure this 26 uSec or 70 uSec high signal on the pin using a timer component

   
   
    

clock it at 1 mhz, period at 200 for a (200 us)

    

reset with a 0 and enable it in software after pulling pin low for 18 ms while the pin is high

    

wire the data input pin (set as bidirectional) to both the trigger and capture inputs

    

trigger on the rising edge and capture on the falling edge

    

Enable in software

   
   

I don't have a scope to see any of this, so I don't know if it works, but I bought 4, so I'm pretty sure one should work.  

   

My questions:

   

1.  Can you use the same line to trigger and capture in a timer component?

   

2.  How do you set up the ISR so you don't miss the next pulse?  It needs to clear the ISR and determine if the pulse time is > 30 uSec to store a 1.  What needs to be serviced in the ISR so it keeps running?  I understand it counts down from the period max, in this case 200.  

   

3.  Am I even on the right track here?  Is the software method in the online example the best way to do this or is there an even better way that is simpler and more efficient? 

   

4.  What does the tc output and interrupt output do on the top design timer block?  I don't think I need those.

   

5.  Should I use a shift register component to feed in the 1's 0's and build the bytes for the measured value?

   

Thanks for any perspective or information you can offer.

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.
EvPa_264126
Level 7
Level 7
500 replies posted 250 replies posted 100 likes received

You can use interrupt instead of shift registers:

View solution in original post

0 Likes
24 Replies
EvPa_264126
Level 7
Level 7
500 replies posted 250 replies posted 100 likes received

sensor uses a single wire interface (not 1-wire.)
I used a ready-made library for DTH11 (https://github.com/tarasii/DTH11).
My project for PSoC4   DHT11.cywrk.Archive01.zip    it  here.
I do not use the PSoC analog and digital peripheral capabilities)))
But maybe it will help you at the start.
ps Strange - Your English is poorly understood my translate.google))

0 Likes
Anonymous
Not applicable

@pavloven, Thanks for responding.  one wire or single wire sound similar to me, but one is a standard, so I described that incorrectly.  

   

My main question is: why would you not use a digital peripheral? If you did, how would you do it?

   

Sorry about my english.  I speak somewhat "western American" and I'm a material scientist, so I'm not speaking EE either.  I'll see if I can get it to work with your code and project.  Thanks again for taking time to reply.

0 Likes
EvPa_264126
Level 7
Level 7
500 replies posted 250 replies posted 100 likes received

It is difficult to think of something, if the solution is already there.
Ready-made  library   not use  of hardware.

   

My friend was doing hardware 1-wire.
I think it is too difficult:

   

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

This is another wonderful example of the flexibility PSoCs can give you: You can use a completely software controlled solution (which is required when you use a dumb microcontroller), you may use a completely hardware driven solution (which frees the CPU from burning MIPS) or you can use a combination of both to suit your needs and abilities.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

@pavloven,  I had found your library and tried it to make it work yesterday and it didn't.  Need to double check the wiring.  I had a question on the code:

   
    

for(i=0;i<83 && cnt<MAX_TICS;i++){        // why 83 and not 40?  Is it one iteration for each edge?
        if (i & 1){
            cnt = read_cycle(cnt, 1);
        }
        else {
            cnt = read_cycle(cnt, 0);
            dt[i/2]= cnt;                 // i/2... gives you an array that is written over twice at each item
        }
    }

    

when I tried your code, I got 512 for the temperature and no humidity value.

   
0 Likes
EvPa_264126
Level 7
Level 7
500 replies posted 250 replies posted 100 likes received

83 - I think it is the amount of change of contact  Data.
The project works you can-see)))
Data pin - Resistive pull up!

   

0 Likes
Anonymous
Not applicable

I'll check my contacts and try again.  I do have a 5 k pullup on the line.

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Ported to the psoc3 030 kit and tried it with a 1k and a 10 k pullup and I get 768 or 1024 °C.  It certainly is not that hot in here.  Tried 2 different sensors and I get the same thing.  I'll try it with the 4200 usb proto board.

0 Likes
EvPa_264126
Level 7
Level 7
500 replies posted 250 replies posted 100 likes received

Yes, I see it is if I change the IMO on 48 MHz
This is a consequence of simplicity solutions in the program read_cycle () and convert data.
Try to choose the frequency of IMO ((
Or change the comparison threshold of 0/1 in a row 52 dht11.c:
//convert data
 .......
      if (dt>xx) {     //  xx - threshold  for 0 /1
.......

0 Likes
Anonymous
Not applicable

Comparison threshold should increase if clock is too fast?  that makes sense... if the threshold is too low, then everything is a 1 and the result is a higher number.

   

I changed the IMO from 48 to 24 and no change.  I'll try changing the threshold.  Thanks for responding and for posting the original code.  I appreciate your time and willingness to help.  More than just getting it to work, I'd like to better understand how it works.  Then I can create my own solution with confidence it will work.

0 Likes
lock attach
Attachments are accessible only for community members.
EvPa_264126
Level 7
Level 7
500 replies posted 250 replies posted 100 likes received

Yes, I set 40 for  48Mhz
I made a simple control.
Change the item number for dt[..]  and look at the number on the display:

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

I tried it and with a denominator (xx mentioned above) of 1-30 it didn't work as a uint8.  it was counting as 1,2,4,8,16,32,128, so I changed all the uint8 variables to uint16 and it counts 1,2,3...

   

 

   

   for(;;){
        
        res = read_DHT11(buf, Denom);
        sprintf(strDisp, "RH=%02d%% t=%dC     ", buf[0], buf[2]);
        LCD_Char_Position(0,0);
        LCD_Char_PrintString(strDisp);
        sprintf(strDisp, "Denom = %d  ", Denom);
        LCD_Char_Position(1,0);
        LCD_Char_PrintString(strDisp);
        if (Denom++ > 30){
            Denom = 1;
        }
        CyDelay(200);
    }
}

   

in the dht11.c file I put:

   

...

   

if (dt>Denom) {

   

...

   

so the program counts though the 30 denominator values and none of them are reasonable at 24 or 48 MHz

   

at 48 mhz, it looks like this

   

Denom    RH 

   

1       0

   

2  -255

   

3  -1 (to 7)

   

8  -222 

   

9  -255

   

11    7967  5654  (same to 30)

   

None of these are remotely close.  

   

At 24 MHz it is similar but above 12 they go to 0.

   

If I set the main oscillator at 12 MHz, the denominator looks reasonable when it is 1.

   

but only for the first read...

   

Turns out i had to reset the buf[] to 0 for array elements 0 and 2 before each call and set all uint variables from uint8 to uint16.  now it works...

   

   

it works for denom 1,2,3,4.

   

When I up the clock back to 24 MHz, the denom works for 2,3,4,5,6,7,8,9,10,11

   

and 48 mhz, the denom works from 8 to 27.  

   

The key was to clean the arrays so the bits don't add from one measurement to the next.  I've attached a copy of the 48 MHZ file set for 3.3V that walks through denominators 1-30 to read the DHT11 for the CY8CKIT-030 with the code changes.

   

@pavloven: THANK YOU!  The sensors are good and I know they provide real data.

   

 

   

 

   

Now back to the original question.  Shouldn't a precision clock in a digital peripheral and make this work the same?

   

I think something like a timer with a 1 MHz clock, trigger on a rising edge, capture on a falling edge and save a 1 or zero based on the captured time value?  I have not yet gotten that to work.

   

0 Likes
lock attach
Attachments are accessible only for community members.
EvPa_264126
Level 7
Level 7
500 replies posted 250 replies posted 100 likes received

Only attempt ...

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Here's my attempt (not working).  I'll try yours.

0 Likes
lock attach
Attachments are accessible only for community members.
EvPa_264126
Level 7
Level 7
500 replies posted 250 replies posted 100 likes received

This works, but it is very wasteful on resources.
I use another contact P0_1 instead P4_1

   

and You are wrong to connect the timer - Data should be rather than Vcc))

0 Likes
Anonymous
Not applicable

I've been looking at examples like this one that use the timer to measure the pulse width: convert from pulse width to 1's and 0's.  

   

I'm not sure where I used Vcc instead of data.  Thanks for your continued interest.

0 Likes
lock attach
Attachments are accessible only for community members.
EvPa_264126
Level 7
Level 7
500 replies posted 250 replies posted 100 likes received

You can use interrupt instead of shift registers:

0 Likes
Anonymous
Not applicable

ok now that's cool!  That is what I was trying to do with the timer, but I didn't know how to get it into the bit array.

   

I see you have the ISR function just above main.  You trigger the start of the send with the control register and read the signal with a PWM.  I didn't know you would or could ever use a PWM like that.  So you start the pwm at the end of each 50 usecond pulse and then its interrupt reads the data pin at 70 us.  If it is a 0, the line will be low because it will be in the next bit's 50 us start and if it is a 1, it will be high because it is a longer pulse.  I would worry about the line being sometimes high and sometimes low if you trigger it at 70 us each time and that would be right at the end of the bit time sequence for a 1.  It works though straight out of the box.  I'll be changing the period to see how that affects it.

0 Likes
Anonymous
Not applicable

it looks like a period of 76-53 will work and give a reasonable response.

   

I changed the C in Main of the ISR example project as follows:

   

int8 period = 70;

   

... (inside the for loop)

   

       

   

        LCD_Char_Position(0,7); LCD_Char_PrintString("  T = ");
        LCD_Char_PrintNumber(t); LCD_Char_PrintString("     ");
        LCD_Char_Position(1,0); LCD_Char_PrintString("pwm period = ");
        LCD_Char_PrintNumber(period);
        PWM_WritePeriod(period--);
        if (period < 30) period = 80;

0 Likes
Anonymous
Not applicable

I would expect it to work at 30 us , but not at 70 us.  For the initial DHT delay, it would expect a 0 for bit 0, a 1 for bit 1, then a 0 for bit 2 and a 0 for bit 3.  I put the bit numbers in red, circled the rising edge where they would enable the pwm.  At a period of 69 for 70 us, for bit 2, it would interrupt right at the edge of the pulse, so when you read the pin, it could be on the falling edge and may be misread as a 0.  Bit 3 (I would expect) would read correctly down to 28 or 30 us.  Am I looking at the wrong trigger edge?

   

   

0 Likes
lock attach
Attachments are accessible only for community members.
EvPa_264126
Level 7
Level 7
500 replies posted 250 replies posted 100 likes received

PWM pulse may be short.
I hope the picture more clearly display the idea.

0 Likes
Anonymous
Not applicable

I see it now.  At first it appeared that the pwm was interrupting after the period was complete, but it is actually initiating the ISR after the 34 us count comparison.  Since the compare value is 34, that is where the pin read is performed and the line will be low or high for a 1 or a 0.  34 is > 26 and < 70 so the 0 and 1 should be easily distinguished.  I would expect for this to work the boxes for "Interrupt on Compare 1 Event" would need to be checked.  It works and it is not checked.

   

   

I made a fresh project and from scratch tried to recreate this to see if I really understood what was going on.  It didn't work by simply starting the ISR:

   

isr_1_Start():

   

it only worked with:

   

isr_1_StartEx(isr_cnt);

   

I didn't see that in any of the the code examples and seems counter intuitive.  If you did it with the "isr_1_Start()" command would you need to put your isr code in the isr_1.c file? 

   

0 Likes
EvPa_264126
Level 7
Level 7
500 replies posted 250 replies posted 100 likes received

Yes, you can save the code in isr_1.c. But it will be lost in the transition from PSoC3 to PSoC5.
I  delete the whole folder PSoCx before archiving.
_StartEx (...) - Creates certainty in the code location.
 see    AN54460 - PSoC® 3 and PSoC 5LP Interrupts

Anonymous
Not applicable

Thanks for the link.  I watched the video and read the pdf.

0 Likes