Lập trình STM32 với DHT11 theo chuẩn 1 Wire

stm32 dht11

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 lắm. Trong bài này, chúng ta sẽ học cách đọc giá trị nhiệt độ, độ ẩm của DHT11 qua giao tiếp 1 dây (One Wire).

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 1 dây (chỉ dùng 1 dây digital duy nhất để truyền dữ liệu). Bộ tiền xử lý tín hiệu tích hợp trong cảm biến giúp bạn có được giá trị đo trực tiếp 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 có khoảng đo hẹp hơn và độ chính xác kém hơn khá nhiều.

DHT11–Temperature Sensor Pinout

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 – 80%RH với sai số ±5%.
  • Đo tốt ở nhiệt độ 0 – 50°C với 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 tiếp 1 dây để 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 1 Wire nhé.

Giao tiếp One Wire (1 Wire) là gì ?

1-Wire là một hệ thống bus giao tiếp đượ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à cả nguồn nuôi qua cùng một dây tín hiệu duy nhất. 1-Wire cũng tương tự như I²C, nhưng với tốc độ truyền dữ liệu thấp hơn 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 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 bằng điện trở kéo lên, và GPIO được cấu hình dạng Open Drain. Về nguyên lý, chuẩn 1 Wire có thể giao tiếp với nhiều thiết bị trong cùng một mạng theo sơ đồ sau:

1 wire topo

Phương thức hoạt động của 1 Wire

Để 1 Wire hoạt động, có 4 thao tác được sử dụng: Reset, Write bit 0, Write bit 1, Read.

Reset: chuẩn bị giao tiếp. Master cấu hình chân Data là Output, kéo xuống 0 một khoảng H rồi nhả ra để điện trở treo kéo lên mức 1. Sau đó Master chuyển chân sang Input, delay I (us) rồi đọc giá trị Slave trả về. Nếu bằng 0 (Slave kéo xuống – presence pulse) thì cho phép giao tiếp. Nếu bằng 1 thì đường truyền lỗi hoặc không có Slave. 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 trả về mức 1 một khoảng B (us).

Write 0: truyền đi bit 0: Master kéo xuống 0 một khoảng C rồi trả về 1 một khoảng D (us).

Read: đọc một bit: Master kéo xuống 0 một khoảng A rồi nhả ra, delay khoảng E (us) rồi đọc giá trị Slave gửi về. Các bạn phải đọc được tín hiệu trong khoảng F, sau khoảng đó Slave sẽ nhả chân về trạng thái 1 (IDLE – rảnh rỗi).

1 wire timing

Tùy mỗi dòng IC sẽ có bảng Timing phù hợp, hoặc IC đó sử dụng thời gian theo tiêu chuẩn (Standard/Overdrive)…

1 wire data timing

Để 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).

Lưu ý: DHT11 chỉ “mượn” ý tưởng 1 dây, chứ không dùng đúng chuẩn 1-Wire của Dallas (như cảm biến DS18B20). DHT11 không có mã ROM ID riêng, nên mỗi dây Data chỉ nối được đúng 1 con DHT11, muốn dùng nhiều cảm biến thì phải dùng nhiều chân GPIO. Thư viện 1-Wire cho DS18B20 cũng không đọc được DHT11 và ngược lại.

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 DHT11 bao gồm 40 bit, tương ứng với 5 byte. 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 độ (°C)
  • Byte 4: giá trị phần thập phân của nhiệt độ (°C)
  • Byte 5: tổng kiểm tra (Checksum), bằng 8 bit thấp của tổng 4 byte phía trước

DHT11 gửi bit có trọng số lớn nhất (MSB) trước, và byte 1 được gửi đầu tiên, cuối cùng là byte 5.

dht11 data packet
Gói tin của DHT11

Chu trình nhận dữ liệu

Bình thường DHT11 ở trạng thái tiêu thụ năng lượng thấp. Khi có tín hiệu Start (Reset), nó sẽ thức dậy, 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 đó 5 byte 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 cho tới khi có tín hiệu Start tiếp theo.

dht 11 process
Chu trình giao tiếp với DHT11

Cách reset hay start

Để xuất tín hiệu Start cho DHT11, chúng ta kéo chân Data xuống 0 ít nhất 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 khoảng 80us.

Tiếp theo sẽ là 40 bit (5 byte) dữ liệu ngay sau đó.

dht 11 start

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 khoảng 50us và trả về 1 khoảng 26 – 28us.

Với bit 1, DHT11 sẽ kéo chân Data xuống 0 khoảng 50us và trả về 1 khoảng 70us.

Thực tế, chúng ta chỉ cần đo thời gian Data ở mức 1 là khoảng 28us hay 70us là đã có thể phân biệt được rồi. Giống như mã Morse vậy: tín hiệu ngắn là bit 0, tín hiệu dài là bit 1.

dht11 write 0
DHT11 bit 0
dht11 write 1
DHT11 bit 1

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.

dh11

Chọn dao động cho mạch là thạch anh ngoài.

dh11 rcc

Trong tab Timer chọn Timer 4 – Internal Clock và setup tham số như hình (với clock Timer 72MHz thì Prescaler = 72 – 1). Như vậy mỗi lần đếm của Timer 4 sẽ cách nhau 1us, giúp chúng ta tạo hàm delay micro giây.

dh11 tim

Chọn chân giao tiếp với DHT11 là PB14, chế độ Output.

dh11 gpio

Trong Clock tree chúng ta sẽ cho STM32 chạy ở tốc độ 72MHz.

dh11 clock

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

dh11 define

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 (mỗi con 1 chân) trong cùng một project nhé.

dh11 code

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. Các bạn vào Debug, chuột phải vào biến DHT1 chọn Add to Watch 1 để xem nhé.

Kết nối phần cứng: chân DATA của DHT11 nối với PB14, VCC nối 3.3V, GND nối GND.

Lưu ý: Chân DATA của DHT11 phải có điện trở kéo lên 4.7kΩ hoặc 10kΩ nối lên VCC (module DHT11 3 chân thường đã hàn sẵn). Ngoài ra không đọc DHT11 nhanh hơn 1 lần/giây, và sau khi cấp nguồn nên chờ khoảng 1 giây rồi mới đọc lần đầu, nếu không cảm biến sẽ không phản hồi hoặc trả về giá trị cũ.

dht11 ket qua

Giải thích code trong thư viện DHT11

Hàm DHT_Start sẽ kéo chân Data xuống 0 trong khoảng thời gian Start (datasheet yêu cầu ít nhất 18ms), sau đó đổi chân từ Output sang Input, chờ khoảng 40us rồi đọc giá trị chân Data. Hàm trả về 0 nếu DHT11 không phản hồi và 1 nếu DHT11 có phản hồi.

dh11 code 3

Hàm Read sẽ đặt chân Data về Input, chờ chân Data lên mức 1 (hết 50us mức thấp mở đầu mỗi bit), rồi delay khoảng 40us. Khi đó nếu bit được gửi là 1 thì Data vẫn đang ở mức 1 (vì bit 1 giữ mức cao 70us), còn nếu là bit 0 thì Data đã bị kéo xuống 0 rồi (vì bit 0 chỉ giữ mức cao 26 – 28us).

Ghi giá trị vào biến Value. Chu trình này lặp lại 8 lần để đọc 1 byte.

dh11 code 4

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
dh11 code 5

Cuối cùng là hàm ReadTempHum, làm đúng theo chu trình đã nói phía trước: Start -> đọc 5 byte, sau đó tính toán để trả về 2 giá trị float Temp và Hum.

dh11 code 6

Kết

Lập trình STM32 với DHT11 không quá phức tạp. 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 qua 1 dây…

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

5/5 - (3 bình chọn)

8 những suy nghĩ trên “Lập trình STM32 với DHT11 theo chuẩn 1 Wire”

  1. nam nói:

    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

  2. Linh nói:

    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.

    • Khuê Nguyễn nói:

      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é

  3. trabc nói:

    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,

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *