树莓派3B读取DHT11温度湿度数据

在学习树莓派做物联网的小demo的时候,买了一个DHT11温湿度计,在网上找了一圈,发现程序大多不能使用

找到DHT11的时序图后和同学研究修改了网上的一个源代码,修改后基本上可以稳定读取温湿度值

先转载DHT11的原理

1.数据总时序

用户主机(MCU)发送一次开始信号后,DHT11 从低功耗模式转换到高速模式,待主机开始信号结束后,DHT11 发送响应信号,送出 40bit 的数据,幵触发一次信采集

这里写图片描述

2.主机发送起始信号

单片机连接DHT11的DATA引脚的I/O口输出低电平,且低电平保持时间不能小于 18ms,然后等待 DHT11 作出应答信号。

这里写图片描述

3.检测从机应答信号

DHT11 的 DATA 引脚检测到外部信号有低电平时, 等待外部信号低电平结束, 延迟后 DHT11 的 DATA引脚处于输出状态,输出 80 微秒的低电平作为应答信号,紧接着输出 80 微秒的高电平通知外设准备接收数据。

这里写图片描述

4.接收数据 
(1)数据判定规则 
位数据“0”的格式为: 50 微秒的低电平和 26-28 微秒的高电平,位数据“1”的格式为: 50 微秒的低电平加 70微秒的高电平。

接收数据时可以先等待低电平过去,即等待数据线拉高,再延时60us,因为60us大于28us且小于70us,再检测此时数据线是否为高,如果为高,则数据判定为1,否则为0。

这里写图片描述

(2)数据格式

一次传送 40 位数据,高位先出

8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据+8bit 校验位。

(3)数据校正 
判断“8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据”的结果是否等于8bit 校验位。如果等于则数据接收正确,否则应该放弃这一次的数据,重新接收。

然后就是树莓派的代码了,语言是C语言,我用的是GPIO1

//
//mydht11.c
//
#include 
#include 
#include 

typedef unsigned char uint8;
typedef unsigned int  uint16;
typedef unsigned long uint32;

#define HIGH_TIME 32

int pinNumber = 1;  //use gpio1 to read data
uint32 databuf;

uint8 readSensorData(void)
{
    uint8 crc; 
    uint8 i;
 
    pinMode(pinNumber,OUTPUT); // set mode to output
    digitalWrite(pinNumber, 1); // output a low level
    delayMicroseconds(4);
    digitalWrite(pinNumber, 0); // output a high level 
    delay(25);
    digitalWrite(pinNumber, 1); // output a low level
    delayMicroseconds(60); 
    pinMode(pinNumber, INPUT); // set mode to input
    pullUpDnControl(pinNumber,PUD_UP);

    if(digitalRead(pinNumber)==0) //SENSOR ANS
    {
        while(!digitalRead(pinNumber)); //wait to high
        delayMicroseconds(80);
        for(i=0;i<32;i++)
        {
          while(digitalRead(pinNumber)); //data clock start
          while(!digitalRead(pinNumber)); //data start
          delayMicroseconds(HIGH_TIME);
          databuf*=2;
          if(digitalRead(pinNumber)==1) //1
          {
            databuf++;
          }
        }

        for(i=0;i<8;i++)
        {
          while(digitalRead(pinNumber)); //data clock start
          while(!digitalRead(pinNumber)); //data start
          delayMicroseconds(HIGH_TIME);
          crc*=2;  
          if(digitalRead(pinNumber)==1) //1
          {
            crc++;
          }
        }
      return 1;
    }
    else
    {
      return 0;
    }
}
 
int main (void)
{
    if (-1 == wiringPiSetup()) {
      //printf("Setup wiringPi failed!");
      return 1;
    }
 
    pinMode(pinNumber, OUTPUT); // set mode to output
    digitalWrite(pinNumber, 1); // output a high level 

    //while(1) 
    //{
    pinMode(pinNumber,OUTPUT); // set mode to output
    digitalWrite(pinNumber, 1); // output a high level 
    //delay(3000);
    if(readSensorData())
    {
      printf("OK!\n");
      printf("RH:%d.%d\n",(databuf>>24)&0xff,(databuf>>16)&0xff); 
      printf("TMP:%d.%d\n",(databuf>>8)&0xff,databuf&0xff);
      databuf=0;
    }
    else
    {
      printf("Error!\n");
      databuf=0;
    }
    //}
  return 0;
}

用gcc来编译

gcc dht11.c -o dht11 -lwiringPi

然后就可以直接执行来获取温湿度了

root@raspberrypi:~# ./dht11
OK!
RH:73.0
TMP:22.7
root@raspberrypi:~#

因为此程序是用来配合node.js获取温湿度的,因此注释掉了循环,如果想循环读取温湿度,可以把循环和delay的注释去掉就行了

后来测试发现还是有一定的几率读取不出来温湿度,很有可能是因为树莓派硬件问题,时序控制不精确

你可能感兴趣的:(树莓派)