Giới thiệu
AM2301 (hay DHT21) là cảm biến đo nhiệt độ và độ ẩm tương đối với độ chính xác cao và khả năng truyền dữ liệu dễ dàng qua giao thức 1-Wire. Nó được sử dụng phổ biến trong các ứng dụng IoT, tự động hóa và kiểm soát môi trường.
Thông số kỹ thuật
- Điện áp hoạt động: 3.3 - 5V
- Phạm vi đo nhiệt độ: -40°C đến +80°C (Sai số ±0.5°C)
- Phạm vi đo độ ẩm: 0 - 100% RH (Sai số ±3%)
- Tần suất lấy mẫu: Tối đa 0.5 Hz (1 lần/2 giây)
- Giao tiếp: 1-Wire
- Kích thước: 59mm x 27mm x 13.5mm
Sơ đồ chân AM2301/DHT21
Mô tả các chân
- Dây màu đỏ: Chân cấp nguồn, có thể kết nối với 3.3V hoặc 5V từ Arduino.
- Dây đen: nối đất (GND)
- Dây màu vàng: Data (phải được kết nối với một trong các chân kỹ thuật số của vi điều khiển)
Thành phần cần thiết
Cài đặt thư viện và phần mềm
- Mở Arduino IDE.
- Vào Tools > Manage Libraries.
- Tìm và cài đặt thư viện DHT sensor library của Adafruit.
- Đảm bảo bạn đã cài thư viện Adafruit Unified Sensor (được yêu cầu kèm theo).
VD1: Hiển thị nhiệt độ độ ẩm đo được lên serial monitor
Sơ đồ kết nối
- VCC: Kết nối 3.3V hoặc 5V từ Arduino
- GND: Kết nối chân GND của Arduino
- DATA: Kết nối với chân kỹ thuật số của Arduino (VD: D2) ở bài viết này mình nối với chân A1
Code
#include <LiquidCrystal.h>
#include <DHT.h>
#define DHTPIN A1 // Chân DATA nối với chân A1
#define DHTTYPE DHT21 // Cảm biến AM2301/DHT21
DHT dht(DHTPIN, DHTTYPE);
float h = dht.readHumidity(); // Đọc độ ẩm
float t = dht.readTemperature(); // Đọc nhiệt độ
void setup() {
Serial.begin(9600);
dht.begin();
Serial.println("truongcongly.com");
Serial.println("Đang đọc dữ liệu từ cảm biến...");
}
void loop() {
delay(1000);
//Đọc dữ liệu và lưu trữ vào các biến hum và temp
hum = dht.readHumidity();
temp = dht.readTemperature();
// Kiểm tra lỗi đọc dữ liệu
if (isnan(hum) || isnan(temp)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
} else {
// In giá trị nhiệt độ và độ ẩm ra Serial Monitor
Serial.print("Temperature: ");
Serial.print(temp, 1);
Serial.print(" Hummidity: ");
Serial.print(hum, 1);
Serial.println();
}
}
Hướng dẫn kiểm tra
- Nạp code vào Arduino qua cổng USB.
- Mở Serial Monitor (Ctrl + Shift + M) trong Arduino IDE để xem dữ liệu cảm biến được in ra mỗi 1 giây.
VD2: Làm mạch khống chế nhiệt độ độ ẩm hiển thị lên lcd và điều khiển ngõ ra relay
Sơ đồ kết nối
Arduino | HC-SR04 | Buzzer |
---|---|---|
GND | GND | GND |
5V | Vcc | |
D6 | Echo | |
D7 | Trig | |
D13 | Positive (+) |
Code
#include <LiquidCrystal.h>
#include <DHT.h>
#include <EEPROM.h>
//Constants
#define DHTPIN A1 //what pin we're connected to
#define DHTTYPE DHT21 //DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE); //Initialize DHT sensor for normal 16mhz Arduino
//Variables
float hum; //Stores humidity value
float temp; //Stores temperature value
int setT = 0, setH = 0;
enum Mode { HOT,
COOL };
Mode mode = HOT;
unsigned long previousMillis = 0; // Lưu thời gian trước đó
unsigned long lastPressTime = 0; // Thời gian của lần nhấn trước
const unsigned long delayTime = 100; // Thời gian nhấn chậm (ms)
const unsigned long rapidDelayTime = 200; // Thời gian nhấn giữ (ms)
int lastKeyState = 0; // Trạng thái của nút trước đó
int homeIndex = 0, settingIndex = 0;
//LCD pin to Arduino
const int pin_RS = 8;
const int pin_EN = 9;
const int pin_d4 = 4;
const int pin_d5 = 5;
const int pin_d6 = 6;
const int pin_d7 = 7;
const int pin_BL = 10;
LiquidCrystal lcd(pin_RS, pin_EN, pin_d4, pin_d5, pin_d6, pin_d7);
byte degree[8] = {
0B01110,
0B01010,
0B01110,
0B00000,
0B00000,
0B00000,
0B00000,
0B00000
};
const int Q1 = 2; //Ngõ ra 1
const int Q2 = 3; //Ngõ ra 2
char keyPad() {
int x = analogRead(0);
if (x < 60) {
return 'R';
} else if (x < 200) {
return 'U';
} else if (x < 400) {
return 'D';
} else if (x < 600) {
return 'L';
} else if (x < 800) {
return 'S';
}
}
bool clearCursor = false; // Biến để theo dõi trạng thái xóa cursor
void setTemp() {
unsigned long currentMillis = millis(); // Lấy thời gian hiện tại
char buffer[3]; // Buffer để lưu chuỗi định dạng
// Cập nhật LCD
lcd.setCursor(4, 0);
lcd.print("Settings");
lcd.setCursor(0, 1);
lcd.print("T=");
sprintf(buffer, "%02d", setT); // Định dạng setT thành 2 chữ số
lcd.print(buffer); // In giá trị đã định dạng
lcd.setCursor(5, 1);
lcd.print("H=");
sprintf(buffer, "%02d", setH); // Định dạng setH thành 2 chữ số
lcd.print(buffer); // In giá trị đã định dạng
lcd.setCursor(10, 1);
lcd.print("M=");
if (mode == HOT) {
sprintf(buffer, "HOT");
} else {
sprintf(buffer, "COOL");
}
lcd.print(buffer); // In giá trị đã định dạng
// Kiểm tra xem có đến thời gian để cập nhật hay không
if (currentMillis - previousMillis >= 200) {
previousMillis = currentMillis; // Cập nhật thời gian cuối cùng
// Thay đổi trạng thái xóa cursor
clearCursor = !clearCursor;
if (clearCursor) {
lcd.setCursor(4, 1);
lcd.print(" "); // Xóa cursor
} else {
lcd.setCursor(4, 1);
lcd.print("."); // Hiển thị lại chữ H
}
}
// Gọi các hàm khác hoặc xử lý công việc khác ở đây nếu cần
}
void setHum() {
unsigned long currentMillis = millis(); // Lấy thời gian hiện tại
char buffer[3]; // Buffer để lưu chuỗi định dạng
// Cập nhật LCD
lcd.setCursor(4, 0);
lcd.print("Settings");
lcd.setCursor(0, 1);
lcd.print("T=");
sprintf(buffer, "%02d", setT); // Định dạng setT thành 2 chữ số
lcd.print(buffer); // In giá trị đã định dạng
lcd.setCursor(5, 1);
lcd.print("H=");
sprintf(buffer, "%02d", setH); // Định dạng setH thành 2 chữ số
lcd.print(buffer); // In giá trị đã định dạng
lcd.setCursor(10, 1);
lcd.print("M=");
if (mode == HOT) {
sprintf(buffer, "HOT");
} else {
sprintf(buffer, "COOL");
}
lcd.print(buffer); // In giá trị đã định dạng
// Kiểm tra xem có đến thời gian để cập nhật hay không
if (currentMillis - previousMillis >= 200) {
previousMillis = currentMillis; // Cập nhật thời gian cuối cùng
// Thay đổi trạng thái xóa cursor
clearCursor = !clearCursor;
if (clearCursor) {
lcd.setCursor(9, 1);
lcd.print(" "); // Xóa cursor
} else {
lcd.setCursor(9, 1);
lcd.print("."); // Hiển thị lại chữ H
}
}
// Gọi các hàm khác hoặc xử lý công việc khác ở đây nếu cần
}
void setMode() {
unsigned long currentMillis = millis(); // Lấy thời gian hiện tại
char buffer[3]; // Buffer để lưu chuỗi định dạng
// Cập nhật LCD
lcd.setCursor(4, 0);
lcd.print("Settings");
lcd.setCursor(0, 1);
lcd.print("T=");
sprintf(buffer, "%02d", setT); // Định dạng setT thành 2 chữ số
lcd.print(buffer); // In giá trị đã định dạng
lcd.setCursor(5, 1);
lcd.print("H=");
sprintf(buffer, "%02d", setH); // Định dạng setH thành 2 chữ số
lcd.print(buffer); // In giá trị đã định dạng
lcd.setCursor(10, 1);
lcd.print("M=");
if (mode == HOT) {
sprintf(buffer, "HOT");
} else {
sprintf(buffer, "COOL");
}
lcd.print(buffer); // In giá trị đã định dạng
// Kiểm tra xem có đến thời gian để cập nhật hay không
if (currentMillis - previousMillis >= 200) {
previousMillis = currentMillis; // Cập nhật thời gian cuối cùng
// Thay đổi trạng thái xóa cursor
clearCursor = !clearCursor;
if (clearCursor) {
lcd.setCursor(15, 1);
lcd.print(" "); // Xóa cursor
} else {
lcd.setCursor(15, 1);
lcd.print("."); // Hiển thị lại chữ H
}
}
// Gọi các hàm khác hoặc xử lý công việc khác ở đây nếu cần
}
void switchScreen(int &index) {
int key = keyPad(); // Lấy trạng thái nút
// Kiểm tra nút phải
if (key == 'R') {
if (lastKeyState != 'R') { // Nếu nút vừa được nhấn
lastPressTime = millis(); // Ghi lại thời gian nhấn
}
// Tăng nhanh nếu giữ nút
if (millis() - lastPressTime < rapidDelayTime) {
// Không làm gì, chỉ tăng sau khi nhấn giữ
} else if (millis() - lastPressTime >= delayTime) { // Nếu đã qua thời gian nhấn chậm
index++;
if (index > 1) index = 0;
lcd.clear();
lastPressTime = millis(); // Cập nhật thời gian
}
}
// Kiểm tra nút trái
else if (key == 'L') {
if (lastKeyState != 'L') { // Nếu nút vừa được nhấn
lastPressTime = millis(); // Ghi lại thời gian nhấn
}
// Tăng nhanh nếu giữ nút
if (millis() - lastPressTime < rapidDelayTime) {
// Không làm gì, chỉ tăng sau khi nhấn giữ
} else if (millis() - lastPressTime >= delayTime) { // Nếu đã qua thời gian nhấn chậm
index--;
if (index < 0) index = 1;
lcd.clear();
lastPressTime = millis(); // Cập nhật thời gian
}
}
lastKeyState = key; // Cập nhật trạng thái nút trước đó
}
void setup() {
lcd.createChar(1, degree);
pinMode(Q1, OUTPUT);
pinMode(Q2, OUTPUT);
digitalWrite(Q1, LOW);
digitalWrite(Q2, LOW);
Serial.begin(9600);
lcd.begin(16, 2);
dht.begin();
lcd.setCursor(2, 0);
lcd.print("AM2301 DHT21");
lcd.setCursor(6, 1);
lcd.print("test");
delay(500);
lcd.clear();
}
void loop() {
//Đọc dữ liệu và lưu trữ vào các biến hum và temp
hum = dht.readHumidity();
temp = dht.readTemperature();
setT = EEPROM.read(5);
setH = EEPROM.read(6);
if (isnan(hum) || isnan(temp)) {
Serial.println(F("Failed to read from DHT sensor!"));
lcd.setCursor(0, 0);
lcd.print("DHT sensor error!");
lcd.setCursor(0, 1);
lcd.print(" ");
return;
} else {
switchScreen(homeIndex);
switch (homeIndex) {
case 0:
// Kiểm tra xem đã đủ 2000ms kể từ lần cập nhật trước chưa
if (millis() - previousMillis >= 2000) {
previousMillis = millis(); // Cập nhật thời gian hiện tại
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(temp, 1);
lcd.write(1);
lcd.print("C");
lcd.setCursor(0, 1);
lcd.print("H:");
lcd.print(hum, 1);
lcd.print(" %");
// In giá trị nhiệt độ và độ ẩm ra Serial Monitor
Serial.print("Temp: ");
Serial.print(temp, 1);
Serial.print(" Hum: ");
Serial.print(hum, 1);
Serial.println();
switch (mode) {
case HOT:
if (temp > setT) {
lcd.setCursor(10, 0);
lcd.print("Q1: CL");
digitalWrite(Q1, LOW);
} else {
lcd.setCursor(10, 0);
lcd.print("Q1: OP");
digitalWrite(Q1, HIGH);
}
if (hum > setH) {
lcd.setCursor(10, 1);
lcd.print("Q2: CL");
digitalWrite(Q2, LOW);
} else {
lcd.setCursor(10, 1);
lcd.print("Q2: OP");
digitalWrite(Q2, HIGH);
}
break;
case COOL:
if (temp < setT) {
lcd.setCursor(10, 0);
lcd.print("Q1: CL");
digitalWrite(Q1, LOW);
} else {
lcd.setCursor(10, 0);
lcd.print("Q1: OP");
digitalWrite(Q1, HIGH);
}
if (hum < setH) {
lcd.setCursor(10, 1);
lcd.print("Q2: CL");
digitalWrite(Q2, LOW);
} else {
lcd.setCursor(10, 1);
lcd.print("Q2: OP");
digitalWrite(Q2, HIGH);
}
}
}
break;
case 1:
if (keyPad() == 'S') {
settingIndex++;
if (settingIndex > 3) settingIndex = 0;
lcd.setCursor(0, 1);
lcd.print(" ");
while (keyPad() == 'S')
;
}
switch (settingIndex) {
case 0:
{
char buffer[3];
lcd.setCursor(4, 0);
lcd.print("Settings");
lcd.setCursor(0, 1);
lcd.print("T=");
sprintf(buffer, "%02d", setT); // Định dạng setT thành 2 chữ số
lcd.print(buffer); // In giá trị đã định dạng
lcd.setCursor(5, 1);
lcd.print("H=");
sprintf(buffer, "%02d", setH); // Định dạng setH thành 2 chữ số
lcd.print(buffer); // In giá trị đã định dạng
lcd.setCursor(10, 1);
lcd.print("M=");
if (mode == HOT) {
sprintf(buffer, "HOT");
} else {
sprintf(buffer, "COOL");
}
lcd.print(buffer); // In giá trị đã định dạng
break;
}
case 1:
{
setTemp();
int key = keyPad();
// Kiểm tra nút lên
if (key == 'U') {
if (lastKeyState != 'U') { // Nếu nút vừa được nhấn
lastPressTime = millis(); // Ghi lại thời gian nhấn
}
// Tăng nhanh nếu giữ nút
if (millis() - lastPressTime < rapidDelayTime) {
// Không làm gì, chỉ tăng sau khi nhấn giữ
} else if (millis() - lastPressTime >= delayTime) { // Nếu đã qua thời gian nhấn chậm
setT++;
if (setT > 80) setT = 0;
lastPressTime = millis(); // Cập nhật thời gian
}
}
// Kiểm tra nút xuông
if (key == 'D') {
if (lastKeyState != 'D') { // Nếu nút vừa được nhấn
lastPressTime = millis(); // Ghi lại thời gian nhấn
}
// Tăng nhanh nếu giữ nút
if (millis() - lastPressTime < rapidDelayTime) {
// Không làm gì, chỉ tăng sau khi nhấn giữ
} else if (millis() - lastPressTime >= delayTime) { // Nếu đã qua thời gian nhấn chậm
setT--;
if (setT < 0) setT = 80;
lastPressTime = millis(); // Cập nhật thời gian
}
}
EEPROM.write(5, setT);
break;
}
case 2:
{
int key = keyPad();
// Kiểm tra nút lên
if (key == 'U') {
if (lastKeyState != 'U') { // Nếu nút vừa được nhấn
lastPressTime = millis(); // Ghi lại thời gian nhấn
}
// Tăng nhanh nếu giữ nút
if (millis() - lastPressTime < rapidDelayTime) {
// Không làm gì, chỉ tăng sau khi nhấn giữ
} else if (millis() - lastPressTime >= delayTime) { // Nếu đã qua thời gian nhấn chậm
setH++;
if (setH > 80) setH = 0;
lastPressTime = millis(); // Cập nhật thời gian
}
}
// Kiểm tra nút xuông
if (key == 'D') {
if (lastKeyState != 'D') { // Nếu nút vừa được nhấn
lastPressTime = millis(); // Ghi lại thời gian nhấn
}
// Tăng nhanh nếu giữ nút
if (millis() - lastPressTime < rapidDelayTime) {
// Không làm gì, chỉ tăng sau khi nhấn giữ
} else if (millis() - lastPressTime >= delayTime) { // Nếu đã qua thời gian nhấn chậm
setH--;
if (setH < 0) setH = 80;
lastPressTime = millis(); // Cập nhật thời gian
}
}
setHum();
EEPROM.write(6, setH);
break;
}
case 3:
{
int key = keyPad();
// Kiểm tra nút lên
if (key == 'U') {
if (lastKeyState != 'U') { // Nếu nút vừa được nhấn
lastPressTime = millis(); // Ghi lại thời gian nhấn
}
// Tăng nhanh nếu giữ nút
if (millis() - lastPressTime < rapidDelayTime) {
// Không làm gì, chỉ tăng sau khi nhấn giữ
} else if (millis() - lastPressTime >= delayTime) { // Nếu đã qua thời gian nhấn chậm
// Thay đổi giữa HOT và COOL
if (mode == HOT) {
mode = COOL;
} else {
mode = HOT;
}
lastPressTime = millis(); // Cập nhật thời gian
}
}
// Kiểm tra nút xuông
if (key == 'D') {
if (lastKeyState != 'D') { // Nếu nút vừa được nhấn
lastPressTime = millis(); // Ghi lại thời gian nhấn
}
// Tăng nhanh nếu giữ nút
if (millis() - lastPressTime < rapidDelayTime) {
// Không làm gì, chỉ tăng sau khi nhấn giữ
} else if (millis() - lastPressTime >= delayTime) { // Nếu đã qua thời gian nhấn chậm
if (mode == HOT) {
mode = COOL;
} else {
mode = HOT;
}
lastPressTime = millis(); // Cập nhật thời gian
}
}
setMode();
EEPROM.write(7, mode);
break;
}
}
break;
}
}
}
Video
Sự khác nhau giữa DHT11, DHT22 và DHT21 (AM2301)
Phạm vi và độ chính xác của phép đo nhiệt độ
- DHT11: -20 đến 60°C với độ chính xác ±2°C
- DHT21: -40 đến 80°C với độ chính xác ±0,3°C
- DHT22: -40 đến 80°C với độ chính xác ±0,5°C
Phạm vi và độ chính xác của phép đo độ ẩm
- DHT11: 5 đến 95% với độ chính xác ±5%
- DHT21: 0 đến 99% với độ chính xác ±2%
- DHT22: 0 đến 99% với độ chính xác ±2%
Nhận xét