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





