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 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.

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 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:

1 wire topo

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)

1 wire timing

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…

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

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.

dht11 data packet
Gói tin của DHT11

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.

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

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 đó

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 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.

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

dh11 tim

Chọn chân giao tiếp với DHT11 là PB14 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 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 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

dht11 ket qua

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

dh11 code 3

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.

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 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.

dh11 code 6

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

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,

Trả lời

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 *