Cảm biến nhiệt độ DHT11 rất hay được sử dụng trong các dự án nhỏ hoặc đồ án sinh viên, ưu điểm của nó là nhỏ gọn và rẻ. Nhưng độ chính xác thì không cao mấy. Trong bài này, chúng ta sẽ học cách đọc giá trị nhiệt độ, độ ẩm của DHT11 theo chuẩn Onewire.
Bài này nằm trong Serie Học STM32 từ A tới Z
Tổng quan về cảm biến nhiệt độ, độ ẩm DHT11
Cảm biến độ ẩm và nhiệt độ DHT11 Temperature Humidity Sensor là cảm biến rất thông dụng hiện nay vì chi phí rẻ và rất dễ lấy dữ liệu thông qua giao tiếp One wire (giao tiếp digital 1 dây truyền dữ liệu duy nhất). Bộ tiền xử lý tín hiệu tích hợp trong cảm biến giúp bạn có được dữ liệu chính xác mà không phải qua bất kỳ tính toán nào. So với cảm biến đời mới hơn là DHT22 thì DHT11 cho khoảng đo và độ chính xác kém hơn rất nhiều.
Thông tin kỹ thuật:
- Nguồn: 3 -> 5 VDC.
- Dòng sử dụng: 2.5mA max (khi truyền dữ liệu).
- Đo tốt ở độ ẩm 20 to 70%RH với sai số 5%.
- Đo tốt ở nhiệt độ 0 to 50°C sai số ±2°C.
- Tần số lấy mẫu tối đa 1Hz (1 giây 1 lần)
- Kích thước 15mm x 12mm x 5.5mm.
- 4 chân, khoảng cách chân 0.1”.
DHT11 sử dụng giao thức 1 Wire để giao tiếp với vi điều khiển, vậy trước hết hãy tìm hiểu 1 chút về chuẩn này nhé.
Giao tiếp One Wire (1 Wire) là gì ?
1-Wire là một hệ thống bus giao tiếp với thiết bị được thiết kế bởi Dallas Semiconductor Corp. 1-Wire hỗ trợ truyền dữ liệu tốc độ thấp (16.3 kbit/s), truyền tín hiệu, và nguồn nuôi qua cùng một chân tín hiệu đơn. 1-Wire cũng tương tự như I²C, nhưng với tốc độ truyền dữ liệu thấp và khoảng cách xa hơn. Nó thường được sử dụng để giao tiếp với các thiết bị nhỏ giá rẻ như nhiệt kế kĩ thuật số và công cụ đo thời tiết. Một mạng lưới của các thiết bị 1-Wire với một thiết bị điều khiển chính được gọi là một MicroLAN.
Theo Wikipedia
Mô hình kết nối và phương thức hoạt động của chuẩn 1 wire
Cũng giống như giao tiếp I2C, dây tín hiệu của 1 Wire phải được treo lên Vcc. Và cấu hình GPIO dạng Open Drain. Về nguyên lý, chuẩn Onewire có thể giao tiếp với nhiều thiết bị trong cùng một mạng theo sơ đồ sau:
Phương thức hoạt động của 1 Wire
Để 1 Wire hoạt động, sẽ có 4 phương thức được sử dụng đó là: Reset, Write bit 0, Write bit 1, Read.
Reset: Chuẩn bị giao tiếp . Master cấu hình chân data là Ouput, kéo xuống 0 một khoảng H rồi nhả ra để trở treo kéo lên mức 1. Sau đó cấu hình Master là chân Input, delay I (us) rồi đọc giá trị slave trả về . Nếu = 0 thì cho phép giao tiếp .Nếu data = 1 đường truyền lỗi hoặc slave đang bận. Tương tự như bạn đọc bit ACK trong giao tiếp I2C
Write 1 : truyền đi bit 1 : Master kéo xuống 0 một khoảng A(us) rồi về mức 1 khoảng B (us)
Write 0 : truyền đi bit 0 : Master kéo xuống 0 khoảng C rồi trả về 1 khoảng D (us)
Read : Đọc một Bit : Master kéo xuống 0 khoảng A rồi trả về 1. delay khoảng E(us) rồi đọc giá trị slave gửi về. Các bạn phải bắt được tín hiệu trong khoảng F. Sau khoảng đó sẽ Slave sẽ nhả chân F về trạng thái 1 (IDLE – Rảnh rỗi)
Tùy vào mỗi một dòng IC sẽ có bảng Timing phù hợp. Nhưng cũng có thể IC đó sử dụng thời gian theo tiêu chuẩn Standard…
Để giao tiếp 1 Wire chính xác, chúng ta cần tạo ra các delay chính xác tới micro giây (us).
Phương thức giao tiếp của DHT11
Chi tiết các bạn đọc tại Datasheet: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf
Khung truyền – gói tin
Một gói tin (packet) của DHT 11 bao gồm 40bit, tương ứng với 5byte. Trong đó:
- Byte 1: giá trị phần nguyên của độ ẩm (RH%)
- Byte 2: giá trị phần thập phân của độ ẩm (RH%)
- Byte 3: giá trị phần nguyên của nhiệt độ (TC)
- Byte 4 : giá trị phần thập phân của nhiệt độ (TC)
- Byte 5 : kiểm tra tổng ( Check Sum) là tổng của 4 byte phía trước cộng lại
DHT11 sẽ gửi MSB (bit có trọng số lớn nhất ) tức là byte 1 sẽ được gửi đầu tiên, cuối cùng là byte 5.
Chu trình nhận dữ liệu
Trạng thái bình thường DHT11 sẽ ở trạng thái tiêu thụ năng lượng thấp. Khi có tín hiệu Reset, chúng sẽ được wakeup sau đó DHT11 phản hổi bằng cách kéo chân Data xuống 1 khoảng thời gian, rồi nhả ra.
Sau đó 5byte dữ liệu sẽ được gửi đi, MCU sẽ đọc 5 byte đó. Kết thúc DHT11 nhả chân Data về lại mức 1 và trở về trạng thái tiết kiệm năng lượng. Nó sẽ được đánh thức nếu có 1 tín hiệu reset.
Cách reset hay start
Để xuất tín hiệu reset hay start cho DHT11, chúng ta sẽ kéo chân Data xuống 0 ít nhất là 18ms, sau đó nhả ra 20-40us để chờ DHT11 phản hồi. Nếu DHT11 phản hồi, nó sẽ kéo chân Data xuống 0 khoảng 80us, sau đó nhả về 1 80us.
Tiếp theo sẽ là 80bit (5byte) dữ liệu ngay sau đó
Cách nhận biết bit 0 và 1 trong giá trị trả về của DHT11
Với bit 0 DHT11 sẽ kéo chân Data xuống 0 50us và trả về 1 26-28us
Với bit 1 DHT11 sẽ kéo chân Data xuống 0 50us và trả về 1 70us
Thực tế, chúng ta chỉ cần đo thời gian Data ở mức 1 là 28us hay 70us là đã có thể phân biệt được rồi.
Lập trình STM32 giao tiếp 1 wire với DHT11
Khởi tạo trong CubeMX
Mở cubemx chọn chip stm32f103c8, trong tab sys chọn Debug – serial wire.
Chọn dao động cho mạch là thạch anh ngoài.
Trong tab Timer chọn Timer 4 – Internal Clock và Setup tham số như hình. Như vậy mỗi lần đếm của Timer 4 sẽ cách nhau 1us. Điều này sẽ giúp chúng ta tạo delayus. (Trễ mirco giây)
Chọn chân giao tiếp với DHT11 là PB14 output.
Trong Clock tree chúng ta sẽ cho STM32 chạy ở tốc độ 72Mhz.
Thêm thư viện và lập trình
Download và thêm 2 thư viện DHT11 và Timer_delay vào project. Làm theo link: Hướng dẫn download tài liệu STM32
Tạo một biến struct DHT11 có tên là DHT1. Bạn có thể khởi tạo nhiều con DHT11 khác nhau trong cùng một project nhé.
Khởi tạo chân và timer cho DHT11 bằng hàm Init.
Đọc giá trị nhiệt độ, độ ẩm bằng hàm ReadTempHum
Kết quả trả về sẽ nằm trong Struct DHT1 nhé. Các bạn vào Debug, nhấn Add to watch 1 biến DHT1. Sau đó view nhé.
Lưu ý: Chân DATA của DHT11 phải có trở treo 4k7 hoặc 10k nối lên VCC nhé các bạn
Giải thích code trong thư viện DHT11
Hàm DHT_Start sẽ ghi giá trị 0 40us vào chân Data, sau đó đổi từ Output sang Input. Rồi chờ trong 40us, sau đó đọc giá trị từ Data. Nếu chân Data phản hổi lại sẽ response 0 và 1 tương ứng với không phản hồi và phản hồi
Hàm Read sẽ set chân Data về In, sau đó kiểm tra chân Data có được kéo về 0 không? Nếu được kéo về, delay 40us. Khi đó nếu bit được gửi là 1 thì data vẫn sẽ giữ ở mức 1. Nếu là 0 thì đã bị kéo xuống mức 0 rồi.
Ghi giá trị vào biến Value. Chu trình này lặp lại 8lần để read 1 byte.
Hàm Init sẽ truyền vào Timer dùng làm delay, các chân IO, kiểu DHT. Các giá trị này đã được khai báo tại Struct DHT_Name trong file.h
Cuối cùng hàm ReadTempHum. Sẽ làm đúng theo chu trình đã nói phía trước. Start->read các byte. Sau đó, tính toán để trả về 2 giá trị float Temp và Hum.
Kết
Lập trình STM32 với DHT11 không quá phức tap. Qua bài này các bạn có thể hình dung ra phần nào, cách chúng ta lập trình dựa trên Timing diagram, cách đọc dữ liệu 1 wire….
Nếu thấy bài viết này hay, hãy chia sẻ tới những người bạn học hay đồng nghiệp của mình. Và nếu thắc mắc điều gì, hãy để lại bình luận nhé
Và cùng gia nhập những người nghiện lập trình tại đây nhé: Hội anh em nghiện lập trình
ad ơi e muốn hiển rhuj giá trị lên LCD thì làm như nào ạ
chả hiểu sao làm được trang web như này khai báo timer2 , code thì để là timer 4 debug thì chắc la ko chạy nên giá trị ms bằng 0
Ok bạn, lỗi typing thôi mình sửa lại rồi nhé
Chào anh,
Em có sử dụng thư viện DHT11 của anh để đọc cảm biến nhiệt độ và gửi lên LCD (Thư viện LCD em cũng dùng của anh).
Nhưng khi lần đầu build code (hoặc rebuild) sẽ xuất hiện cảnh báo:
(44): warning: #188-D: enumerated type mixed with another type
HAL_GPIO_WritePin(DHT->PORT, DHT->Pin, Value);
(44): warning: #188-D: enumerated type mixed with another type
HAL_GPIO_WritePin(DHT->PORT, DHT->Pin, Value);
(115): warning: #550-D: variable “Temp” was set but never used
uint16_t Temp, Humi, SUM = 0;
(115): warning: #550-D: variable “Humi” was set but never used
2 biến nhiệt độ và độ ẩm không được sử dụng.
Giá trị nhiệt độ và độ ẩm không thể đọc về được.
Em phát hiện lỗi xảy ra khi dùng CubeMX cấu hình GPIO cho LCD và DHT11 cùng 1 project thì sẽ xuất hiện lỗi này.
Anh có gặp trường hợp này chưa ạ, anh có chia sẽ giúp em không ạ?
Em cảm ơn.
enumerated type mixed with another type -> Do truyền vào giá trị không thuộc giá trị định nghĩa (Reset là 0 và set là 1) nên báo vậy. thực chất ko vấn đề gì
(115): warning: #550-D: variable “Humi” was set but never used => Cái này là do e khai nhưng ko sử dụng thôi nhé
Anh ơi, sao em làm y chan hết, tới lúc cuối hiển thị tại của sổ watch 1 toàn là ra giá trị 0 không vậy anh, chẳng đo được j cả,với bên trên em coi ảnh của anh cũng vậy! làm sao để hiển thị giá trị á anh
Mong anh giúp em với,
Em đã nối trở cho DHT11 chưa
anh cho em hỏi là em làm i chang thì temp nó ra 307.564 còn humi là 4685 sao số nó ra lớn z ạ