The schematic for the DHT-11 with connections to the PIC18F248 is given in the Schematics Section below. The ancillary circuitry for the PIC18F248 also includes connection via RS232 to a PC (enables PC control of the DS1307 to set parameters and retrieve data).
Power Supply
A typical "wall-wart" power-supply is used (a surplus laptop charger in this case) in conjunction with a voltage regulator (LM7805) to provide the regulated 5V required by the PIC microcontroller. The DHT-11 also requires a 3-5V supply, which is the same supply as for the PIC microcontroller in this case.
Circuit Operation
The schematic shows the basic minimum circuit to demonstrate the operation of the DHT-11 sensor, in this case, controlled/interfaced to a PIC18F248 microcontroller which also provides data output to PC via RS232 connection.
The LM7805 provides the 5V circuit voltage (stepping down from the 12V input from a "wall-wart" power-supply). The crystal X1 and associated capacitors C1 and C2 provide the oscillator for the PIC18F248 microcontroller. Incircuit serial programming (ICSP) of the PIC18F248 microcontroller is provided via connector J1 with switch SW1, resistor R1 and diode D2 providing voltage protecting during loading code into the PIC microcontroller.
Control signals to/from the PIC18F248 microcontroller are sent from a suitable port on the microcontroller (port B in this case) in order to control the DHT-11 and retrieve data.
Calibration
The DHT-11 sensor provides the relative humidity and temperature data digitally and notionally does not require calibration (datasheet stated accuracy: at 25oC ±5% RH, ±0.2oC).
Calibration checking of relative humidity data from the DHT-11 however can be performed using suitable binary saturated aqueous solutions of simple salts (common table salt can be used for a single point calibration check if desired). The results of such a check of the DHT-11 relative humidity data is reported in the Testing/Experimental Results Section below.
Firmware/Software
The DHT-11 provides simple digital control and a serial interface for retrieval of data using a "one-wire" protocol. The "one-wire" refers to the single data line, however, the sensor still obviously requires V+ and ground, so three wires are required to connect the sensor.
The "one-wire" bus requires a 5.1kohm pull-up resistor, so that when the bus is idle, the bus status is high. The communications protocol is a master-slave structure, in which the master initiates data transfer and then the slave device (DHT-11) responds with a single transmission of 40 bits (5 bytes, high byte first). The data format of the transmission is 8bit humidity integer data + 8bit humidity decimal data +8 bit temperature integer data + 8bit decimal temperature data +8 bit parity bit [however, in practical the "decimal" data bytes are observed to be always zero (0)]. The actual data transmission timing diagrams and steps of the protocol are well documentated in the datasheet, so are not reproduced here.
The PIC micrcontroller code is based upon the CCS routines (3) and (4). The code has been modified to provide access to all the functions available from the DHT-11, and enable the PIC microcontroller to transmit the collected data to a PC via RS232 connection.
The DHT11_lib.h library file contains various #define's used to specify the DHT-11 command set and functions. Various downloads are available in the table below.
Code Snippet 1: Interface to PIC18F248
#include "DHT11.h"
#include "DHT11_Lib.h"
#zero_ram //all variables automatically initialised to 0
BYTE toggleReadCount;
long readCount;
#int_timer0
void timer0_isr(void) {
set_timer0(TIMER0_PRELOAD); // Reload the Timer - prescaler = 1, period ~90us
DHTexit = true;
}
#int_timer1
void timer1_interrupt() { /* Timer1 has wrapped around to 0. */
toggleReadCount=1;
set_timer1(3035); //prescaler=8, 10Mhz, preload=3036 -> Freq 5hz, period=0.2sec
}
void get_DHT11_data(){
unsigned char DHT_transmission = 0; //indicates if recieved data from DHT11 valid or error condition
DHT_transmission = DHT11_get_data(); //send 'start' signal and receive data message from DHT11 (5 sequential bytes)
switch (DHT_transmission){
case 1:{
printf("No Sensor Start\n\r");
break;}
case 2:{
printf("No Sensor Found\n\r");
break;}
case 3:{
printf("Checksum Error\n\r");
break;}
default: {
printf("T: %2u.%01u \n\r",humidityTemp_data[2], humidityTemp_data[3]);
printf("H: %2u.%01u \n\r",humidityTemp_data[0], humidityTemp_data[1]);
break;}
}
}
void main() {
char recChar; //the received character from the serial port via keyboard
int16 ADCvalue;
int16 numReadings = 0;
float tempCelsius;
int8 toggleReading = false;
unsigned char DHT_transmission = 0; //indicates if recieved data from DHT11 valid or error condition
printf("start\n\r");
setup_adc_ports(RA0_RA1_ANALOG_RA3_REF); //Vref as input to RA3 (pin 5) on the PIC
setup_adc(ADC_CLOCK_DIV_32 );
set_adc_channel(0); //0 = AN0 (pin2), 1=AN1 (pin3), etc
setup_timer_0(T0_INTERNAL | T0_DIV_1 | T0_8_BIT);
set_timer0(TIMER0_PRELOAD); //prescaler = 1, period ~90us
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); //prescaler 8
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER0);
disable_interrupts(INT_TIMER1);
DHT11_init(); //this is basically only a 1sec delay to ensure DHT11 settled after power-up
while(TRUE){
if (kbhit()) {
recChar = getc();;
switch (recChar) {
case 'd': //temperature from LM35
case 'D': ADCvalue = Read_ADC();
tempCelsius = ADCvalue*0.24414; //10bit - 2.5V/1024 = 0.00244v/count
printf("LM35 = %2.1f Deg C\n\r",tempCelsius);
break;
case 'h': //retrieve and print data from DHT-11
case 'H': get_DHT11_data();
break;
case 'r': //continous reading of DHT-11 and LM35
//from datasheet, not recommended to repeatedly read the sensors,
//each read sensor interval is greater than 5 seconds can be obtained accurate data
case 'R': if (toggleReading) {
toggleReading = false;
disable_interrupts(INT_TIMER1);
printf("Disable Continous Readings \n\r");
} else {
printf("Enable Continous Readings \n\r");
toggleReading = true;
readCount = 0;
toggleReadCount = 0;
numReadings = 0;
set_timer1(3035); //prescaler=8, 10Mhz, preload=3036 -> Freq 5hz, period=0.2sec
enable_interrupts(INT_TIMER1);
}
break;
default: printf("Unknown cmd\n\r");
break;
}
}
if (toggleReadCount){
toggleReadCount = 0;
readCount++; //150 counts of 0.2sec = read every 30 secs
}
if (readCount>=150) { //150 counts of 0.2sec = read every 30 secs
disable_interrupts(INT_TIMER1);
ADCvalue = Read_ADC();
tempCelsius = ADCvalue*0.24414;
numReadings +=1;
if (DHT11_get_data() == 0) { //send 'start' signal and receive data message from DHT11 (5 sequential bytes)
printf("%3Lu,%2u,%2u,%2.1f\n\r",numReadings,humidityTemp_data[2],humidityTemp_data[0],tempCelsius);
//DHT-11 temp, DHT-11 humidity, LM35 temp
} else {
printf("%3Lu,%2u,-,%2.1f\n\r",numReadings,DHT_transmission,tempCelsius);
//DHT-11 error, "-", LM35 temp
}
readCount = 0;
toggleReadCount = 0;
set_timer1(3035); //prescaler=8, 10Mhz, preload=3036 -> Freq 5hz, period=0.2sec
enable_interrupts(INT_TIMER1);
}
}
}
Code Snippet 2: DHT11_lib.h library file
#define DHT11_pin PIN_B4 //DHT11 sensor connected to Port B Pin 4
#define TIMER0_PRELOAD 31
int8 DHTexit = false;
unsigned char humidityTemp_data[5]; //received data from DHT11, DHT11 transmits 5 bytes
//which give humidity, temperature, CRC (see datasheet)
void DHT11_init()
/******************************************************************************
* Function: DHT11_init()
* Dependencies:
* Input:
* Output:
*
* Overview: initialise the DHT11
* Notes: Data sheet advises that upon startup, DHT11 requires 1 second
* to stabilise before will respond to transmission requests
*****************************************************************************/
{
delay_ms(1000);
}
unsigned char DHT11_get_byte()
/******************************************************************************
* Function: DHT11_get_byte()
* Dependencies:
* Input: Pin to which DHT11 connected (DHT11_pin)
* Output: The byte received from the DHT11 (value)
*
* Overview: Accumulates the input bits from the DHT11 to form a byte that
* represents the data read.
* Notes: The DHT11 has a custom 1-wire interface (see datasheet).
* The distinction between logical "0" and "1" is via pulse width
* of the input pulses transmited by the DHT11.
*****************************************************************************/
{
int8 iIndex;
int8 iValue = 0;
for(iIndex = 0; iIndex < 8 ; iIndex++) {
DHTexit = False;
set_timer0(TIMER0_PRELOAD); //prescaler = 1, period ~90us
while (!input(DHT11_pin) && !DHTexit);
delay_us(30);
if (input(DHT11_pin)) {
iValue = iValue |(1<<(7 - iIndex));
DHTexit = False;
set_timer0(TIMER0_PRELOAD); //prescaler = 1, period ~90us
while (input(DHT11_pin) && !DHTexit);
}
}
return iValue;
}
unsigned char DHT11_get_data()
/******************************************************************************
* Function: DHT11_get_data()
* Dependencies: Global variable "humidityTemp_data[]" which stores received bytes
* Input: Pin to which DHT11 connected (DHT11_pin)
* Output: Status code representing the result of reading the transmission
* of the 5 bytes of sequential data from the DHT11 after the DHT11
* start transmission
* 0 = received data OK
* 1 = DHT11 did not respond to 'start' signal
* 2 = DHT11 did not complete correct response to 'start' signal - not connected
* 3 - CRC error, received data incorrectly
*
* Overview: Initiates start transmission from the DHT11 using the timing
* requirements of the communications protocol in the DHT11 datasheet.
* Upon successful initiation of transmission, stores the 5 sequential
* bytes sent from teh DHT11 that represent the humidity, temperature and CRC
* Notes: Calls DHT11_get_byte() to decode pulse widths from DHT11 transmission to
* which form the individual bits of the transmitted bytes
*****************************************************************************/
{
unsigned char i = 0;
int16 check_sum = 0;
output_low(DHT11_pin); //PIC initiates data transmission from the DHT11
delay_ms(25); //by sending 'start' signal, LOW >18ms, HIGH 20-40us
output_high(DHT11_pin);
delay_us(30);
DHTexit = false; //DHT11 response starts/expected
set_timer0(TIMER0_PRELOAD); //prescaler = 1, period ~90us
while (!input(DHT11_pin) && !DHTexit);
if (DHTexit) { //data line should go low, if not DHT11 did not respond to 'start'
return 1;
}
DHTexit = false; //data line held low by DHT11 for 80us
set_timer0(TIMER0_PRELOAD); //prescaler = 1, period ~90us
while (input(DHT11_pin) && !DHTexit);
if (DHTexit) { //data line should go high, if not DHT11 not connected/responding
return 2;
}
for (i=0;i<=4;i+=1) { //transmission now starts of 5 bytes
humidityTemp_data[i]=DHT11_get_byte(); //individual bits of each byte accumulated (pulse widths define logical 1 or 0
}
output_high(DHT11_pin); //data line HIGH end of transmission
for (i=0;i<4;i+=1) { //calculate check sum and compare to CRC byte
check_sum += humidityTemp_data[i];
}
check_sum = check_sum & 0xFF;
if (check_sum != humidityTemp_data[4]) {
return 3; //checksum not equal to CRC byte = PROBLEM with transmitted bytes
} else {
return 0; //received data OK
}
}
Downloads
Only Logged-In Members can add comments