一步一步做一个联网传感器系统 ------ 温湿度实现(第二篇)

一 需求

我们需要实现一个联网温湿度显示系统,它测量室内的温湿度,将数据传输给服务器;手机(iOS)端通过向服务器发起请求来获取温湿度数据。本文先实现获取DHT11的温湿度数据

二 器件

什么温湿度传感器好用?DHT11呗,又便宜,性能也没那么不堪。用什么联网?ESP8266呀,教程又多,AT指令又容易上手。最后,我手里有一个Arduino uno的板子,那何不就地取材呢?

三 实现

1. DHT11的使用方法

DHT11有三个引脚 (图片来自网络,没有任何宣传意图):

一步一步做一个联网传感器系统 ------ 温湿度实现(第二篇)_第1张图片 DHT11
​​​

不懂的童鞋们,百度一下就知道了,很简单。这个家伙是一个单总线的器件(两电源脚,一个数据脚),这意味这电路很简单,但时序会比较复杂。此处,数据引脚接arduino UNO的8号引脚。不多说,上时序图(图片来自于网络):

一步一步做一个联网传感器系统 ------ 温湿度实现(第二篇)_第2张图片

那么,DHT11的使用就如上图所示:

1. 单片机(arduino)发送一个低电平(至少持续18ms)

2. 单片机发送一个高电平(持续20-40us)

3. 前两步相当于一个唤醒信号,DHT11如果没坏,会发回一个响应信号。这一步接受响应信号的低电平部分(约80us)

4. 这一步接受响应信号的高电平部分(大约80us)。

5. 好,DHT11发送完响应信号之后,进入数据传输阶段,这一阶段由两部分组成------一个50us的等待部分,一个真正数据传输部分。这一步就是50us的低电平等待部分。

6. 这一步是数据传输部分。DHT11发送的数据是二进制,0和1都由高电平表示,但是持续时间不同。如果单片机引脚收到了26-28us的高电平,则收到了“0”数据;如果接受到70us的高电平,则收到了“1”数据。DHT11发完一位数据,又回到第5步,重复40次,一共发送40位数据。

2. DHT11的程序

头文件:

#ifndef _Dht11_H_
#define _Dht11_H_
#include 
#define OK 0
#define HIGH_TIMEOUT 1
#define LOW_TIMEOUT 2
#define READ_TIMEOUT 3
#define FAILED_CHECK 4
class dht11
{
  public:
  int dht11_ReadData(int pin); //读取温湿度原始数据
  int getHumidity(); //外部获取湿度
  int getTemperature();//外部获取温度
  private:
  uint8_t humidity; //湿度
  uint8_t temperature;// 温度
};
#endif

cpp源文件

#include "dht11.h"

int dht11::dht11_ReadData(int pin)
{
    uint8_t res[5];//这里用来放置数据,5个,每一个8位,一共40位
    uint8_t count= 7;//每一个数据是8位,一位一位读,所以它用来计数
    uint8_t index= 0;//读完一个数据读下一个,所以它是res数组的计数
    unsigned int timeCount= 10000; //这个是用来看是否超时的

    for (int i=0; i< 5; i++) 
        res[i] = 0;
    //为了防止出现随机数。全部初始化为0.

    pinMode(pin, OUTPUT);
    //将引脚定义为输出,因为第1、2步是单片机发送低电平和高电平,所以是输出状态
    digitalWrite(pin, LOW);
    delay(18);//低电平持续18秒(第一步)

    digitalWrite(pin, HIGH); 
    delayMicroseconds(40);//高电平持续40us(第二步)

    pinMode(pin, INPUT);
    //引脚定义为输入,因为第3,4步是接收DHT11的应答信号,是输入状态

    
    while(digitalRead(pin) == LOW) //(第三步)
        if (timeCount-- == 0) 
            return LOW_TIMEOUT;
    //如果timeCount走完了,而引脚还是低电平,说明DHT11的返回信号有问题,因为此时应该输出高电平

    timeCount= 10000;
    while(digitalRead(pin) == HIGH) //(第四步)
        if (timeCount-- == 0) 
            return HIGH_TIMEOUT;
    //和上面的道理一样。

    //应答信号结束之后,就是进入读取阶段了
    for (int i=0; i<40; i++)
    {
        
        timeCount= 10000;
        while(digitalRead(pin) == LOW) //第5步,50us的低电平
            if (timeCount-- == 0) 
                return READ_TIMEOUT; //超时,50us之后不管数据位是0是1,都应该是高电平了
      
        unsigned long t = micros();//获取当前时间
    
        timeCount= 10000;
        while(digitalRead(pin) == HIGH) //开始读取高电平
            if (loopCnt-- == 0) 
                return READ_TIMEOUT;
        
        if ((micros() - t) > 40)  //跳出while循环说明高电平结束,再次获取当前时间,将其与
                                  //之前获取的时间相减,就是高电平持续时间。大于40us,是“1”          
            res[index] |= (1 << count);//将数据1放置到对应的数据位上。
        //数据0不用管,因为已经在程序开始的时候初始化为0了。
        if (count== 0)   //一个完整的8位数据获取完毕,重新装填计数器
        {
            count= 7;  
            index++;      
        }
        else count--;
    }

    humidity    = res[0]; 
    temperature = res[2]; 

    uint8_t sum = res[0] + res[2];  //因为第2位和第4位总是0,不用管他们

    if (res[4] != sum) 
        return FAILED_CHECK;
}

int dht11::getHumidity()
{
  return humidity;
}

int dht11::getTemperature()
{
  return temperature;
}

 3 主函数实现

#include 
#define DHT 8 //引脚8接DHT11的数据引脚
dht11 dht = dht11();
void setup(){
    Serial.begin(115200);
}

void loop{
    int res = dht.dht11_ReadData(DHT);
    int temp = 0, hum = 0; 
    switch(res){
        case 0:
            temp = dht.getTemperature();
            hum = dht.getHumidity();
            Serial.print(temp);
            Serial.write(',');
            Serial.print(hum);
            break;
        case 1:
            Serial.write("HIGH_TIMEOUT");
            break;
        case 2:
            Serial.write("LOW_TIMEOUT");
            break;
        case 3:
            Serial.write("READ_TIMEOUT");
            break;
        case 4:
            Serial.write("FAILED_CHECK");
    }
}

4. 结果

28, 57

温度28,相对湿度57%

你可能感兴趣的:(一步一步做一个联网传感器系统 ------ 温湿度实现(第二篇))