Đọc DS18B20 trên ESP32 mà không treo vòng lặp chính
DS18B20 nói chuyện qua 1-Wire, và ở độ phân giải 12 bit nó cần 750 mili giây để chuyển đổi xong một lần đo. Viết theo kiểu sách giáo khoa thì vòng lặp chính đứng im đúng 750ms đó — trên một thiết bị còn phải nháy LED và trả lời nút bấm thì người dùng thấy ngay.
Cách sai mà ai cũng viết đầu tiên
import time, onewire, ds18x20
from machine import Pin
ds = ds18x20.DS18X20(onewire.OneWire(Pin(4)))
roms = ds.scan()
while True:
ds.convert_temp()
time.sleep_ms(750) # <-- cả con chip đứng ở đây
for rom in roms:
print(ds.read_temp(rom))750ms nhân với mỗi chu kỳ đo. Nếu đo mỗi giây thì ba phần tư thời gian sống của con chip là ngồi đợi một cảm biến.
Tách yêu cầu đo ra khỏi lúc đọc kết quả
1-Wire không bắt phải đợi. Ra lệnh chuyển đổi, đi làm việc khác, quay lại đọc khi đã đủ 750ms:
import time, onewire, ds18x20
from machine import Pin
ds = ds18x20.DS18X20(onewire.OneWire(Pin(4)))
roms = ds.scan()
deadline = 0
pending = False
while True:
now = time.ticks_ms()
if not pending:
ds.convert_temp()
deadline = time.ticks_add(now, 760) # 750 + biên an toàn
pending = True
elif time.ticks_diff(deadline, now) <= 0:
for rom in roms:
print(ds.read_temp(rom))
pending = False
nhap_nhay_led() # vòng lặp chính vẫn chạy`ticks_diff` chứ không phải phép trừ thường: bộ đếm của MicroPython tràn, và phép trừ trực tiếp sẽ cho một số âm khổng lồ đúng lúc tràn — lỗi chỉ xuất hiện sau vài chục ngày chạy liên tục, đúng loại lỗi khó nhất để bắt.
Hai thứ hay quên
Điện trở kéo lên 4.7kΩ giữa DQ và VCC. Thiếu nó mạch vẫn 'chạy' ở bàn nhưng sai số loạn khi dây dài ra.
Độ phân giải cấu hình được. Xuống 9 bit thì chỉ cần 94ms, đổi lại bước đo 0.5°C — với bài toán theo dõi nhiệt phòng thì đó là đánh đổi đáng.
Bình luận
Chưa có bình luận nào. Nếu bài này sai ở đâu, nói giúp.