Sunday, July 2, 2017

Interfacing PIC16F887 with DHT11 sensor


 
This mini project shows the interfacing of PIC16F887 microcontroller with DHT11 (RHT01) digital humidity and temperature sensor.
In this post I'm not going to give any details about the DHT11 sensor because every thing is in the datasheet of the device which can be downloaded from the following link:
DHT11 Datasheet Download

Hardware Required:
  • PIC16F887 Microcontroller
  • DHT11 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 with DHT11 digital sensor circuit:
Project circuit diagram is below.
Interfacing PIC16F887 micrcontroller with DHT11 (RHT01) sensor circuit diagram
The internal oscillator of the microcontroller is used and MCLR pin function is disabled.
Interfacing PIC16F887 with DHT11 sensor CCS C code:
Reading the datasheet of the DHT11 sensor is recommended for understanding the source code.
/* Interfacing PIC16F887 with DHT11 sensor CCS C code
   Read DHT11 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 DHT11_PIN PIN_B0                              // DHT11 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 ;
void start_signal(){
  output_drive(DHT11_PIN);                            // Configure connection pin as output
  output_low(DHT11_PIN);                              // Connection pin output low
  delay_ms(25);
  output_high(DHT11_PIN);                             // Connection pin output high
  delay_us(25);
  output_float(DHT11_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(DHT11_PIN) && get_timer1() < 100);     // Wait until DHT11_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(DHT11_PIN) && get_timer1() < 100);    // Wait until DHT11_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(DHT11_PIN))                          // Wait until DHT11_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(DHT11_PIN))                           // Wait until DHT11_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 reding 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)){
          message1[7]  = T_Byte1/10  + 48;
          message1[8]  = T_Byte1%10  + 48;
          message1[10] = T_Byte2/10  + 48;
          message2[7]  = RH_Byte1/10 + 48;
          message2[8]  = RH_Byte1%10 + 48;
          message2[10] = RH_Byte2/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 DHT11
      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");
    }
  }
}
DHT11 With PIC16F887 microcontroller simulation video:


Source code, hex and Proteus simulation files can be downloaded from the following link.
Download

Wednesday, November 9, 2016

PIC16F877A With DHT11 sensor and ST7735 SPI TFT


Interfacing PIC16F877A with DHT11 sensor and ST7735R SPI color TFT display
PIC16F877A with DHT11 sensor and ST7735 SPI TFT display 
This post shows how to interface PIC16F877A microcontroller with DHT11 relative humidity and temperature sensor and 1.8" ST7735R SPI TFT display.
DHT11 sensor is a digital device used to sense relative humidity and temperature and convert that data into digital signals. For more details about this type of sensors and how to interface it with PIC16F877A microcontroller see the following two topics:
Interfacing PIC16F877A with DHT11 (RHT01) sensor Proteus simulation
Interfacing DHT11 relative humidity and temperature sensor with PIC16F877A microcontroller
And to see how to interface PIC16F877A with ST7735 SPI TFT display read the following topic:
ST7735 1.8" TFT display with PIC16F877A example
Components List:
  • PIC16F877A Microcontroller
  • ST7735R SPI TFT Display
  • DHT11 (RHT01) Sensor
  • 8MHz Crystal oscillator
  • 2 x 22pF Capacitors
  • 10K Resistor 
  • 4.7K Resistor
  • 5 x 1K Resistors
  • +5V Power Supply Source
  • Breadboard
  • Jumper Wires
PIC16F877A With DHT11 sensor and ST7735 SPI TFT circuit:
PIC16F877A with DHT11 sensor and ST7735 SPI TFT display circuit
PIC16F877A With DHT11 sensor and ST7735 SPI TFT CCS C code:
PIC16F877A hardware SPI module is used in this project..
ST7735 SPI TFT driver is required to compile this code, download link in this topic:
ST7735 SPI TFT Display Driver for CCS PIC C compiler
The code is has been tested with versions 4.068 and 5.051.
/* PIC16F877A with DHT11 sensor and ST7735 1.8" SPI color TFT display example CCS C code
   ST7735 TFT display driver for CCS PIC C compiler is required
   http: //ccspicc.blogspot.com/
   electronnote@gmail.com
*/

// TFT module connections
#define TFT_CS   PIN_D1
#define TFT_DC   PIN_D0
#define TFT_SPI_HARDWARE
// End TFT module connections

#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP                       
#use delay(clock = 8000000)
#include <ST7735_TFT.c>
#use fast_io(D)
#use fast_io(B)
#define DHT11_PIN PIN_B0                              // DHT11 Data pin is connected to pin RB0

char *text = "DHT11 Sensor with    PIC16F877A and ST7735 TFT";
char temperature[] = "00.0";
char humidity[]    = "00.0%";
short Time_out;
unsigned int8 T_byte1, T_byte2, RH_byte1, RH_byte2, CheckSum, clear = 0 ;
void start_signal(){
  output_drive(DHT11_PIN);                            // Configure DHT11 pin as output
  output_low(DHT11_PIN);                              // DHT11 pin output low
  delay_ms(25);
  output_high(DHT11_PIN);                             // DHT11 pin output high
  delay_us(30);
  output_float(DHT11_PIN);                            // Configure v pin as input
}
short check_response(){
  delay_us(40);
  if(!input(DHT11_PIN)){                              // Read and test if DHT11 pin is low
    delay_us(80);
    if(input(DHT11_PIN)){                             // Read and test if DHT11 pin is high
      delay_us(50);
      return 1;
    }
  }
}
unsigned int8 Read_Data(){
  unsigned int8 i, k, _data = 0;                      // k is used to count 1 bit reading duration
  if(Time_out)
    break;
  for(i = 0; i < 8; i++){
    k = 0;
    while(!input(DHT11_PIN)){                         // Wait until DHT11 pin get raised
      k++;
      if(k > 100){
        Time_out = 1;
        break;
      }
      delay_us(1);
    }
    delay_us(30);
    if(!input(DHT11_PIN))
      bit_clear(_data, (7 - i));                      // Clear bit (7 - i)
    else{
      bit_set(_data, (7 - i));                        // Set bit (7 - i)
      while(input(DHT11_PIN)){                        // Wait until DHT11 pin goes low
        k++;
        if(k > 100){
        Time_out = 1;
        break;
      }
      delay_us(1);}
    }
  }
  return _data;
}
void main(){
  TFT_BlackTab_Initialize();
  fillScreen(ST7735_BLACK);
  drawtext(0, 0, text, ST7735_WHITE, ST7735_BLACK, 1);
  drawFastHLine(0, 35, _width, ST7735_BLUE);
  while(TRUE){
    Time_out = 0;
    Start_signal();
    if(check_response()){                             // If there is a response from sensor
      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
      if(Time_out){                                   // If reading takes long time
        if(clear != 1){
          clear = 1;
          fillrect(0, 40, _width, 120, ST7735_BLACK);
        }
        strcpy(text, "Time out!");
        drawtext(10, 90, text, ST7735_RED, ST7735_BLACK, 2);
      }
      else{
       if(CheckSum == ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0xFF)){
         temperature[0]  = T_Byte1/10  + 48;
         temperature[1]  = T_Byte1%10  + 48;
         temperature[3] = T_Byte2/10  + 48;
         humidity[0]  = RH_Byte1/10 + 48;
         humidity[1]  = RH_Byte1%10 + 48;
         humidity[3] = RH_Byte2/10 + 48;
         if(clear != 2){
          clear = 2;
          fillrect(0, 50, _width, 120, ST7735_BLACK);
          drawFastHLine(0, 96, _width, ST7735_BLUE);
        }
         strcpy(text, "Temperature:");
         drawtext(28, 50, text, ST7735_MAGENTA, ST7735_BLACK, 1);
         drawtext(34, 70, temperature, ST7735_YELLOW, ST7735_BLACK, 2);
         drawCircle(84, 70, 2, ST7735_YELLOW);
         drawchar(90, 70, 'C', ST7735_YELLOW, ST7735_BLACK, 2);
         strcpy(text, "Humidity:");
         drawtext(37, 110, text, ST7735_MAGENTA, ST7735_BLACK, 1);
         drawtext(34, 130, humidity, ST7735_CYAN, ST7735_BLACK, 2);
       }
       else{
         if(clear != 3){
          clear = 3;
          fillrect(0, 40, _width, 120, ST7735_BLACK);
         }
         strcpy(text, "Checksum");
         drawtext(16, 80, text, ST7735_RED, ST7735_BLACK, 2);
         strcpy(text, "Error!");
         drawtext(28, 100, text, ST7735_RED, ST7735_BLACK, 2);
       }
      }
    }
    else {
      if(clear != 4){
        clear = 4;
        fillrect(0, 40, _width, 120, ST7735_BLACK);
      }
      strcpy(text, "No");
      drawtext(52, 60, text, ST7735_RED, ST7735_BLACK, 2);
      strcpy(text, "response");
      drawtext(16, 80, text, ST7735_RED, ST7735_BLACK, 2);
      strcpy(text, "from the");
      drawtext(16, 100, text, ST7735_RED, ST7735_BLACK, 2);
      strcpy(text, "sensor");
      drawtext(28, 120, text, ST7735_RED, ST7735_BLACK, 2);
    }
  delay_ms(1000);
  }
}
PIC16F877A With DHT11 sensor and ST7735 SPI TFT video:
This video shows a simple hardware circuit of this project.


Saturday, September 17, 2016

DHT11 Interfacing with PIC12F1822 microcontroller


In this blog there are some topics talking about the DHT11 relative humidity and temperature sensor and how to interface it with different types of PIC microcontrollers. The datasheet of the DHT11 sensor shows its characteristics and how it works.
Also the following topic shows the DHT11 timing and how to simulate it using Proteus:
Interfacing PIC16F877A with DHT11 (RHT01) sensor Proteus simulation
This topic shows how to interface this sensor with the microcontroller PIC12F1822. This microcontroller has only 8 pins and 6 of them can work as an I/O pins.
An LCD is used to display temperature and relative humidity values. A shift register is used to make a 3-wire LCD as shown at the following link;
Interfacing PIC12F1822 microcontroller with LCD display
Therefor for this simple project we need 3 data lines for the LCD and 1 line for the DHT11 sensor which means we need 4 I/O pins.
Components List:
  • PIC12F1822 Microcontroller
  • DHT11 (RHT01) Sensor
  • 1602 LCD
  • 74HC595 Shift Register (74HC164 or CD4094 can do the job)
  • 10K Variable Resistor
  • 4.7K Resistor
  • +5V Power Supply
  • Breadboard
  • Jumper Wires
Interfacing PIC12F1822 with DHT11 sensor circuit:
Interfacing PIC12F1822 with DHT11 (RHT01) sensor circuit CCS C
The shift register data line is connected to RA0 pin and the clock line is connected to RA1 pin. LCDs enable pin is connected to pin RA3.
The internal oscillator of the PIC12F1822 microcontroller is used.
To see how to use 74HC164 or CD4094 instead of 74HC595 go to the link above.
The DHT11 sensor has 4 pins:
VCC : Positive power supply (+5V)
DATA : Sensor data input and output
NC : Not connected terminal
GND : Ground (0V)
A pull-up resistor must be added between the DHT11 data pin and VCC (+5V) pin as shown in the circuit schematic (4.7K ~ 10K).
Interfacing PIC12F1822 with DHT11 sensor CCS C code:
If you want to understand the code please read the DHT11 datasheet.
Variables Time_out and k are used to test reading time to avoid wrong data reception and microcontroller hanging.
The microcontroller runs with its internal oscillator at 32MHz (8MHz + PLL).
// Interfacing PIC12F1822 with DHT11 sensor CCS PIC C code
// 3-Wire LCD driver must be added
// http://ccspicc.blogspot.com/
// electronnote@gmail.com
// Use at your own risk

//LCD module connections
#define LCD_DATA_PIN PIN_A0
#define LCD_CLOCK_PIN PIN_A1
#define LCD_EN_PIN PIN_A2
//End LCD module connections

#include <12F1822.h>
#fuses NOMCLR INTRC_IO PLL_SW
#use delay(clock=32000000)
#include <3WireLCD.c>
#use fast_io(A)
#define DHT11_PIN PIN_A4                              // Connection pin between DHT11 and mcu

char message1[] = "Temp = 00.0 C  ";
char message2[] = "RH   = 00.0 %  ";
short Time_out;
unsigned int8 T_byte1, T_byte2, RH_byte1, RH_byte2, CheckSum ;
void start_signal(){
  output_drive(DHT11_PIN);                            // Configure connection pin as output
  output_low(DHT11_PIN);                              // Connection pin output low
  delay_ms(25);
  output_high(DHT11_PIN);                             // Connection pin output high
  delay_us(30);
  output_float(DHT11_PIN);                            // Configure connection pin as input
}
short check_response(){
  delay_us(40);
  if(!input(DHT11_PIN)){                              // Read and test if connection pin is low
    delay_us(80);
    if(input(DHT11_PIN)){                             // Read and test if connection pin is high
      delay_us(50);
      return 1;
    }
  }
}
unsigned int8 Read_Data(){
  unsigned int8 i, k, _data = 0;                      // k is used to count 1 bit reading duration
  if(Time_out)
    break;
  for(i = 0; i < 8; i++){
    k = 0;
    while(!input(DHT11_PIN)){                         // Wait until DHT11 pin get raised
      k++;
      if(k > 100){
        Time_out = 1;
        break;
      }
      delay_us(1);
    }
    delay_us(30);
    if(!input(DHT11_PIN))
      bit_clear(_data, (7 - i));                      // Clear bit (7 - i)
    else{
      bit_set(_data, (7 - i));                        // Set bit (7 - i)
      while(input(DHT11_PIN)){                        // Wait until DHT11 pin goes low
        k++;
        if(k > 100){
        Time_out = 1;
        break;
      }
      delay_us(1);}
    }
  }
  return _data;
}
void main() {
  setup_oscillator(OSC_8MHZ | OSC_PLL_ON);            // Set internal oscillator to 32MHz (8MHz and PLL)
  lcd_initialize();                                   // Initialize LCD module
  lcd_cmd(LCD_CLEAR);                                 // LCD Clear
  delay_ms(1000);
  while(TRUE){
    Time_out = 0;
    Start_signal();
    if(check_response()){                             // If there is a response from sensor
      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
      if(Time_out){                                   // If reading takes long time
        lcd_cmd(LCD_CLEAR);                           // LCD Clear
        lcd_goto(5, 1);                               // Go to column 5 row 1
        lcd_out("Time out!");
      }
      else{
       if(CheckSum == ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0xFF)){
         message1[7]  = T_Byte1/10  + 48;
         message1[8]  = T_Byte1%10  + 48;
         message1[10] = T_Byte2/10  + 48;
         message2[7]  = RH_Byte1/10 + 48;
         message2[8]  = RH_Byte1%10 + 48;
         message2[10] = RH_Byte2/10 + 48;
         message1[11] = 223;                          // Degree symbol
         lcd_goto(1, 1);                              // Go to column 1 row 1
         printf(lcd_out, message1);                   // Display message1
         lcd_goto(1, 2);                              // Go to column 1 row 2
         printf(lcd_out, message2);                   // Display message2
       }
       else{
         lcd_cmd(LCD_CLEAR);                          // LCD Clear
         lcd_goto(1, 1);                              // Go to column 1 row 1
         lcd_out("Checksum Error!");
       }
      }
    }
    else {
      lcd_cmd(LCD_CLEAR);                             // LCD Clear
      lcd_goto(3, 1);                                 // Go to column 3 row 1
      lcd_out("No response");
      lcd_goto(1, 2);                                 // Go to column 1 row 2
      lcd_out("from the sensor");
    }
  delay_ms(1000);
  }
}
Interfacing PIC12F1822 with DHT11 video:

Thursday, September 8, 2016

Real time clock with relative humidity and temperature sensing using PIC16F877A, 2004 LCD, DS1307 RTC and DHT11


This topic shows how to build a real time clock with relative humidity and temperature sensing using PIC16F877A microcontroller, DS1307 RTC and DHT11 (RHT01) sensor where all data are displayed on 20x4 LCD display. The 20x4 LCD has 20 columns and 4 rows which is good enough for this project. The compiler used to program the microcontroller is CCS PIC C PCWHD.
To see how to interface PIC16F877A with DS1307 take a look at the following topic:
Real time clock using PIC16F877A microcontroller and DS1307 serial RTC
And to see how to interface PIC18F4550 with DHT22 (AM2302) take a look at this topic:
Interfacing DHT11 relative humidity and temperature sensor with PIC16F877A microcontroller
The DS1307 RTC is an 8-pin integrated circuit uses I2C communication protocol to communicate with master device which is in our case the PIC16F877A microcontroller. This small chip can count seconds, minutes, hours, day, date, month and year with leap-year up to year 2100.
The DHT11 (RHT01) sensor comes in a single row 4-pin package and operates from 3.3 to 5.5V power supply. It can measure temperature from 0-50 °C with an accuracy of ±2°C and relative humidity ranging from 20-90% with an accuracy of  ±5%. The sensor provides fully calibrated digital outputs for the two measurements. It has got its own proprietary 1-wire protocol, and therefore, the communication between the sensor and a microcontroller is not possible through a direct interface with any of its peripherals. The protocol must be implemented in the firmware of the MCU with precise timing required by the sensor.
Component list:
  • PIC16F877A microcontroller
  • DS1307 RTC
  • DHT11 (RHT01) Sensor
  • 2004 LCD
  • 3V Coin cell battery
  • 8MHz and 32.768KHz crystal oscillators
  • 2 x 22pF capacitors
  • 3 x 10K resistors
  • 4.7K resistor
  • 10K Potentiometer
  •  2 Buttons
  • +5V Power Supply
  • Protoboard
  • Jumper Wires
PIC16F877A + 2004 LCD + DS1307 RTC + DHT11 sensor circuit:
PIC16F877A + 2004 LCD + DS1307 RTC + DHT11 (RHT01) circuit CCS C
 The two pushbuttons for adjusting time and date as shown in the video below.
CCS C code:
The project C code is just a combination of the C codes of the two previous projects.
The reading of relative humidity and temperature data is done every 1 second.
// PIC16F877A + 2004 LCD + DS1307 RTC + DHT11 Sensor CCS C code
// 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 <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP                       
#use delay(clock = 8000000)
#include <lcd.c>
#use fast_io(B)
#use I2C(master, I2C1, FAST=100000)
#define DHT11_PIN PIN_B2                // Connection pin between DHT11 and mcu

short button_state, Time_out;
char time[] = "TIME:      :  :  ";
char calendar[] = "  /  /20  ";
unsigned int8 second, second10, minute, minute10,
               hour, hour10, date, date10, month, month10,
               year, year10, day, i, j ;
char message1[] = "Temperature: 00.0 C ";
char message2[] = "Humidity   : 00.0 % ";
unsigned int8 T_byte1, T_byte2, RH_byte1, RH_byte2, CheckSum, time_read ;
void ds1307_display(){
  second10  =  (second & 0x70) >> 4;
  second = second & 0x0F;
  minute10  =  (minute & 0x70) >> 4;
  minute = minute & 0x0F;
  hour10  =  (hour & 0x30) >> 4;
  hour = hour & 0x0F;
  date10  =  (date & 0x30) >> 4;
  date = date & 0x0F;
  month10  =  (month & 0x10) >> 4;
  month = month & 0x0F;
  year10  =  (year & 0xF0) >> 4;
  year = year & 0x0F;
  time[16]  = second  + 48;
  time[15]  = second10  + 48;
  time[13]  = minute  + 48;
  time[12]  = minute10  + 48;
  time[10]  = hour  + 48;
  time[9]  = hour10  + 48;
  calendar[9]  = year  + 48;
  calendar[8]  = year10  + 48;
  calendar[4]  = month + 48;
  calendar[3]  = month10 + 48;
  calendar[1]  = date + 48;
  calendar[0]  = date10 + 48;
  lcd_gotoxy(1, 1);                              // Go to column 1 row 1
  printf(lcd_putc, time);                        // Display time
  lcd_gotoxy(1, 2);                              // Go to column 1 row 2
  switch(day){
    case 1: lcd_putc("DATE:Sun"); break;
    case 2: lcd_putc("DATE:Mon"); break;
    case 3: lcd_putc("DATE:Tue"); break;
    case 4: lcd_putc("DATE:Wed"); break;
    case 5: lcd_putc("DATE:Thu"); break;
    case 6: lcd_putc("DATE:Fri"); break;
    case 7: lcd_putc("DATE:Sat"); break;}
  lcd_gotoxy(10, 2);                              // Go to column 9 row 2
  printf(lcd_putc, calendar);                    // Display calendar
}
void ds1307_write(unsigned int8 address, data_){
  i2c_start();                                   // Start I2C
  i2c_write(0xD0);                               // DS1307 address
  i2c_write(address);                            // Send register address
  i2c_write(data_);                        // Write data to the selected register
  i2c_stop();                                    // Stop I2C
}
void ds1307_read(){
   i2c_start();                                  // Start I2C
   i2c_write(0xD0);                              // DS1307 address
   i2c_write(0);                                 // Send register address
   i2c_start();                                  // Restart I2C
   i2c_write(0xD1);                              // Initialize data read
   second =i2c_read(1);                          // Read seconds from register 0
   minute =i2c_read(1);                          // Read minuts from register 1
   hour = i2c_read(1);                           // Read hour from register 2
   day = i2c_read(1);                            // Read day from register 3
   date = i2c_read(1);                           // Read date from register 4
   month = i2c_read(1);                          // Read month from register 5
   year = i2c_read(0);                           // Read year from register 6
   i2c_stop();                                   // Stop I2C
}
int8 edit(int8 parameter, int8 xx, int8 yy){
  while(TRUE){
    if(input(PIN_B0)) button_state = 0;
    while(!input(PIN_B1)){
      parameter++;
      if(i == 1 && parameter > 23)
        parameter = 0;
      if(i == 2 && parameter > 59)
        parameter = 0;
      if(i == 3 && parameter > 31)
        parameter = 1;
      if(i == 4 && parameter > 12)
        parameter = 1;
      if(i == 5 && parameter > 99)
        parameter = 0;
      lcd_gotoxy(xx, yy);
      printf(lcd_putc,"%02u", parameter);
      delay_ms(200);}
    lcd_gotoxy(xx, yy);
    lcd_putc("  ");
    j = 0;
    while((input(PIN_B0) || button_state) && input(PIN_B1) && j < 5){
      j++;
     delay_ms(50);}
    lcd_gotoxy(xx, yy);
    printf(lcd_putc,"%02u", parameter);
    j = 0;
    while((input(PIN_B0) || button_state) && input(PIN_B1) && j < 5){
      j++;
      delay_ms(50);}
    if(!input(PIN_B0) && !button_state){
      button_state = 1; return parameter;}
  } 
}
void start_signal(){
  output_drive(DHT11_PIN);              // Configure connection pin as output
  output_low(DHT11_PIN);                // Connection pin output low
  delay_ms(25);
  output_high(DHT11_PIN);               // Connection pin output high
  delay_us(30);
  output_float(DHT11_PIN);              // Configure connection pin as input
}
short check_response(){
  delay_us(40);
  if(!input(DHT11_PIN)){                // Read and test if connection pin is low
    delay_us(80);
    if(input(DHT11_PIN)){               // Read and test if connection pin is high
      delay_us(50);
      return 1;
    }
  }
}
unsigned int8 Read_Data(){
  unsigned int8 i, k, _data = 0;     // k is used to count 1 bit reading duration
  if(Time_out)
    break;
  for(i = 0; i < 8; i++){
    k = 0;
    while(!input(DHT11_PIN)){                          // Wait until pin goes high
      k++;
      if (k > 100) {Time_out = 1; break;}
      delay_us(1);}
    delay_us(30);
    if(!input(DHT11_PIN))
      bit_clear(_data, (7 - i));                       // Clear bit (7 - i)
    else{
      bit_set(_data, (7 - i));                         // Set bit (7 - i)
      while(input(DHT11_PIN)){                         // Wait until pin goes low
      k++;
      if (k > 100) {Time_out = 1; break;}
      delay_us(1);}
    }
  }
  return _data;
}
void main(){
  port_b_pullups(TRUE);                           // Enable PORTB pull-ups
  output_b(0);
  set_tris_b(3);                                  // Configure RB0 & RB1 as inputs
  lcd_init();                                     // Initialize LCD module
  lcd_putc('\f');                                 // LCD clear
  while(TRUE){
    Time_out = 0;
    if(input(PIN_B0)) button_state = 0;
    if(!input(PIN_B0) && (!button_state)){
      button_state = 1;
      // Convert BCD to decimal
      minute = minute + minute10 * 10;
      hour = hour + hour10 * 10;
      date = date + date10 * 10;
      month = month + month10 * 10;
      year = year + year10 * 10;
      // End conversion
      i=1;
      hour = edit(hour, 10, 1);
      i=2;
      minute = edit(minute, 13, 1);
      while(TRUE){
        if(input(PIN_B0)) 
          button_state = 0;
        while(!input(PIN_B1)){
          day++;
          if(day > 7)
            day = 1;
          lcd_gotoxy(6, 2);                        // Go to column 6 row 2
          switch(day){
            case 1: lcd_putc("Sun"); break;
            case 2: lcd_putc("Mon"); break;
            case 3: lcd_putc("Tue"); break;
            case 4: lcd_putc("Wed"); break;
            case 5: lcd_putc("Thu"); break;
            case 6: lcd_putc("Fri"); break;
            case 7: lcd_putc("Sat"); break;}
          delay_ms(200);
        }
        lcd_gotoxy(6, 2);
        lcd_putc("   ");
        j = 0;
        while((input(PIN_B0)||button_state) && input(PIN_B1) && j < 5){
          j++;
          delay_ms(50);}
        lcd_gotoxy(6, 2);
        switch(day){
          case 1: lcd_putc("Sun"); break;
          case 2: lcd_putc("Mon"); break;
          case 3: lcd_putc("Tue"); break;
          case 4: lcd_putc("Wed"); break;
          case 5: lcd_putc("Thu"); break;
          case 6: lcd_putc("Fri"); break;
          case 7: lcd_putc("Sat"); break;}
        if(!input(PIN_B0) && (!button_state)){
          button_state = 1;
          break;}
        j = 0;
        while((input(PIN_B0)||button_state) && input(PIN_B1) && j < 5){
          j++;
          delay_ms(50);}
      }
      i=3;
      date = edit(date, 10, 2); 
      i=4;
      month = edit(month, 13, 2);
      i=5;
      year = edit(year, 18, 2);
      // Convert decimal to BCD
      minute = ((minute/10) << 4) + (minute % 10);
      hour = ((hour/10) << 4) + (hour % 10);
      date = ((date/10) << 4) + (date % 10);
      month = ((month/10) << 4) + (month % 10);
      year = ((year/10) << 4) + (year % 10);
      // End conversion
      ds1307_write(1, minute);
      ds1307_write(2, hour);
      ds1307_write(3, day);
      ds1307_write(4, date);
      ds1307_write(5, month);
      ds1307_write(6, year);
      ds1307_write(0, 0);
    }
    ds1307_read();                              // Read data from DS1307 RTCC
    ds1307_display();                           // Diaplay time and calendar
    if(((second10 * 10+second)>time_read)||((second10 * 10+second)==0 && time_read)){
      time_read = second10 * 10 + second;
      Start_signal();
      if(check_response()){                     // If there is response from sensor
        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
        if(Time_out){                           // If reading takes long time
          lcd_gotoxy(21, 1);                    // Go to column 1 row 3
          lcd_putc("     Time Out!      ");
          lcd_gotoxy(21, 2);                    // Go to column 1 row 4
          lcd_putc("                    ");     // Clear 4th row
        }
        else{
          if(CheckSum == ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0xFF)){
            message1[13]  = T_Byte1 / 10  + 48;
            message1[14]  = T_Byte1 % 10  + 48;
            message1[16]  = T_Byte2 / 10  + 48;
            message2[13] = RH_Byte1 / 10 + 48;
            message2[14] = RH_Byte1 % 10 + 48;
            message2[16] = RH_Byte2 / 10 + 48;
            message1[17] = 223;                   // Degree symbol 
            lcd_gotoxy(21, 1);                    // Go to column 1 row 3
            printf(lcd_putc, message1);           // Display message1
            lcd_gotoxy(21, 2);                    // Go to column 1 row 4
            printf(lcd_putc, message2);           // Display message2
          }
          else{
            lcd_gotoxy(21, 1);                    // Go to column 1 row 3
            lcd_putc("  Checksum Error!   ");
            lcd_gotoxy(21, 2);                    // Go to column 1 row 4
            lcd_putc("                    ");     // Clear 4th row
          }
        }
      }
      else {
        lcd_gotoxy(21, 1);           // Go to column 1 row 3
        lcd_putc("    No response     ");
        lcd_gotoxy(21, 2);           // Go to column 1 row 4
        lcd_putc("  from the sensor   ");
      }
    }  
    delay_ms(50);
  }
}
Project Video:

Saturday, September 3, 2016

DHT11 VS DHT22


Comparison between DHT11 (RHT01) and DHT22 (AM2302 - RHT03) sensors
DHT11 VS DHT22 Hardware circuit using PIC16F877A and 2004 (20x4) LCD 
DHT11 (RHT01) and DHT22 (AM2302 - RHT03) are relative humidity and temperature sensors. These sensors are small, cheap and easy to use. They use only one wire to communicate with mcu.
The following two topic shows how to interface PIC16F877A with DHT11 and DHT22 sensors respectively:
Interfacing DHT11 relative humidity and temperature sensor with PIC16F877A microcontroller
Interfacing PIC16F877A with DHT22(AM2302-RHT03) sensor using CCS PIC C

The following table shows the DHT11 sensor characteristics (from DHT11 datasheet):
DHT11 Characteristics 
And the following table shows DHT22 (AM2302) technical specification (from AM2302 datasheet):
DHT22 Characteristics
The differences between the two sensors are summarized in the following table:


DHT11 DHT22
Relative Humidity Operating Range 20 ~ 90% 0 ~ 100%
Relative Humidity Accuracy ±5%RH ±2%RH (Max ±5%RH)
Humidity Resolution1%RH 0.1%RH
Humidity Repeatability±1%RH ±1%RH
Humidity Hysteresis ±1%RH ±0.3%RH
Long-term Stability ±1%RH/year ±0.5%RH/year
Temperature Operating Range 0 ~ 50°C -40 ~ 80°C
Temperature Accuracy±2°C±0.5°C
Temperature Resolution1°C0.1°C

DHT11 and DHT22 interfacing with PIC16F877A microcontroller:
The following circuit schematic shows the comparison between DHT11 and DHT22 sensors connection circuit.
DHT11 versus DHT22 (AM2302) using PIC16F877A and 20x4 LCD circuit CCS
The microcontroller used to make the comparison between DHT11 and DHT22 is PIC16F877A which runs with crystal oscillator at 8MHz.
The sensor DHT11 as well as DHT22 has 4 pins which are:
Vcc : Positive power supply (+5V)
Data : Sensor data input and output
NC : Not connected terminal
Gnd : Ground (0V).
A pull-up resistor must be added between the data pin of each sensor and VCC (+5V) pin as shown in the circuit schematic (4.7K ~ 10K).
2004 (20x4) LCD display is used to display temperature and humidity results for both sensors.
CCS C code for DHT11 vs DHT22 project:
The comparison between DHT11 and DHT22 (AM2302) sensors full CCS C code is below.
// DHT11 VS DHT22 CCS C code
// 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 <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP                       
#use delay(clock = 8000000)
#include <lcd.c>
#use fast_io(B)
#define DHT11 PIN_B4                           // Connection pin between DHT11 and mcu
#define DHT22 PIN_B5                           // Connection pin between DHT22 and mcu

char message1[] = "DHT11 Temp = 00.0 C ";
char message2[] = "DHT11 RH   = 00.0 % ";
char message3[] = "DHT22 Temp = 00.0 C ";
char message4[] = "DHT22 RH   = 00.0 % ";
short Time_out;
unsigned int8 T_byte1, T_byte2, RH_byte1, RH_byte2, CheckSum ;
unsigned int16 Temp, RH;
void dht11_start_signal(){
  output_drive(DHT11);                        // Configure connection pin as output
  output_low(DHT11);                          // Connection pin output low
  delay_ms(25);
  output_high(DHT11);                         // Connection pin output high
  delay_us(30);
  output_float(DHT11);                        // Configure connection pin as input
}
short dht11_check_response(){
  delay_us(40);
  if(!input(DHT11)){                          // Read and test if connection pin is low
    delay_us(80);
    if(input(DHT11)){                         // Read and test if connection pin is high
      delay_us(50);
      return 1;
    }
  }
}
unsigned int8 dht11_Read_Data(){
  unsigned int8 i, k, _data = 0;        // k is used to count 1 bit reading duration
  if(Time_out)
    break;
  for(i = 0; i < 8; i++){
    k = 0;
    while(!input(dht11)){                            // Wait for DHT22 pin to go high
      k++;
      if(k > 100){
        Time_out = 1;
        break;
      }
      delay_us(1);
    }
    delay_us(30);
    if(!input(dht11))
      bit_clear(_data, (7 - i));                     // Clear bit (7 - i)
    else{
      bit_set(_data, (7 - i));                       // Set bit (7 - i)
      while(input(dht11)){                           // Wait for DHT22 pin to go low
        k++;
        if(k > 100){
        Time_out = 1;
        break;
      }
      delay_us(1);}
    }
  }
  return _data;
}
void dht22_start_signal(){
  output_drive(DHT22);                        // Configure connection pin as output
  output_low(DHT22);                          // Connection pin output low
  delay_ms(25);
  output_high(DHT22);                         // Connection pin output high
  delay_us(30);
  output_float(DHT22);                        // Configure connection pin as input
}
short dht22_check_response(){
  delay_us(40);
  if(!input(DHT22)){                          // Read and test if connection pin is low
    delay_us(80);
    if(input(DHT22)){                         // Read and test if connection pin is high
      delay_us(50);
      return 1;
    }
  }
}
unsigned int8 dht22_Read_Data(){
  unsigned int8 i, k, _data = 0;                // k is used to count 1 bit reading duration
  if(Time_out)
    break;
  for(i = 0; i < 8; i++){
    k = 0;
    while(!input_state(dht22)){                      // Wait for DHT22 pin to go high
      k++;
      if(k > 100){
        Time_out = 1;
        break;
      }
      delay_us(1);
    }
    delay_us(30);
    if(!input_state(dht22))
      bit_clear(_data, (7 - i));                     // Clear bit (7 - i)
    else{
      bit_set(_data, (7 - i));                       // Set bit (7 - i)
      while(input_state(dht22)){                     // Wait for DHT22 pin to go low
        k++;
        if(k > 100){
        Time_out = 1;
        break;
      }
      delay_us(1);}
    }
  }
  return _data;
}
void main(){
  lcd_init();                                        // Initialize LCD module
  lcd_putc('\f');                                    // LCD clear
  delay_ms(1000);
  while(TRUE){
    Time_out = 0;
    dht11_Start_signal();
    if(dht11_check_response()){                // If there is a response from dht11 sensor
      RH_byte1 = dht11_Read_Data();                  // read RH byte1
      RH_byte2 = dht11_Read_Data();                  // read RH byte2
      T_byte1 = dht11_Read_Data();                   // read T byte1
      T_byte2 = dht11_Read_Data();                   // read T byte2
      Checksum = dht11_Read_Data();                  // read checksum
      if(Time_out){                                  // If reading takes long time
        lcd_gotoxy(1, 1);                            // Go to column 1 row 1
        lcd_putc("  DHT11 Time out!   ");
        lcd_gotoxy(1, 2);                            // Go to column 1 row 1
        lcd_putc("                    ");            // Clear second row
      }
      else{
       if(CheckSum == ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0xFF)){
         message1[13]  = T_Byte1/10  + 48;
         message1[14]  = T_Byte1%10  + 48;
         message1[16] = T_Byte2/10  + 48;
         message2[13]  = RH_Byte1/10 + 48;
         message2[14]  = RH_Byte1%10 + 48;
         message2[16] = RH_Byte2/10 + 48;
         message1[17] = 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_gotoxy(1, 1);                           // Go to column 1 row 1
         lcd_putc("DHT11 Checksum Error");
         lcd_gotoxy(1, 2);                           // Go to column 1 row 2
         lcd_putc("                    ");           // Clear second row
       }
      }
    }
    else {                                     // If dht11 sensor don't respond
      lcd_gotoxy(1, 1);                              // Go to column 1 row 1
      lcd_putc("    No response     ");
      lcd_gotoxy(1, 2);                              // Go to column 1 row 2
      lcd_putc(" from DHT11 sensor  ");
    }
    Time_out = 0;
    dht22_Start_signal();
    if(dht22_check_response()){                       // If there is a response from sensor
      RH_byte1 = dht22_Read_Data();                  // read RH byte1
      RH_byte2 = dht22_Read_Data();                  // read RH byte2
      T_byte1 = dht22_Read_Data();                   // read T byte1
      T_byte2 = dht22_Read_Data();                   // read T byte2
      Checksum = dht22_Read_Data();                  // read checksum
      if(Time_out){                                  // If reading takes long time
        lcd_gotoxy(21, 1);                           // Go to column 1 row 1
        lcd_putc("  DHT22 Time out!   ");
        lcd_gotoxy(21, 2);                           // Go to column 1 row 4
        lcd_putc("                    ");            // Clear fourth row
      }
      else{
       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){
           message3[12] = '-';
           Temp = Temp & 0X7FFF; }
         else
          message3[12] = ' ';
         message3[13]  = (Temp / 100) % 10  + 48;
         message3[14]  = (Temp / 10) % 10  + 48;
         message3[16] = Temp % 10  + 48;
         message4[13]  = (RH / 100) % 10 + 48;
         message4[14]  = (RH / 10) % 10 + 48;
         message4[16] = RH % 10 + 48;
         message3[17] = 223;                         // Degree symbol
         lcd_gotoxy(21, 1);                          // Go to column 1 row 3
         printf(lcd_putc, message3);                 // Display message3
         lcd_gotoxy(21, 2);                          // Go to column 1 row 4
         printf(lcd_putc, message4);                 // Display message4
       }
       else{
         lcd_gotoxy(21, 1);                          // Go to column 1 row 3
         lcd_putc("DHT22 Checksum Error");
         lcd_gotoxy(21, 2);                          // Go to column 1 row 4
         lcd_putc("                    ");           // Clear fourth row
       }
      }
    }
    else {                                       // If dht22 sensor don't respond
      lcd_gotoxy(21, 1);                             // Go to column 1 row 3
      lcd_putc("    No response     ");
      lcd_gotoxy(21, 2);                             // Go to column 1 row 4
      lcd_putc(" from DHT22 sensor  ");
    }
  delay_ms(1000);
  }
}   // End of program

DHT11 VS DHT22 Video:
The following video shows the comparison between the two sensors results.