Helpful ReplyHot!DH11 with PIC18F4550

Page: 123 > Showing page 1 of 3
Author
eagle1
Super Member
  • Total Posts : 309
  • Reward points : 0
  • Joined: 2014/11/02 03:04:06
  • Location: Saudi Arabia
  • Status: offline
2018/08/15 12:12:09 (permalink)
0

DH11 with PIC18F4550

Hello,
 
I'm trying to get the DH11 working precisely. I fixed as much as I could in the code, but I still get parity error all the time.
 
I tried to follow different styles from online codes, I also got a lot from my previous NEC decoding strategy. But here I need some help.
 
It's mentioned that the sensor need a pull-up resistor but I read the breakout sensor has an SMD one, so I'm not connecting any, even if I connect one the result doesn't change much.
 
Here's my code:
 
This one to read each 8-bits data:
uint8_t DH11_read_8bits(void)
{
    DH11_code = 0;
    for (i=7;i>=0;i--)
    {
        while(!PORTDbits.RD1); // wait for 0 leading bit
        TMR2 = 0;
        while(PORTDbits.RD1); // high bit 0 or 1
        TMR2_temp = TMR2;
        if((TMR2_temp < 40) && (TMR2_temp > 20))// 0 bit is 26-28us
        DH11_code &= ~(1<<(i));
        else
        DH11_code |= (1<<(i));
    }
    return DH11_code;
}

 
This is the main function:
Note: I'm commenting the parity error part because I get error all the time and the function returns 1.
uint8_t DH11_read(void)
{
  TRISDbits.RD1=0;
  LATDbits.LATD1=0;
  __delay_ms(18); // user 18ms low
  LATDbits.LATD1=1;
  __delay_us(40); // user 40us high
  TRISDbits.RD1=1;
  
  while(!PORTDbits.RD1);// sensor response 80us low
  while(PORTDbits.RD1);// sensor response 80us high
  
  
 HumHigh = DH11_read_8bits();
 HumDeci = DH11_read_8bits();
 TempHigh = DH11_read_8bits();
 TempDeci = DH11_read_8bits();
 parity_sum = DH11_read_8bits();
 parity_check = HumHigh+HumDeci+TempHigh+TempDeci;
  /*if (parity_check != parity_sum)
  {
    LCD_string("parity error");
    __delay_ms(500);
    sendCMD(clear_display);
    return 1;
  }*/
  
  LCD_string("Humi: ");
  move_cursor(1,6);
  sprintf(val_arr,"%.2d",HumHigh);
  LCD_string(val_arr);
  move_cursor(1,8);
  sprintf(val_arr,".%.2d",HumDeci);
  LCD_string(val_arr);
  LCD_string("%");
  move_cursor(2,0);
  LCD_string("Temp: ");
  move_cursor(2,6);
  sprintf(val_arr,"%.2d",TempHigh);
  LCD_string(val_arr);
  move_cursor(2,8);
  sprintf(val_arr,".%.2d",TempDeci);
  LCD_string(val_arr);
  move_cursor(2,11);sendData(0xDF);
  move_cursor(2,12);sendData(0x43);
  move_cursor(2,13);
  __delay_ms(1000);
  sendCMD(clear_display);
}

 
#1
qɥb
Monolothic Member
  • Total Posts : 3329
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/15 13:32:08 (permalink)
+1 (1)
I am a bit suspicious of this bit of code.
  __delay_ms(18); // user 18ms low
  LATDbits.LATD1=1;
  __delay_us(40); // user 40us high
  TRISDbits.RD1=1;
  
  while(!PORTDbits.RD1);// sensor response 80us low
  while(PORTDbits.RD1);// sensor response 80us high
 

You drive RD1 high for 18ms, when the datasheet says to drive it low.
You then raise TRISD1 to let the pin float, then immediately do a while test to see if it is low.
Without a delay there, that first test is always going to fall straight through to the second while.
 
Did you write this code, or is it taken from some library?
 
 

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#2
eagle1
Super Member
  • Total Posts : 309
  • Reward points : 0
  • Joined: 2014/11/02 03:04:06
  • Location: Saudi Arabia
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/15 14:28:10 (permalink)
0
It's actually the instruction before the 18ms delay which drives the pin low, then high for 40us.
1. Configure RD1 output
2. Drive the pin low 18ms
3. Drive it high 40us
4. Configure RD1 as input for receiving the sensor response and following 40-bits data
 
  TRISDbits.RD1=0;
  LATDbits.LATD1=0;
  __delay_ms(18); // user 18ms low
  LATDbits.LATD1=1;
  __delay_us(40); // user 40us high
  TRISDbits.RD1=1;

 

#3
qɥb
Monolothic Member
  • Total Posts : 3329
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/15 16:03:32 (permalink) ☄ Helpfulby eagle1 2018/08/15 16:05:09
+1 (1)
Apologies, posted before my first coffee for the day! ;)
As you say, your 18ms low is correct.
I'm still suspicious of the last two instructions.
 
  TRISDbits.RD1=1;
  
  while(!PORTDbits.RD1);// sensor response 80us low

As I mentioned fall into the first while() loop straight after floating RD1.
The pin will still be high, so the while condition will be false, so it will fall straight through that loop.
  while(PORTDbits.RD1);// sensor response 80us high

This loop will exit when it sees a low, which will happen at the start of the "DHT responds and pulls LOW" pulse in your diagram.
 
That means you will enter your "DH11_read_8bits" function one bit too early.
 

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#4
eagle1
Super Member
  • Total Posts : 309
  • Reward points : 0
  • Joined: 2014/11/02 03:04:06
  • Location: Saudi Arabia
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/15 16:23:41 (permalink)
0
qɥb
Apologies, posted before my first coffee for the day! ;)

Well, it's my 2nd home made cappuccino cup for today, so I know what are you talking about :)
 

As you say, your 18ms low is correct.
I'm still suspicious of the last two instructions.
 
  TRISDbits.RD1=1;
  
  while(!PORTDbits.RD1);// sensor response 80us low

As I mentioned fall into the first while() loop straight after floating RD1.
The pin will still be high, so the while condition will be false, so it will fall straight through that loop.

Sorry, I planned to describe all the necessary details about my setup.
The pin is pulled HIGH by the sensor, it's like the IR receiver, but instead of receiving data during the LOW pulses, it's in the HIGH pulses and the LOW pulses are leading 0 bits.
 
You know what? I even don't think it's necessary to pull the pin HIGH again after pulling it LOW for 18ms, because the pin is already pulled HIGH by the sensor.
 
After the 18ms, the sensor should respond by pulling the pin LOW for 80us and then HIGH for another 80us.
 
So, the first while loop testing the LOW state is for the LOW 80us.
The next while loop testing the HIGH state is for the HIGH 80us.
 

  while(PORTDbits.RD1);// sensor response 80us high

This loop will exit when it sees a low, which will happen at the start of the "DHT responds and pulls LOW" pulse in your diagram.

According to the diagram, after the LOW/HIGH 80us response. Which I included the 2 LOW/HIGH while loops tests for. The start of the data receiving is by pulling the pin LOW for 80us, and this is what I'm testing in the 40-bits function "DH11_read_8bits".
 

That means you will enter your "DH11_read_8bits" function one bit too early.
 

I don't know about this point, maybe I'm falling into this mistake!
 
#5
qɥb
Monolothic Member
  • Total Posts : 3329
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/15 16:33:50 (permalink)
0
eagle1
...
You know what? I even don't think it's necessary to pull the pin HIGH again after pulling it LOW for 18ms, because the pin is already pulled HIGH by the sensor.

Probably not at that point.
It would be receiving the signal, waiting for you to pull it high so it doesn't do it while you are holding it low.
So, driving it high yourself, THEN floating it, speeds everything up a little.
 

After the 18ms, the sensor should respond by pulling the pin LOW for 80us and then HIGH for another 80us.
 
So, the first while loop testing the LOW state is for the LOW 80us.
The next while loop testing the HIGH state is for the HIGH 80us.

As I've already explained, the first while loop is NOT testing the 80us low pulse, because you enter it while the signal is still high, so it exits immediately.
That screws up your following logic.
 

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#6
eagle1
Super Member
  • Total Posts : 309
  • Reward points : 0
  • Joined: 2014/11/02 03:04:06
  • Location: Saudi Arabia
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/15 16:34:00 (permalink)
0
Hmmmm I thought before there's something I have to check about the microcontroller timing!
 
As I'm running the microcontroller at 4MHz, so the instruction cycle is 1us. So I configured the timer with no prescaler, so I count the actual timing for the bits. But I don't know what's going on now.
 
I configured the timer with 1:2 prescaler as I'm running a test code for measuring the bits timings.
 
With no prescaler I get 60 for low bit and 105 for high bit!
With 1:2 prescaler I get 28 for low, 50 for high!
 
#7
eagle1
Super Member
  • Total Posts : 309
  • Reward points : 0
  • Joined: 2014/11/02 03:04:06
  • Location: Saudi Arabia
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/15 16:42:12 (permalink)
0
qɥb
As I've already explained, the first while loop is NOT testing the 80us low pulse, because you enter it while the signal is still high, so it exits immediately.
That screws up your following logic.

What I learned about while loops especially for testing state of pins.
 
For example, when the pin HIGH and the following instruction is testing the LOW state of the pin, that the program is waiting for the execution of this instruction, so as soon as the pin is LOW the while loop is now true and it should loops until the pin is HIGH again and that terminates this while loop.
 
I also found this strategy by most programmers on websites.
 
Check this link:
http://www.electronicwings.com/pic/dht11-sensor-interfacing-with-pic18f4550
 
This man is also including another while loop for HIGH state.
#8
qɥb
Monolothic Member
  • Total Posts : 3329
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/15 16:50:13 (permalink)
+1 (1)
eagle1
...
What I learned about while loops especially for testing state of pins.
 
For example, when the pin HIGH and the following instruction is testing the LOW state of the pin, that the program is waiting for the execution of this instruction, so as soon as the pin is LOW the while loop is now true and it should loops until the pin is HIGH again and that terminates this while loop.

Huh?
I think you are over complicating a very simple situation.
while(!PORTDbits.RD1);// sensor response 80us low

The expression "!PORTDbits.RD1" is "true" when the signal is low.
So, that while instruction will keep looping so long as the signal is low.
If the signal is high when you enter the while loop, it will exit immediately.
If you want to detect a signal transition, then you need to wait while the state before the transition is not present, then wait again while it IS present.
 
 
 

I also found this strategy by most programmers on websites.
 
Check this link:
http://www.electronicwings.com/pic/dht11-sensor-interfacing-with-pic18f4550
 
This man is also including another while loop for HIGH state.

Indeed he is, which is why his code will work, and yours doesn't.

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#9
eagle1
Super Member
  • Total Posts : 309
  • Reward points : 0
  • Joined: 2014/11/02 03:04:06
  • Location: Saudi Arabia
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/15 17:05:02 (permalink)
0
qɥb
 
The expression "!PORTDbits.RD1" is "true" when the signal is low.
So, that while instruction will keep looping so long as the signal is low.
If the signal is high when you enter the while loop, it will exit immediately.
If you want to detect a signal transition, then you need to wait while the state before the transition is not present, then wait again while it IS present.



I totally agree with you that's what I meant, maybe the point I didn't cover is the leading time before entering the while loop for LOW state that I should include another while loop for HIGH state, which I'm doing now in my code.
 
I don't know now I'm getting a reading. The temperature is constant, but the humidity changes when I cover the sensor with my finger.
 

#10
eagle1
Super Member
  • Total Posts : 309
  • Reward points : 0
  • Joined: 2014/11/02 03:04:06
  • Location: Saudi Arabia
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/16 05:17:07 (permalink)
0
I measured the first 3 while loops:
  TMR2 = 0;
  while(PORTDbits.RD1);
  TMR2_val[0] = TMR2; 
  TMR2 = 0;
  while(!PORTDbits.RD1);// sensor response 80us low
  TMR2_val[1] = TMR2;
  TMR2 = 0;
  while(PORTDbits.RD1);// sensor response 80us high
  TMR2_val[2] = TMR2;

 
I get 21, 77, 83
 
Which is reasonable, but one interesting issue is that I can test the pin even it's not configured as an input!
 
So why I have to configure the pin as an input where I can test the received pulses as the pin is output?
 
Update:
 
I want to test all the timings of this sensor, with this code.
 
The first 3 while loops measurements are reasonable. But the next 40-bits are far way of the dedicated timings in the diagram and datasheet. I get 60 for LOW bit and 105 for HIGH bit! Why?
 TMR2 = 0;
 while(PORTDbits.RD1);
 TMR2_val[0] = TMR2;
 TMR2 = 0;
 while(!PORTDbits.RD1);// sensor response 80us low
 TMR2_val[1] = TMR2;
 TMR2 = 0;
 while(PORTDbits.RD1);// sensor response 80us high
 TMR2_val[2] = TMR2;
   for (i=3;i<43;i++)
   {
       while(!PORTDbits.RD1); // wait for 0 leading bit
       TMR2 = 0;
       while(PORTDbits.RD1); // high bit 0 or 1
       TMR2_val[i] = TMR2;
   }

 
post edited by eagle1 - 2018/08/16 05:24:29
#11
qɥb
Monolothic Member
  • Total Posts : 3329
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/16 06:46:36 (permalink) ☄ Helpfulby eagle1 2018/08/16 08:34:10
+1 (1)
You can always test the state of a pin.
The TRIS register is just used to enable/disable the output driver.
 

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#12
eagle1
Super Member
  • Total Posts : 309
  • Reward points : 0
  • Joined: 2014/11/02 03:04:06
  • Location: Saudi Arabia
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/16 08:06:44 (permalink)
0
OK, what I'm doing now is that I want to measure the time of each bit. I don't know if the way I'm doing is correct.
 
First of all, I have to initiate the transmission, by this code:
 
TRISDbits.RD1=0;
LATDbits.LATD1=0;
__delay_ms(18); // user 18ms low
LATDbits.LATD1=1;
TRISDbits.RD1=1;
TMR2 = 0;

 
After that, I have to measure the start and response pulses:
Start is 18ms LOW/20us HIGH by the user
Response is 20us HIGH/80us LOW/80us HIGH by the sensor
while(PORTDbits.RD1);// leading HIGH pulse
TMR2_val[0] = TMR2;
TMR2 = 0;
while(!PORTDbits.RD1);// sensor response 80us low
TMR2_val[1] = TMR2;
TMR2 = 0;
while(PORTDbits.RD1);// sensor response 80us high
TMR2_val[2] = TMR2;

 
Then measure the 40-bit, and here where I have the problem of measuring the timings, I don't get like 26-28us for 0 bit and 70us for 1 bit. I get like 60us for 0 bit and 105 for 1 bit.
for (i=3;i<43;i++)
{
    while(!PORTDbits.RD1); // wait for 0 leading bit
    TMR2 = 0;
    while(PORTDbits.RD1); // high bit 0 or 1
    TMR2_val[i] = TMR2;
}

 
What I'm doing wrong here?
#13
eagle1
Super Member
  • Total Posts : 309
  • Reward points : 0
  • Joined: 2014/11/02 03:04:06
  • Location: Saudi Arabia
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/16 12:02:06 (permalink)
0
This video I recorded this afternoon:
https://www.youtube.com/watch?v=zeEC5qLpjEc
#14
eagle1
Super Member
  • Total Posts : 309
  • Reward points : 0
  • Joined: 2014/11/02 03:04:06
  • Location: Saudi Arabia
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/18 11:15:37 (permalink)
0
Update:
 
OK, I did a test with my Arduino board and AVR-GCC code, and the results are impressive!
 
I got the precise timings for the DH11, but I couldn't get the same results with the PIC18F4550, why? I really don't know what could affect the timings measurements process for the PIC18F4550!
 
The Arduino is really fast running at 16MHz with instruction cycle of 62.5ns, so running the timer0 with prescaler of 8 so timer runs at 0.5us and multiplying the timer results with 2 I can get 1us timer resolution.
 
And then I run the DH11 test code for measuring the bits timings and it worked.
 
Here's my code:
#include <avr/io.h>
#include <util/delay.h>
#include <inttypes.h>
#include "I2C_m.h"
#include "sensors.h"


void DH11_init(void)
{
  _delay_ms(2000);
  TCCR0B = 0x02; // enable timer0
}


void DH11_read(uint8_t *bits_timing)
{
 uint8_t i;
 DDRB = 0xFF; // Pin0 output
 PORTB &= ~(1<<PB0);
 _delay_ms(18);
 PORTB |= (1<<PB0);
 DDRB = 0xFE;
 
 TCNT0=0;
 while((PINB & (1<<PINB0)));
 bits_timing[0]=TMR0_MSK;
 
 TCNT0=0;
 while(!(PINB & (1<<PINB0)));
 bits_timing[1]=TMR0_MSK; 
 
 TCNT0=0;
 while((PINB & (1<<PINB0)));
 bits_timing[2]=TMR0_MSK; 
 
 for (i=3;i<43;i++)
    { 
        while(!(PINB & (1<<PINB0))); // wait for 0 leading bit
        TCNT0=0;
        while(PINB & (1<<PINB0)); // high bit 0 or 1 
        bits_timing[i] = TMR0_MSK;
    }
}

 
#15
eagle1
Super Member
  • Total Posts : 309
  • Reward points : 0
  • Joined: 2014/11/02 03:04:06
  • Location: Saudi Arabia
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/18 15:34:24 (permalink)
0
qɥb
You can always test the state of a pin.
The TRIS register is just used to enable/disable the output driver.

In AVR I can't test the pin if it's configured as an output!
#16
1and0
Access is Denied
  • Total Posts : 8351
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/18 22:37:54 (permalink)
0
eagle1
Then measure the 40-bit, and here where I have the problem of measuring the timings, I don't get like 26-28us for 0 bit and 70us for 1 bit. I get like 60us for 0 bit and 105 for 1 bit.
for (i=3;i<43;i++)
{
    while(!PORTDbits.RD1); // wait for 0 leading bit
    TMR2 = 0;
    while(PORTDbits.RD1); // high bit 0 or 1
    TMR2_val[i] = TMR2;
}

What I'm doing wrong here?

In your video, I don't see the variable i being declared in your function, so it must be a global variable. If so, what is its type?
 
Anyway, try unrolling the for() loop and see what timings you get. Also, is there any interrupt enabled?
#17
qɥb
Monolothic Member
  • Total Posts : 3329
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/18 23:16:00 (permalink)
+1 (1)
eagle1
qɥb
You can always test the state of a pin.
The TRIS register is just used to enable/disable the output driver.

In AVR I can't test the pin if it's configured as an output!

Which AVR?
That would make it awkward to toggle an LED if you can't test the current value.

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#18
1and0
Access is Denied
  • Total Posts : 8351
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/19 04:28:47 (permalink) ☄ Helpfulby eagle1 2018/08/19 10:00:12
+1 (1)
Replace this
TRISDbits.RD1=0;
LATDbits.LATD1=0;
__delay_ms(18); // user 18ms low
LATDbits.LATD1=1;
TRISDbits.RD1=1;

 
with this
TRISDbits.RD1=0;
LATDbits.LATD1=0;
__delay_ms(18); // user 18ms low
LATDbits.LATD1=1;
__delay_us(20); // user 20us high <<<<<
TRISDbits.RD1=1;

 
#19
1and0
Access is Denied
  • Total Posts : 8351
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: DH11 with PIC18F4550 2018/08/19 05:29:17 (permalink) ☄ Helpfulby eagle1 2018/08/19 10:00:21
+2 (2)
I've followed most of your threads and it looks to me you have a tendency to complicate things. Take this snippet from your Post #1 as an example,
if((TMR2_temp < 40) && (TMR2_temp > 20))// 0 bit is 26-28us
DH11_code &= ~(1<<(i));
else
DH11_code |= (1<<(i));

here it considers a width of 21-39 us is a "0" bit, and a "1" bit has a width of less than 21 us (which is wrong) or a width of greater than 39 us. Why make this so complicated when you know you're reading the data bits here? The result will be either a "0" or a "1" so just use a threshold to determine the bit, such as the mid point (28+70)/2 = 49. That is, if TMR2_temp is less than 49 us it's a "0" else it's a "1".
 
Also, if you have read and understood what I posted in your other thread(s), you will know operation such as (1<<(i)) is _not_ very efficient on an 8-bit PIC device. In that same thread, I've discussed that shifting the data byte is more efficient, as it takes only one shift instruction (RLF or RRF); whereas the number of shift instructions for (1<<(i)) depends on the value i, not to mention the overhead of a loop.
#20
Page: 123 > Showing page 1 of 3
Jump to:
© 2018 APG vNext Commercial Version 4.5