Arduino đọc dữ liệu nhiệt độ và độ ẩm từ DHT11, DHT22, SHTC3

Bài viết này hướng dẫn cách sử dụng bo mạch NodeMcu để đọc dữ liệu từ ba cảm biến nhiệt độ và độ ẩm: DHT11, DHT22 và SHTC3, sau đó gửi dữ liệu đến cổng nối tiếp. Tôi đã cung cấp ví dụ cho từng cảm biến, cả với và không sử dụng thư viện bên thứ ba.

Hướng dẫn thiết lập môi trường phát triển ESP8266: https://blog.zeruns.com/archives/526.html

Địa điểm mua các cảm biến được sử dụng trong bài viết nằm ở cuối bài.

DHT11

DHT11 là một cảm biến nhiệt độ và độ ẩm có đầu ra tín hiệu số đã được hiệu chuẩn. Độ chính xác của nó là ±5% RH đối với độ ẩm và ±2°C đối với nhiệt độ, phạm vi đo là độ ẩm 20-90% RH và nhiệt độ 0~50°C. Độ chính xác không cao nhưng giá thành rẻ. DHT11 sử dụng giao thức một dây. Điện áp cấp là 3.3~5V.

Sử dụng thư viện DHT

Sử dụng thư viện DHT sensor library (cần cài đặt thủ công, hướng dẫn cài đặt ở Hướng dẫn thiết lập môi trường phát triển ESP8266 ở trên) để đọc trực tiếp dữ liệu từ DHT11.

#include ```<DHT.h>        // Gọi thư viện DHT

DHT dht(D1, DHT11);      // Thiết lập chân dữ liệu kết nối với IO và loại cảm biến

void setup(){ // Hàm khởi tạo, chỉ chạy một lần khi chương trình bắt đầu
  Serial.begin(115200);   // Thiết lập tốc độ baud của cổng nối tiếp
  dht.begin();       
}
//https://blog.zeruns.com
void loop() {
  delay(1000);                  // Trễ 1000 mili giây
  float RH = dht.readHumidity();   // Đọc dữ liệu độ ẩm
  float T = dht.readTemperature();// Đọc dữ liệu nhiệt độ
  Serial.print("Humidity:");  // In ra cổng nối tiếp "Humidity:"
  Serial.print(RH);           // In ra dữ liệu độ ẩm
  Serial.print("%");
  Serial.print("  Temperature:");
  Serial.print(T);            // In ra dữ liệu nhiệt độ
  Serial.println("C"); 
  Serial.println("https://blog.zeruns.com");
}

Không sử dụng thư viện

Đọc dữ liệu từ tài liệu hướng dẫn của DHT11 và tự viết chương trình.

Tài liệu hướng dẫn DHT11: http://go.zeruns.com/G

#define data D1   // Chân Data (Pin 2) của DHT11 kết nối với chân D1 của bo mạch NodeMcu

unsigned char i;  // Biến nguyên không dấu 8 bit
float RH,T;       // Số thực đơn chính xác (độ dài 32 bit)
byte RH_H,RH_L,T_H,T_L,sum,check;  // Biến byte, số nhị phân

void setup() {    // Hàm khởi tạo, chỉ chạy một lần khi chương trình bắt đầu
  Serial.begin(115200);   // Thiết lập tốc độ baud của cổng nối tiếp
}

void loop() {     // Hàm lặp, chạy liên tục sau khi hoàn thành hàm khởi tạo
  delay(1000);    // Trễ 1000 mili giây
  DHT11();        // Lấy dữ liệu nhiệt độ và độ ẩm
  Serial.print("Humidity:");  // In ra cổng nối tiếp "Humidity:"
  Serial.print(RH);           // In ra dữ liệu độ ẩm
  Serial.print("%");
  Serial.print("  Temperature:");
  Serial.print(T);            // In ra dữ liệu nhiệt độ
  Serial.println("C"); 
  Serial.println("https://blog.zeruns.com");
}

void DHT11()
{
  RH_H=0,RH_L=0,T_H=0,T_L=0,sum=0,check=0;
  pinMode(data,OUTPUT);   // Thiết lập chân IO ở chế độ đầu ra
  digitalWrite(data,1);   // Thiết lập chân IO đầu ra mức cao
  delay(10);              // Trễ 10 mili giây
  digitalWrite(data,0);   // Thiết lập chân IO đầu ra mức thấp
  delay(25);              // Trễ 25 mili giây
  digitalWrite(data,1);   // Thiết lập chân IO đầu ra mức cao
  pinMode(data,INPUT);    // Thiết lập chân IO ở chế độ đầu vào
  delayMicroseconds(30);  // Trễ 30 micro giây
  if(!digitalRead(data))  // Kiểm tra mức điện áp đầu vào có phải mức thấp không
  {//https://blog.zeruns.com
    while(!digitalRead(data));  // Lặp cho đến khi đầu vào ở mức cao
    while(digitalRead(data));   // Lặp cho đến khi đầu vào ở mức thấp
    for(i=0;i<8;i++)            // Lặp 8 lần
    {   
      while(!digitalRead(data));// Lặp cho đến khi đầu vào ở mức cao   
      delayMicroseconds(28);    // Trễ 28 micro giây
      if(digitalRead(data)){    // Kiểm tra mức điện áp đầu vào có phải mức cao không
        bitWrite(RH_H, 7-i, 1); // Ghi 1 vào bit thứ 7-i (tính từ phải sang) của biến nhị phân RH_H   
        while(digitalRead(data));
      }
    }
    for(i=0;i<8;i++)
    {
      while(!digitalRead(data));
      delayMicroseconds(28);
      if(digitalRead(data)){
        bitWrite(RH_L, 7-i, 1);
        while(digitalRead(data));
      }
    }
    for(i=0;i<8;i++)
    {
      while(!digitalRead(data));
      delayMicroseconds(28);
      if(digitalRead(data)){  
        bitWrite(T_H, 7-i, 1);
        while(digitalRead(data));
      }
    }
    for(i=0;i<8;i++)
    {
      while(!digitalRead(data));
      delayMicroseconds(28);
      if(digitalRead(data)){  
        bitWrite(T_L, 7-i, 1);
        while(digitalRead(data));
      }
    }
    for(i=0;i<8;i++)
    {
      while(!digitalRead(data));
      delayMicroseconds(28);
      if(digitalRead(data)){  
        bitWrite(check, 7-i, 1);
        while(digitalRead(data));
      }
    }
   }
  sum=RH_H + RH_L + T_H + T_L;
  byte sum_temp=0;
  // Đọc 8 bit cuối của sum ghi vào sum_temp
  for(i=0;i<8;i++){
    bitWrite(sum_temp,i,bitRead(sum,i)); 
  }//https://blog.zeruns.com
  if(check==sum_temp){  // Kiểm tra dữ liệu
    RH=RH_H+float(RH_L)/10;
    T=T_H+float(T_L)/10;
  }
}

Kết quả

DHT22 (AM2302)

DHT22 (AM2302) là cảm biến nhiệt độ và độ ẩm có đầu ra tín hiệu số đã hiệu chuẩn. Độ chính xác độ ẩm ±2%RH, nhiệt độ ±0.5℃, phạm vi đo độ ẩm 0-100%RH, nhiệt độ -40~80℃, độ phân giải đều là 0.1. Độ chính xác cao và giá thành không đắt. DHT22 sử dụng giao thức một dây. Điện áp cấp là 3.3~5V.

Sử dụng thư viện DHT

Sử dụng thư viện DHT sensor library để đọc dữ liệu trực tiếp từ DHT22.

#include <DHT.h>        // Gọi thư viện DHT

DHT dht(D1, DHT22);      // Thiết lập chân dữ liệu kết nối với IO và loại cảm biến

void setup(){ // Hàm khởi tạo, chỉ chạy một lần khi chương trình bắt đầu
  Serial.begin(115200);   // Thiết lập tốc độ baud của cổng nối tiếp
  dht.begin();       
}
//https://blog.zeruns.com
void loop() {
  delay(1000);                  // Trễ 1000 mili giây
  float RH = dht.readHumidity();   // Đọc dữ liệu độ ẩm
  float T = dht.readTemperature();// Đọc dữ liệu nhiệt độ
  Serial.print("Humidity:");  // In ra cổng nối tiếp "Humidity:"
  Serial.print(RH);           // In ra dữ liệu độ ẩm
  Serial.print("%");
  Serial.print("  Temperature:");
  Serial.print(T);            // In ra dữ liệu nhiệt độ
  Serial.println("C"); 
  Serial.println("https://blog.zeruns.com");
}

Không sử dụng thư viện

Đọc dữ liệu từ tài liệu hướng dẫn của DHT22 và tự viết chương trình.

Tài liệu hướng dẫn DHT22: http://go.zeruns.com/H

#define data D1   // Chân Data (Pin 2) của DHT22 kết nối với chân D1 của bo mạch NodeMcu

unsigned char i;  // Biến nguyên không dấu 8 bit
float RH,T;       // Số thực đơn chính xác (độ dài 32 bit)
byte RH_H,RH_L,T_H,T_L,sum,check;  // Biến byte, số nhị phân

void setup() {    // Hàm khởi tạo, chỉ chạy một lần khi chương trình bắt đầu
  Serial.begin(115200);   // Thiết lập tốc độ baud của cổng nối tiếp
}

void loop() {     // Hàm lặp, chạy liên tục sau khi hoàn thành hàm khởi tạo
  delay(1000);    // Trễ 1000 mili giây
  DHT11();        // Lấy dữ liệu nhiệt độ và độ ẩm
  Serial.print("Humidity:");  // In ra cổng nối tiếp "Humidity:"
  Serial.print(RH);           // In ra dữ liệu độ ẩm
  Serial.print("%");
  Serial.print("  Temperature:");
  Serial.print(T);            // In ra dữ liệu nhiệt độ
  Serial.println("C"); 
  Serial.println("https://blog.zeruns.com");
}

void DHT11()
{
  RH_H=0,RH_L=0,T_H=0,T_L=0,sum=0,check=0;
  pinMode(data,OUTPUT);   // Thiết lập chân IO ở chế độ đầu ra
  digitalWrite(data,1);   // Thiết lập chân IO đầu ra mức cao
  delay(10);              // Trễ 10 mili giây
  digitalWrite(data,0);   // Thiết lập chân IO đầu ra mức thấp
  delay(25);              // Trễ 25 mili giây
  digitalWrite(data,1);   // Thiết lập chân IO đầu ra mức cao
  pinMode(data,INPUT);    // Thiết lập chân IO ở chế độ đầu vào
  delayMicroseconds(30);  // Trễ 30 micro giây
  if(!digitalRead(data))  // Kiểm tra mức điện áp đầu vào có phải mức thấp không
  {//https://blog.zeruns.com
    while(!digitalRead(data));  // Lặp cho đến khi đầu vào ở mức cao
    while(digitalRead(data));   // Lặp cho đến khi đầu vào ở mức thấp
    for(i=0;i<8;i++)            // Lặp 8 lần
    {   
      while(!digitalRead(data));// Lặp cho đến khi đầu vào ở mức cao   
      delayMicroseconds(28);    // Trễ 28 micro giây
      if(digitalRead(data)){    // Kiểm tra mức điện áp đầu vào có phải mức cao không
        bitWrite(RH_H, 7-i, 1); // Ghi 1 vào bit thứ 7-i (tính từ phải sang) của biến nhị phân RH_H   
        while(digitalRead(data));
      }
    }
    for(i=0;i<8;i++)
    {
      while(!digitalRead(data));
      delayMicroseconds(28);
      if(digitalRead(data)){
        bitWrite(RH_L, 7-i, 1);
        while(digitalRead(data));
      }
    }
    for(i=0;i<8;i++)
    {
      while(!digitalRead(data));
      delayMicroseconds(28);
      if(digitalRead(data)){  
        bitWrite(T_H, 7-i, 1);
        while(digitalRead(data));
      }
    }
    for(i=0;i<8;i++)
    {
      while(!digitalRead(data));
      delayMicroseconds(28);
      if(digitalRead(data)){  
        bitWrite(T_L, 7-i, 1);
        while(digitalRead(data));
      }
    }
    for(i=0;i<8;i++)
    {
      while(!digitalRead(data));
      delayMicroseconds(28);
      if(digitalRead(data)){  
        bitWrite(check, 7-i, 1);
        while(digitalRead(data));
      }
    }
   }
  sum=RH_H + RH_L + T_H + T_L;
  byte sum_temp=0;
  // Đọc 8 bit cuối của sum ghi vào sum_temp
  for(i=0;i<8;i++){
    bitWrite(sum_temp,i,bitRead(sum,i)); 
  }//https://blog.zeruns.com
  if(check==sum_temp){
    if(bitRead(RH_H,7)==1){ // Kiểm tra nhiệt độ có âm không
      T=-(float(T_H<<8)+float(T_L))/10;
    }else{
      T=(float(T_H<<8)+float(T_L))/10;
    }
    RH=(float(RH_H<<8)+float(RH_L))/10;
  }  
}

Kết quả

SHTC3

SHTC3 là cảm biến nhiệt độ và độ ẩm có đầu ra tín hiệu số đã hiệu chuẩn. Độ chính xác độ ẩm ±2%RH, nhiệt độ ±0.2℃, phạm vi đo độ ẩm 0-100%RH, nhiệt độ -40~125℃, độ phân giải đều là 0.01. Độ chính xác cao và giá thành cũng tương đối rẻ, nhưng tài liệu rất ít. SHTC3 sử dụng giao thức I2C (IIC). Điện áp cấp là 1.62~3.6V.

Tài liệu hướng dẫn SHTC3: http://go.zeruns.com/I

Sử dụng thư viện Wire (I2C)

Sử dụng thư viện Wire để giao tiếp với SHTC3 và đọc dữ liệu.

/* https://blog.zeruns.com
 * Cách kết nối
 * SHTC3    Bảng phát triển
 * SCL      SCL (Bảng NodeMcu là D1)
 * SDA      SDA (Bảng NodeMcu là D2)
 */
#include <Wire.h>

#define SHTC3_ADDRESS 0x70  // Định nghĩa địa chỉ thiết bị I2C của SHTC3 là 0x70
float T, RH;

void setup() {    // Hàm khởi tạo, chỉ chạy một lần khi chương trình bắt đầu
  Serial.begin(115200);   // Thiết lập tốc độ baud của cổng nối tiếp
  Wire.begin();   // Khởi tạo dưới dạng chủ I2C
}

void loop() {     // Hàm lặp, chạy liên tục sau khi hàm khởi tạo hoàn thành
  delay(1000);    // Trễ 1000 mili giây
  SHTC3();        // Lấy dữ liệu nhiệt độ và độ ẩm
  Serial.print("Humidity:");  // In ra cổng nối tiếp Humidity:
  Serial.print(RH);           // In ra dữ liệu độ ẩm
  Serial.print("%");
  Serial.print("  Temperature:");
  Serial.print(T);            // In ra dữ liệu nhiệt độ
  Serial.println("C"); 
  Serial.println("https://blog.zeruns.com");
}

void SHTC3(){   // Lấy dữ liệu nhiệt độ và độ ẩm
  Wire.beginTransmission(SHTC3_ADDRESS); // Bắt đầu truyền dữ liệu đến thiết bị con I2C theo địa chỉ 0x70.
  Wire.write(byte(0xE0));       // Gửi lệnh ghi
  Wire.endTransmission();       // Dừng truyền dữ liệu đến thiết bị con
  Wire.beginTransmission(SHTC3_ADDRESS);
  Wire.write(byte(0x35));       // Gửi phần cao của lệnh đánh thức
  Wire.write(byte(0x17));       // Gửi phần thấp của lệnh đánh thức
  Wire.endTransmission();
  delayMicroseconds(300);       // Trễ 300 micro giây
  Wire.beginTransmission(SHTC3_ADDRESS);
  Wire.write(byte(0xE0));
  Wire.endTransmission();
  Wire.beginTransmission(SHTC3_ADDRESS);
  Wire.write(byte(0x7C));       // Gửi phần cao của lệnh lấy dữ liệu
  Wire.write(byte(0xA2));       // Gửi phần thấp của lệnh lấy dữ liệu
  Wire.endTransmission();
  Wire.beginTransmission(SHTC3_ADDRESS);
  Wire.write(byte(0xE1));       // Gửi lệnh đọc
  Wire.endTransmission();
  Wire.requestFrom(SHTC3_ADDRESS,6);     // Yêu cầu dữ liệu từ thiết bị con
  uint16_t T_temp, RH_temp, T_CRC, RH_CRC;
  if (2 <= Wire.available()) {
    T_temp = Wire.read();     // Nhận dữ liệu cao của nhiệt độ
    T_temp = T_temp << 8;     // Dịch trái 8 bit
    T_temp |= Wire.read();    // Thực hiện phép toán OR bit giữa dữ liệu cao đã dịch trái và dữ liệu thấp của nhiệt độ nhận được
    T_CRC = Wire.read();      // Nhận mã CRC
    if(SHTC3_CRC_CHECK(T_temp,T_CRC)){  // Kiểm tra dữ liệu
      T = float(T_temp) * 175 / 65536 - 45;  // Tính toán nhiệt độ
    }
  }//https://blog.zeruns.com
  if (2 <= Wire.available()) {
    RH_temp = Wire.read();     // Nhận dữ liệu cao của độ ẩm
    RH_temp = RH_temp << 8;     // Dịch trái 8 bit
    RH_temp |= Wire.read();    // Thực hiện phép toán OR bit giữa dữ liệu cao đã dịch trái và dữ liệu thấp của độ ẩm nhận được
    RH_CRC = Wire.read();
    if(SHTC3_CRC_CHECK(RH_temp,RH_CRC)){
      RH = float(RH_temp) * 100 / 65536;
    }
  }
}
//https://blog.zeruns.com
uint8_t SHTC3_CRC_CHECK(uint16_t DAT, uint8_t CRC_DAT) // Kiểm tra CRC của SHTC3
{
    uint8_t i, t, temp;
    uint8_t CRC_BYTE;  
    CRC_BYTE = 0xFF;  
    temp = (DAT >> 8) & 0xFF;  
    for(t = 0; t < 2; t ++)
    {
        CRC_BYTE ^= temp;
        for(i = 0; i < 8; i ++)
        {
            if(CRC_BYTE & 0x80)
            {
                CRC_BYTE <<= 1;         
                CRC_BYTE ^= 0x31;  
            }else{
                CRC_BYTE <<= 1;  
            }
        }  
        if(t == 0)
        {
            temp = DAT & 0xFF; 
        }
    }//https://blog.zeruns.com  
    if(CRC_BYTE == CRC_DAT)
    {
        temp = 1;  
    }else{
        temp = 0;  
    }   
    return temp;
}

### Sử dụng thư viện SHTC3

Cài đặt thư viện `SparkFun SHTC3` trước.

```c
/* https://blog.zeruns.com
 * Cách kết nối
 * SHTC3    Bảng phát triển
 * SCL      SCL (Bảng NodeMcu là D1)
 * SDA      SDA (Bảng NodeMcu là D2)
 */

#include <SparkFun_SHTC3.h>

SHTC3 mySHTC3;

void setup(){ // Hàm khởi tạo, chỉ chạy một lần khi chương trình bắt đầu
  Serial.begin(115200);   // Thiết lập tốc độ baud của cổng nối tiếp
  while(Serial == false){};   // Chờ kết nối serial khởi động
  Wire.begin();           // Khởi tạo thư viện Wire (I2C)
  unsigned char i=0;
  errorDecoder(mySHTC3.begin());// Để khởi động cảm biến, bạn phải gọi "begin()", cài đặt mặc định sử dụng Wire (cổng I2C mặc định của Arduino)
}
//https://blog.zeruns.com
void loop() {
  float RH, T;
  delay(1000);                  // Trễ 1000 mili giây
  SHTC3_Status_TypeDef result = mySHTC3.update();
  if(mySHTC3.lastStatus == SHTC3_Status_Nominal)   // Kiểm tra xem trạng thái SHTC3 có bình thường không
  {
    RH = mySHTC3.toPercent();   // Đọc dữ liệu độ ẩm                
    T = mySHTC3.toDegC();       // Đọc dữ liệu nhiệt độ             
  }else{
    Serial.print("Update failed, error: ");
    errorDecoder(mySHTC3.lastStatus); // In ra nguyên nhân lỗi
    Serial.println();
  }
  Serial.print("Humidity:");  // In ra cổng nối tiếp Humidity:
  Serial.print(RH);           // In ra dữ liệu độ ẩm
  Serial.print("%");
  Serial.print("  Temperature:");
  Serial.print(T);            // In ra dữ liệu nhiệt độ
  Serial.println("C"); 
  Serial.println("https://blog.zeruns.com");
}

void errorDecoder(SHTC3_Status_TypeDef message) // Hàm errorDecoder in kết quả "SHTC3_Status_TypeDef" theo cách thân thiện với người dùng
{
  switch(message)
  {
    case SHTC3_Status_Nominal : Serial.print("Nominal"); break;
    case SHTC3_Status_Error : Serial.print("Error"); break;
    case SHTC3_Status_CRC_Fail : Serial.print("CRC Fail"); break;
    default : Serial.print("Unknown return code"); break;
  }
}

Hình ảnh hiệu quả

Mua cảm biến

DHT11: Sao chép $Lk3h1Mx8UTO$ để mở Taobao trên điện thoại và đặt hàng ngay

DHT22: Sao chép $kr2T1MxkUKY$ để mở Taobao trên điện thoại và đặt hàng ngay

SHTC3: Sao chép $UD4D1Mx6N3R$ để mở Taobao trên điện thoại và đặt hàng ngay

Bài viết nên đọc:

  • Khuyến nghị VPS/ máy chủ đám mây giá rẻ và hiệu quả: https://blog.zeruns.com/archives/383.html
  • Xây dựng máy chủ xuyên tường nội mạng với bảng điều khiển Web: https://blog.zeruns.com/archives/397.html
  • Tự xây dựng ổ đĩa đám mây với Cloudreve: https://blog.zeruns.com/archives/515.html
  • Cách xây dựng blog cá nhân: https://blog.zeruns.com/archives/218.html
  • Toàn bộ quyền lợi sinh viên: https://blog.zeruns.com/archives/321.html
  • Chia sẻ một trò chơi nhỏ có thể kiếm tiền: https://blog.zeruns.com/archives/472.html
1 Lượt thích