本来想找个I2C接口的温度传感器(比如MAX1668)玩玩,结果要么发现价格有点小贵,要么是蜘蛛脚,不好做实验。最后,采用了Arduiro DHT11电子积木,十分简单方便。电路原理图如下所示,
引脚1接在3.3V电源上,引脚3悬空,引脚4接地。
引脚2接在面包板的P7 (也就是树莓派的PIN #7,BCM的GPIO #4)。注意,这里需要一个大小5.1K的上拉电阻。
好了,下面是我的面包板实验图,第一次居然忘了插数据线,所以没有读出数据,第二次插上数据线就一切正常了。
但是,我发现读到的数据错误率很高,不知道是电阻的问题还是程序的“延时不精确”导致的。
如果用定时器来实现延时,应该会比较好,以后再整吧!
$ sudo ./dht11
Temp = 18 *C, Hum = 40 %
Temp = 18 *C, Hum = 41 %
Temp = 18 *C, Hum = 40 %
Temp = 18 *C, Hum = 40 %
Temp = 18 *C, Hum = 40 %
Temp = 18 *C, Hum = 40 %
Temp = 18 *C, Hum = 40 %
Temp = 18 *C, Hum = 40 %
Temp = 18 *C, Hum = 40 %
Temp = 18 *C, Hum = 40 %
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <bcm2835.h>
#define DHT11_DATA RPI_V2_GPIO_P1_07 // RPi Pin #7
int readDHT(int pin, unsigned int *data)
{
int i = 0, j = 0;
int counter = 0;
int laststate = HIGH;
// Set GPIO pin to output
bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_write(pin, HIGH);
usleep(500000); // 500ms
bcm2835_gpio_write(pin, LOW);
usleep(20000); // 20ms
// Set GPIO pin to input
bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);
// wait for pin to drop?
while (bcm2835_gpio_lev(pin) == 1) {
usleep(1);
}
// reading data
for (i = 0; i < 100; i++) {
counter = 0;
while (bcm2835_gpio_lev(pin) == laststate) {
counter++;
if (counter == 1000)
break;
}
if (counter == 1000) break;
laststate = bcm2835_gpio_lev(pin);
// shove each bit into the storage bytes
if ((i > 3) && (i % 2 == 0)) {
data[j / 8] <<= 1;
if (counter > 200)
data[j / 8] |= 1;
j++;
}
}
/*printf("DHT11 Data (%d bits): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
j, data[0], data[1], data[2], data[3], data[4]);*/
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
printf("Temp = %d *C, Hum = %d \%\n", data[2], data[0]);
return 1;
}
return 0;
}
int main(int argc, char **argv)
{
uint8_t counter = 0;
uint32_t data[100];
if (!bcm2835_init())
return 1;
while (counter < 10) {
memset(data, 0, 100 * sizeof(uint32_t));
if (readDHT(DHT11_DATA, data))
counter++;
}
bcm2835_close();
return 0;
}
最后,玩个增强版,用检测的温度来控制LED。我把电脑的出风口放在传感器旁边,明显看到温度上升,嘿嘿!
上图配修改后的程序,完美收官!
int main(int argc, char **argv)
{
uint8_t counter = 0;
uint32_t data[100];
if (!bcm2835_init())
return 1;
// Set the pin to be an output
bcm2835_gpio_fsel(LED, BCM2835_GPIO_FSEL_OUTP);
while (counter < 10) {
memset(data, 0, 100 * sizeof(uint32_t));
if (readDHT(DHT11_DATA, data)) {
counter++;
if (data[2] != 18) {
bcm2835_gpio_write(LED, HIGH);
} else {
bcm2835_gpio_write(LED, LOW);
}
}
bcm2835_delay(1000);
}
bcm2835_close();
return 0;
}
参考资料
1. DHT Humidity Sensing on Raspberry Pi or Beaglebone Black with GDocs Logging