Jump to content


Photo

DHT11 Low Cost Humidity and Temperature Sensor


6 replies to this topic

#1 gunta

gunta
  • Members
  • 6 posts

Posted 22 September 2011 - 01:21 PM

Hi, I am currently working with DHT11 humidity and temperature sensor. It uses 1 IO pin for communication line. First, I though the communication protocol is 1-Wire and should be easily integrated with Labjack using 1-Wire low-level command. However, after read the datasheet in more detail, I found that the communication protocol is not a standard one. The DHT11 communication protocol has it own specification. The host (master) should first starts the communication with one low (0) signal at least 18ms length, then release the line. After the DHT11 senses the start communication command, it sends 1 pulse of 160us period, then starts sending the data. The bit of data is the length between the rise and fall of the line, which are in 20-26 us for '0' logic and 50us for '1' logic. The total number of the data bits is 40. Could you please help me programming my Labjack to communicate with DHT11? Is the bit bang mode applicable? Thank you for your support. Best Regards,

#2 LabJack Support

LabJack Support
  • Admin
  • 8323 posts

Posted 23 September 2011 - 06:44 AM

This looks like it is going to be difficult. You will need an oscilloscope and probably a logic analyzer. I think you can generate the start condition using a feedback command and then use stream to read read the IO state at 50kHz. The data from the stream would then need to be analyzed to extract the data. It would be much easier to use a part with a standard communication interface such as I2C, SPI, 1-wire, UART. Or even the sensibus that Sensrion uses. Sensirion makes several temperature / humidity sensors that are easy to connect to LabJack DAQs.

#3 gunta

gunta
  • Members
  • 6 posts

Posted 24 September 2011 - 03:04 AM

Yes, it is going to be difficult, because I cannot find the built in api/low-level function, and I have not found someone post any code for this device. However, it is a challenge. Thank you for your suggestion. I agree of using feedback command to send start command. With regards the IO state, I am not sure 50k sample/sec is adequate. The shortest time is 26us, which needs at least 26/5 = 5 us time spacing to capture accurate state, or about 200k sample/s. I will try to stream period measurement using timer mode 2, 3, 12 or 13 in 50k sample/sec, with falling edge detection. DHT11 sends 50us low level signal before each data signal. All data signal are high level. '0' is 26-28 us high level and '1' is 70us high level. The signal specs is updated in this post. I am still counting which clock and divisor are suitable for this task. Why I choose DHT11? When I choose it, I did not know that Labjack U6 supports Sensirion SHTXX sensors. I actually used SHTXX in previous project which is AVR microcontroller based. SHT has better specs. I still consider of using SHT, especially when I don't have enough time to make DHT11 works with Labjack.

#4 LabJack Support

LabJack Support
  • Admin
  • 8323 posts

Posted 26 September 2011 - 07:11 AM

Streaming the a timer as you suggest looks like it might work, but I still think streaming an analog or digital input would work also. At 50 kHz your resolution is 20us, so a "0" (26-28us) will give you 2 high scans, while a "1" (70us) will give you 4 high scans. You should be able to tell them apart.

You will want to start the input stream first. Then generate the start condition using a command/response call with the WAIT iotype:

http://labjack.com/s...rs-guide/4.3.14

#5 gunta

gunta
  • Members
  • 6 posts

Posted 11 October 2011 - 11:16 PM

I choose your method of streaming digital I/O. I use Delphi for programming. I implement the DHT11 reading in a 10 second timer. The peroblem is when reading the stream with following line:
lngErrorcode := eGet(lngHandle, LJ_ioGET_STREAM_DATA, LJ_chALL_CHANNELS, numScans, @dblStreamData);
I found that the actual number of scan is always zero (0), however the eGet() funtion does not return error.

Could you please help me reading the complete code as attached and help finding the solution.

-gunta-


procedure TformMain.Timer3Timer(Sender: TObject);
const
  scanRate: Integer = 50000;
  delayms: Integer = 6;
  streamBufferSize: Integer = 300;
  
var
  i,j: Integer;
  dblStreamData: array[0..299] of Double;
  byteBitsData: array[0..299] of Byte;
  numScans: Double;
  bitCounter: Integer;

  byteDHT11_RH: Byte;
  byteDHT11_Temp: Byte;
  wordDHT11_Check: Word;
  lwDHT11_24bits: LongWord;
  
  dblDHT11_RH: Double;
  dblDHT11_Temp: Double;

begin
  //Make a long parameter which holds the address of the data array.  We do this
  //so the compiler does not generate a warning in the eGet call that retrieves
  //stream data.  Note that the x1 parameter  in eGet (and AddRequest) is fairly
  //generic, in that sometimes it could just be a write parameter, and sometimes
  //it has the address of an array.  Since x1 is not declared as a pointer, the
  //compiler will complain if you just pass the array pointer without casting
  //it to a long as follows.
  //long padblData = (long)&adblData[0];

  // Read Humidity Sensor - DHT11
  // Read data
  for i := 0 to streamBufferSize-1 do
    dblStreamData[i] := 0;

  // Pull down
  lngErrorCode := AddRequest (lngHandle, LJ_ioPUT_DIGITAL_BIT , DHT11_IOpin, 1, 0, 0);
  ErrorHandler(lngErrorcode, 0);

  // LongDelay 18ms
  lngErrorCode := AddRequest (lngHandle, LJ_ioPUT_WAIT, 0, 18000, 0, 0);
  ErrorHandler(lngErrorcode, 0);

  // Release line (give to DHT11), pull up
  lngErrorCode := AddRequest (lngHandle, LJ_ioGET_DIGITAL_BIT , DHT11_IOpin, 1, 0, 0);
  ErrorHandler(lngErrorcode, 0);

  // Streaming at scan rate.
  lngErrorCode := AddRequest (lngHandle, LJ_ioPUT_CONFIG, LJ_chSTREAM_SCAN_FREQUENCY, scanRate, 0, 0);
  ErrorHandler(lngErrorcode, 0);

  //Give the driver a 10 ms buffer
  lngErrorcode := AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chSTREAM_BUFFER_SIZE, streamBufferSize, 0, 0);
  ErrorHandler(lngErrorcode, 0);

  //Configure reads to retrieve whatever data is available without waiting (wait mode LJ_swNONE).
  lngErrorcode := AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chSTREAM_WAIT_MODE, LJ_swNONE, 0, 0);
  ErrorHandler(lngErrorcode, 0);

  //Define the scan list as FIO_EIO.
  lngErrorcode := AddRequest(lngHandle, LJ_ioCLEAR_STREAM_CHANNELS, 0, 0, 0, 0);
  ErrorHandler(lngErrorcode, 0);
  lngErrorcode := AddRequest(lngHandle, LJ_ioADD_STREAM_CHANNEL, 193, 0, 0, 0);
  ErrorHandler(lngErrorcode, 0);

  lngErrorCode := GoOne(lngHandle);
  ErrorHandler(lngErrorcode, 0);

  //Get all the results just to check for errors.
  lngErrorcode := GetFirstResult(lngHandle, lngIOType, lngChannel, dblValue, lngTemp, dblTemp);
  ErrorHandler(lngErrorcode, 0);
  lngGetNextIteration := 0;	//Used by the error handling function.
  while lngErrorcode < LJE_MIN_GROUP_ERROR do
  begin
    lngErrorcode := GetNextResult(lngHandle, lngIOType, lngChannel, dblValue, lngTemp, dblTemp);
    if lngErrorcode <> LJE_NO_MORE_DATA_AVAILABLE then
    ErrorHandler(lngErrorcode, lngGetNextIteration);

    lngGetNextIteration := lngGetNextIteration + 1;
  end;

  //Start the stream.
  lngErrorcode := eGet(lngHandle, LJ_ioSTART_STREAM, 0, dblValue, 0);
  ErrorHandler(lngErrorcode, 0);

  //The actual scan rate is dependent on how the desired scan rate divides into
  //the LabJack clock.  The actual scan rate is returned in the value parameter
  //from the start stream command.
  //Memo1.Lines.Add('Actual Scan Rate = ' + FloatToStr(dblValue));
  //Memo1.Lines.Add('Actual Sample Rate = ' + FloatToStr(2*dblValue));
  
  Sleep (6);

  numScans := 2*scanRate*delayms/1000;  //2x the expected # of scans (2*scanRate*delayms/1000)
  lngErrorcode := eGet(lngHandle, LJ_ioGET_STREAM_DATA, LJ_chALL_CHANNELS, numScans, @dblStreamData);
  ErrorHandler(lngErrorcode, 0);
  Memo1.Lines.Add('Actual Number of Scan = ' + FloatToStr(numScans));

  //Stop the stream
  lngErrorcode := eGet(lngHandle, LJ_ioSTOP_STREAM, 0, dblTemp, lngTemp);
  ErrorHandler(lngErrorcode, 0);

  // Analyze received bits
  for i:= 0 to Round(numScans-1) do
    if (Round(dblStreamData[i]) and (1 Shl (DHT11_IOpin + 8))) <> 0 then
      byteBitsData[i] := 1
    else
      byteBitsData[i] := 0;

  j := 0;
  lwDHT11_24bits := 0;
  for i:= 0 to Round(numScans-1) do
  begin
    if byteBitsData[i] = 0 then
      begin
        if j = 0 then
        begin
          bitCounter := 0;
          j := 1;
        end
        else if j = 1 then
        begin
          if BitCounter >= 3 then j := 2
          else Break;
        end
        else
        begin
          if BitCounter > 2 then
             lwDHT11_24bits := lwDHT11_24bits or (1 Shl (23 - (j-2)));

          j := j + 1;
        end
        
      end
    else
      bitCounter := bitCounter + 1;
  end;

  if j > 2 then lblHumidity.Text := IntToStr(lwDHT11_24bits)
  else lblHumidity.Text := 'F';

  // Set DHT11 pin as output high in idle mode.
  lngErrorCode := eDO(lngHandle, DHT11_IOpin, 1);
  ErrorHandler(lngErrorcode, 0);
end;


#6 LabJack Support

LabJack Support
  • Admin
  • 8323 posts

Posted 12 October 2011 - 07:13 AM

You are using the NONE wait mode so the read will return immediately with whatever data is available from your U6. Problem is you just do 1 read 6ms after starting the stream, but the driver only reads stream data every 40ms by default, so there is not any data available yet.

I suggest you change to wait mode sleep, get rid of the Sleep(6), and instead read say 10,000 scans (at least to start). Also, do your start condition after starting the stream. So something like:

Start 50k stream with SLEEP wait mode
eDO(handle,DIO#,0)
Sleep(20)
eDI(handle,DIO#,junk)
Read 10k scans
Stop stream


#7 gunta

gunta
  • Members
  • 6 posts

Posted 14 October 2011 - 03:29 AM

It works!!! Thank you for Labjack team, for such a great support. With regards the result, the temperature looks fine, but the humidity looks too low. I am from Indonesia, usually the RH is above 70%. I only get 30% from DHT11. However, I am quite happy with the success coding.



Reply to this topic



  


0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users