Monday, July 3, 2017

PIC16F887 Microcontroller with DHT22 digital sensor



This is an example for interfacing the microcontroller PIC16F887 with DHT22 (RHT03 - AM2302) digital relative humidity and temperature sensor with CCS C code and Proteus simulation.
Read DHT22 datasheet to understand what I'm going to do because every thing about the sensor is in its datasheet which can be downloaded from the following link:
DHT22 Datasheet

Required Components:
  • PIC16F887 Microcontroller
  • DHT22 or compatible Sensor
  • 1602 LCD screen
  • 10K Potentiometer
  • 4.7K ohm resistor
  • 0.1µF Ceramic capacitor (Optional but recommended)
  • +5V Power source
  • Breadboards
  • Jumper wires
Interfacing PIC16F887 microcontroller with DHT22 digital sensor circuit:
In this example the internal oscillator of the microcontroller is used and MCLR pin is configured as a digital input pin (no clear circuit required).
PIC16F887 Microcontroller with DHT22 digital sensor C code:
This is the C code of our example, it has been tested with CCS PIC C compiler version 5.051.
/* Interfacing PIC16F887 with DHT22 (AM2302) sensor CCS C code
   Read DHT22 datasheet to understand the code!
   Internal oscillator used @ 8MHz
   Timer1 is configured so that it increments every 1µs
   http://ccspicc.blogspot.com/
   electronnote@gmail.com
*/

//LCD module connections
#define LCD_RS_PIN PIN_D0
#define LCD_RW_PIN PIN_D1
#define LCD_ENABLE_PIN PIN_D2
#define LCD_DATA4 PIN_D3
#define LCD_DATA5 PIN_D4
#define LCD_DATA6 PIN_D5
#define LCD_DATA7 PIN_D6
//End LCD module connections

#include <16F887.h>
#fuses NOMCLR NOBROWNOUT NOLVP INTRC_IO
#use delay(clock = 8MHz)
#include <lcd.c>
#use fast_io(B)
#use fast_io(D)
#define DHT22_PIN PIN_B0                              // DHT22 Data pin is connected to RB0

char message1[] = "Temp = 00.0 C  ";
char message2[] = "RH   = 00.0 %  ";
short Time_out = 0;
unsigned int8 T_byte1, T_byte2, RH_byte1, RH_byte2, CheckSum ;
unsigned int16 Temp, RH;

void start_signal(){
  output_drive(DHT22_PIN);                            // Configure connection pin as output
  output_low(DHT22_PIN);                              // Connection pin output low
  delay_ms(25);
  output_high(DHT22_PIN);                             // Connection pin output high
  delay_us(25);
  output_float(DHT22_PIN);                            // Configure connection pin as input
}
short check_response(){
  set_timer1(0);                                      // Set Timer1 value to 0
  setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);           // Start Timer1 with internal clock source + 2 prescaler
  while(!input(DHT22_PIN) && get_timer1() < 100);     // Wait until DHT22_PIN becomes high (cheking of 80µs low time response)
  if(get_timer1() > 99)                               // If response time > 99µS  ==> Response error
    return 0;                                         // Return 0 (Device has a problem with response)
  else{
    set_timer1(0);                                    // Set Timer1 value to 0
    while(input(DHT22_PIN) && get_timer1() < 100);    // Wait until DHT22_PIN becomes low (cheking of 80µs high time response)
    if(get_timer1() > 99)                             // If response time > 99µS  ==> Response error
      return 0;                                       // Return 0 (Device has a problem with response)
    else
      return 1;                                       // Return 1 (response OK)
  }
}
unsigned int8 Read_Data(){
  unsigned int8 i, _data = 0;
  if(Time_out)
    break;
  for(i = 0; i < 8; i++){
    set_timer1(0);                                    // Set Timer1 value to 0
    while(!input(DHT22_PIN))                          // Wait until DHT22_PIN becomes high
      if(get_timer1() > 100){                         // If low time > 100  ==>  Time out error (Normally it takes 50µs)
        Time_out = 1;
        break;
      }
    set_timer1(0);                                    // Set Timer1 value to 0
    while(input(DHT22_PIN))                           // Wait until DHT22_PIN becomes low
      if(get_timer1() > 100){                         // If high time > 100  ==>  Time out error (Normally it takes 26-28µs for 0 and 70µs for 1)
        Time_out = 1;
        break;
      }
     if(get_timer1() > 50)                            // If high time > 50  ==>  Sensor sent 1 
       bit_set(_data, (7 - i));                       // Set bit (7 - i)
  }
  return _data;
}
void main(){
  setup_oscillator(OSC_8MHZ);                         // Set the internal oscillator to 8MHz
  setup_timer_1(T1_DISABLED);                         // Disable Timer1
  lcd_init();                                         // Initialize LCD module
  lcd_putc('\f');                                     // Clear LCD
  while(TRUE){
    delay_ms(1000);                                   // Wait 1s
    Time_out = 0;
    Start_signal();                                   // Send start signal to the sensor
    if(check_response()){                             // Check if there is a response from sensor (If OK start reading humidity and temperature data)
      RH_byte1 = Read_Data();                         // read RH byte1
      RH_byte2 = Read_Data();                         // read RH byte2
      T_byte1  = Read_Data();                         // read T byte1
      T_byte2  = Read_Data();                         // read T byte2
      Checksum = Read_Data();                         // read checksum
      setup_timer_1(T1_DISABLED);                     // Disable Timer1
      if(Time_out) {                                  // If there is a time out in reading
        lcd_putc('\f');                               // LCD clear
        lcd_gotoxy(5, 1);                             // Go to column 5 row 1
        lcd_putc("Time out!");                        // Display "Time out!"
      }
      else {                                          // If there is no time out
        if(CheckSum == ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0xFF)){
          RH = RH_byte1;
          RH = (RH << 8) | RH_byte2;
          Temp = T_byte1;
          Temp = (Temp << 8) | T_byte2;
          if (Temp > 0X8000){
            message1[6] = '-';
            Temp = Temp & 0X7FFF;
          }
          else
            message1[6] = ' ';
          message1[7]  = (Temp / 100) % 10  + 48;
          message1[8]  = (Temp / 10) % 10  + 48;
          message1[10] = Temp % 10  + 48;
          if(RH == 1000)                              // If the relative humidity = 100.0 %
            message2[6]  = 1 + 48;
          else
            message2[6]  = ' ';
          message2[7]  = (RH / 100) % 10 + 48;
          message2[8]  = (RH / 10) % 10 + 48;
          message2[10] = RH % 10 + 48;
          message1[11] = 223;                         // Degree symbol   
          lcd_gotoxy(1, 1);                           // Go to column 1 row 1
          printf(lcd_putc, message1);                 // Display message1
          lcd_gotoxy(1, 2);                           // Go to column 1 row 2
          printf(lcd_putc, message2);                 // Display message2
        }
        else {
          lcd_putc('\f');                             // LCD clear
          lcd_gotoxy(1, 1);                           // Go to column 1 row 1
          lcd_putc("Checksum Error!");
        }
      }
    }
    else {                                            // If there is no response from DHT22 sensor
      lcd_putc('\f');                                 // LCD clear
      lcd_gotoxy(3, 1);                               // Go to column 3 row 1
      lcd_putc("No response");
      lcd_gotoxy(1, 2);                               // Go to column 1 row 2
      lcd_putc("from the sensor");
    }
  }
}
The following video shows simulation using Proteus of PIC16F887 and DHT22 sensor:


C Code, HEX file and simulation files can be downloaded from this link:
Simulation Download