Connecting the thermal module (DHT11) is quite simple. Here're the pins that I used.
Module RPI
GND GND (Pin 6)
VCC VCC (Pin 1 - may need Pin 2 (5v) for longer distances)
Data GPIO 0 (Pin 11)
Overall, the way to read data from the thermal module is to pulse the data pin and then wait for 40 bits of data.
The Pulse
The RPi needs to pulse the data pin low for 18ms (milliseconds) and then wait for module to pulse the data signal low then high for 80us (microseconds)
The Data
The data is transmitted as 50us of the data line getting pulled low, followed by the line getting pulled high for ~27us (for a "0") or high for 70us (for a "1").
The 40 bits
The 40 bits are made up of the following
2 x 8 bits of humidity
2 x 8 bits of temperature
8 bits of parity
The humidity and temperature are made up of the first 8 bits are the whole part of the number when the second 8 bits are the fractional part. For example 0x10 0x12 would be 0x10.0x12 = 16.18 (% or C, for humidity or temperature)
The Code
The key parts of the code are the pulse and reading the data
The Pulse Code
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delay(18);
digitalWrite(pin, HIGH);
delayMicroseconds(start);
pinMode(pin, INPUT);
The above code sets the pin as OUTPUT, sets it LOW and then delays for 18 milliseconds. It then sets the pin back to HIGH and waits for "start" - this defaults to 60us. Then the pin is set for input. We're ready to read the data.
The Data Code
The code for reading the data has the following structure
1. Wait for High. We need to wait for a HIGH, so we know when to start timing when we get a HIGH. If we don't get a HIGH after 200 attempts, then we bail.
2. Wait for Low. We need to time how long a HIGH is, so we can determine if the value is a zero (~27us) or a one (~70us). We increment 'counter' for each microsecond. If we don't get a HIGH after 200 attempts, then we bail. (We could wait a longer period of time between each sample)
3. Verify Checksum. We verify that sum(bytes 1+2+3+4) AND 0xff == byte 5.
The Complete Code
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <getopt.h>
#include <string.h>
#define DATABITS 1 + 40 //40 data bits plus the start bit
#define PIN 0 //default GPIO pin (wPi pin number)
#define START 60 //wait after start
#define THRESHOLD 45 //Threshold between a zero (should be ~27uS) and a one (should be ~70us)
#define RETRY 3 //Retry attempts
#define soptions "p:s:t:r:hv"
void help()
{
printf("\
--pin\tGPIO Pin to use (wPi Number)\n\
--start\tStart wait in microseconds (default START )\n\
--threshold\tZero or One threshold (default THRESHOLD )\n\
--help\tHelp\n\
--verbose\tOutput Verbose Information\n");
}
static struct option const long_options[] =
{
{"pin", required_argument, NULL, 'p'}, // List all minions
{"start", required_argument, NULL, 's'}, // all output (default)
{"threshold", required_argument, NULL, 't'}, // delay after packet.
{"retry", required_argument, NULL, 't'}, // retry attempts.
{"help", no_argument, NULL, 'h'}, // Help
{"verbose", no_argument, NULL, 'v'}, // verbose output.
{NULL, no_argument, NULL, 0}};
int main(int argc, char *argv[])
{
int counter = 0;
int i, checksum, len = 0, bit;
int pin = PIN; //Raspberry Pi GPIO pin
int start = START;
int threshold = THRESHOLD;
int attempt, retry = RETRY;
int tempData[5] = {0, 0, 0, 0, 0};
int verbose = 0;
int c;
// Need a better way to parse the options. There's no real error handling.
while ((c = getopt_long(argc, argv, soptions, long_options, NULL)) != -1)
{
switch ((char)c)
{
case 'p': //list all registered minions
pin = atoi(optarg);
break;
case 's':
start = atoi(optarg);
break;
case 't':
start = atoi(optarg);
break;
case 'r':
retry = atoi(optarg);
break;
case 'v':
verbose = 1;
break;
default:
case 'h':
help();
exit(0);
break;
}
}
if (wiringPiSetup() == -1)
{
printf("Unable to set up WiringPi - check your installation\n");
return (2);
}
for (attempt = 0; attempt < retry; attempt++)
{
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delay(18);
digitalWrite(pin, HIGH);
delayMicroseconds(start);
pinMode(pin, INPUT);
for (bit = 0; bit < DATABITS; bit++)
{
//wait for low to go high
counter = 0;
while (digitalRead(pin) == LOW)
{
counter++;
delayMicroseconds(1);
if (counter == 200)
{
if (verbose)
printf("No LOW detected for bit %d\n", bit);
break;
}
}
//Now high, wait for low
counter = 0;
while (digitalRead(pin) == HIGH)
{
counter++;
delayMicroseconds(1);
if (counter == 200)
{
if (verbose)
printf("No HIGH detected for bit %d\n", bit);
break;
}
}
if (counter == 200)
{
break;
}
if (bit > 0)
{
tempData[(bit - 1) / 8] <<= 1;
tempData[(bit - 1) / 8] += counter < threshold ? 0 : 1;
}
}
if (counter == 200)
{
if (verbose)
printf("Transmission error \n");
}
else
{
checksum = tempData[0] + tempData[1] + tempData[2] + tempData[3];
checksum & +0xff;
if (checksum == tempData[4])
{
printf("Humidity = %d.%d%% Temperature = %d.%dC \n",
tempData[0], tempData[1], tempData[2], tempData[3]);
return (0);
}
else
{
if (verbose)
{
printf("Checksum error %x:%x\n", checksum, tempData[4]);
printf("%x:%x:%x:%x:%x\n\n", tempData[0], tempData[1], tempData[2], tempData[3], tempData[4]);
}
}
}
delay(100); //delay 100ms (not uS)
memset(tempData, 0, 5);
}
return (1);
}
Compile options
Assuming that above is in powertemp.c, us the following to compile (assume that gpio is installed)
gcc -o pt powertemp.c -lwiringPi -lwiringPiDev
Comments
Post a Comment