Raspberry Pi thiếu analog input. Điều này đặt nó vào thế bất lợi hơn so với các bo mạch dựa trên vi điều khiển như Arduino.
Thế nhưng, đừng tuyệt vọng, bạn còn có nhiều lựa chọn đáng cân nhắc khác. Bạn có thể thiết lập và chạy với Raspberry Pi và ADC bên ngoài.
Tại sao cần thêm input?
Thế giới thực có rất nhiều hiện tượng mà nếu bạn có mạch điện phù hợp, bạn có thể dễ dàng mô tả bằng điện áp. Đưa các điện áp đó sang dạng kỹ thuật số và bạn có thể ghi lại chúng, thao tác và sử dụng chúng để điều khiển các thông số và thiết bị khác.
Bạn có thể đang muốn theo dõi độ ẩm của đất, nhiệt độ của nhà kính hoặc trọng lượng của chuột hamster. Bạn có thể đang tìm cách thêm bộ điều khiển âm lượng cho Pi của mình, xây dựng toàn bộ dãy bộ chỉnh âm lượng hoặc thiết kế cần điều khiển từ đầu… Các khả năng gần như vô hạn.
Các lựa chọn ADC
Vậy ADC nào phù hợp nhất với người mới bắt đầu?
Chip MCP3004 là một trong số những lựa chọn phổ biến và đơn giản nhất từ Microchip. Bạn sẽ có 4 hoặc 8 kênh 10 bit, có thể đọc tới 200 kSPS. Mặt khác, có các thiết bị ADS111x của Texas Instruments, đọc 16 bit ở 860 SPS. Vì vậy, có sự cân bằng giữa tốc độ và độ chính xác (và tất nhiên bao gồm cả giá).
Nhiều bộ vi điều khiển đi kèm với ADC sẵn có. ATMega mà bạn tìm thấy trên Arduino trung bình sẽ cung cấp một số kênh 10 bit. Đây là điều cho phép Arduino cung cấp đầu vào tương tự mà Raspberry Pi không thể. Nếu bạn đã có Arduino tham gia vào quá trình thiết lập và 10 bit là đủ độ trung thực thì đây thực sự có thể là cách dễ nhất để thực hiện.
Programmable Gain Amplifier là gì?
Con chip này đi kèm với một số tính năng thú vị, bao gồm Programmable Gain Amplifier (PGA). Nó sẽ cho phép bạn đặt phạm vi giá trị mong muốn theo thông số kỹ thuật, giảm xuống một phần vôn. Với số lượng giá trị mà 16 bit có thể biểu thị, điều này cho phép bạn phát hiện sự khác biệt chỉ vài microvolt.
Ưu điểm ở đây là bạn có thể thay đổi mức tăng giữa chừng của chương trình. Các chip khác, như MCP3004 lại đi kèm với một pin phụ để bạn có thể cung cấp điện áp tham chiếu.
Multiplexing là gì?
Một multiplexer (hay mux) là một công tắc cho phép bạn đọc nhiều đầu vào bằng một ADC duy nhất. Nếu chip ADC của bạn có nhiều pin đầu vào thì sẽ có một số quá trình ghép kênh bên trong đang diễn ra. Mux của ADS1115 cho phép bốn đầu vào mà bạn có thể chọn chúng thông qua các thanh ghi nội bộ.
Làm việc với các register
ADS1115 cung cấp các tùy chọn này cùng một số tùy chọn khác. Bạn có thể xử lý bộ ghép kênh, điều chỉnh mức tăng, kích hoạt bộ so sánh tích hợp, thay đổi tốc độ lấy mẫu và đặt thiết bị vào chế độ ngủ năng lượng thấp, tất cả chỉ bằng cách lật một vài công tắc.
Những switch hay nút kích hoạt ở đâu? Chúng nằm trong gói, ở dạng các bit bộ nhớ rất nhỏ gọi là các thanh ghi. Để kích hoạt một tính năng nhất định, bạn chỉ cần đặt bit liên quan thành 1, không phải bằng 0.
Hãy nhìn vào datasheet ADS111x, bạn sẽ tìm thấy những mô hình này đi kèm với 4 thanh ghi, bao gồm các thanh ghi cấu hình, chi phối hoạt động của thiết bị.
Ví dụ: bit 14 đến 12 điều khiển bộ ghép kênh. Sử dụng ba bit này, bạn có thể chọn từ tám cấu hình. Số bạn muốn ở đây là “100”, sẽ tạo ra sự khác biệt giữa số 0 đầu vào và mặt đất. Mặt khác, các bit từ 7 đến 5 chi phối tốc độ lấy mẫu. Nếu bạn muốn tối đa 860 mẫu mỗi giây, bạn có thể đặt các mẫu này thành “111”.
Khi bạn biết nên đặt tùy chọn nào, bạn sẽ có hai byte để gửi đến ADC. Nếu sau này bạn muốn đặt một bit ở đây hoặc ở đâu đó, thì bạn có thể xử lý chúng riêng lẻ bằng cách sử dụng toán tử bitwise.
Đây là nơi nó có thể gây nhầm lẫn. Trong trường hợp này, nhị phân không đại diện cho một giá trị mà là giá trị của các công tắc riêng lẻ. Bạn có thể biểu thị các biến này dưới dạng một số lớn, ở dạng thập phân hoặc thập lục phân. Nhưng bạn nên dùng phiên bản nhị phân, dễ đọc hơn.
Kết nối dây
Bạn có thể cắm thẳng thiết bị này vào breadboard. Đầu vào điện áp dương sẽ chấp nhận ở bất kỳ đâu trong khoảng từ 2 đến 5,5v, điều đó có nghĩa là đường 3,3v trên Raspberry Pi sẽ hoạt động tốt.
Đấu dây đầu vào SDA và SCL với các đối tác trên RPi và thực hiện những điều tương tự trên mặt đất và 3,3v. Lấy một chiết áp giữa đường dây nối đất và điện áp, rồi đặt dây dẫn giữa vào đầu vào đầu tiên của ADC. Đó là tất cả những gì bạn cần để bắt đầu!
Xử lý I2C
Các ADC khác nhau hoạt động thông qua các giao thức khác nhau. Trong trường hợp ADS1115, chúng ta sẽ sử dụng I2C.
Ví dụ sau sẽ tương tác với ADC bằng Python. Nhưng trước khi làm điều đó, bạn sẽ cần phải thiết lập nó. Các phiên bản gần đây của Raspberry Pi OS đã thực hiện việc này rất đơn giản. Tới Preferences > Raspberry Pi Configuration. Sau đó, từ tab Interfaces, bật I2C.
Để kiểm tra mọi thứ có hoạt động, mở terminal và chạy:
sudo i2cdetect -y 1
Lệnh này sẽ xuất ra một grid. Giả sử mọi thứ đều hoạt động và bạn đã nối dây chính xác, bạn sẽ thấy một giá trị mới xuất hiện trong khung kẻ ô. Đây là địa chỉ của ADC. Hãy nhớ rằng đây là giá trị thập lục phân, vì vậy bạn cần thêm “0x” vào tiền tố khi sử dụng nó trong mã bên dưới. Ở đây là 0x48:
Sau khi có địa chỉ, bạn có thể sử dụng thư viện SMBus để gửi lệnh I2C. Bạn sẽ xử lý hai phương pháp ở đây. Đầu tiên là write_word_data(), chấp nhận ba đối số: địa chỉ thiết bị, sổ đăng ký bạn đang ghi và giá trị bạn muốn ghi.
Thứ hai là read_word_data(), chỉ chấp nhận địa chỉ thiết bị và thanh ghi. ADC sẽ liên tục đọc điện áp và lưu kết quả vào thanh ghi chuyển đổi. Với phương pháp này, bạn có thể truy xuất nội dung của thanh ghi đó.
Bạn có thể làm đẹp kết quả một chút rồi in nó. Trước khi bạn quay lại phần đầu của vòng lặp, hãy đưa ra một độ trễ ngắn. Điều này sẽ đảm bảo bạn không bị dữ liệu làm choáng ngợp.
from smbus import SMBus
import time
addr = 0x48
bus = SMBus(1)
# Thiết lập các thanh ghi để đọc
CONFIGREG = 1
CONVERSIONREG = 0
# Đặt thanh ghi địa chỉ để trỏ tới register config
# viết thanh ghi cấu hình
bus.write_word_data(addr, CONFIGREG, (0b00000100 << 8 | 0b10000010))
# xác định đỉnh của phạm vi
TOP = 26300
while True:
# đọc thanh ghi
b = bus.read_word_data(addr, CONVERSIONREG)
# hoán đổi hai byte
b = ((b & 0xFF) << 8) | ((b >> 8) & 0xFF)
# trừ một nửa phạm vi để đặt tiếp đất về 0
b -= 0x8000
# Chia kết quả theo phạm vi để có giá trị nằm giữa 0 và 1
b /= TOP
# giới hạn ở 1
b = min(b, 1)
# phía dưới cùng là 0
b = max(b, 0)
# hai vị trí thập phân
b = round(b, 2)
print(b)
time.sleep(.01)
Bạn sắp hoàn thành rồi. Ánh xạ phạm vi giá trị bạn đang nhận được tới giá trị bạn thích, sau đó cắt bớt số vị trí thập phân mong muốn. Bạn có thể điều chỉnh chức năng in để chỉ in một giá trị mới khi nó khác với giá trị cuối cùng.
Xử lý tiếng ồn
Đây là nhược điểm cố hữu của việc sử dụng 16 bit thay vì chỉ 10 bit: một chút nhiễu sẽ dễ nhận biết hơn.
Bằng cách nối đầu vào liền kề (đầu vào 1) với mặt đất và chuyển chế độ sao cho bạn có thể so sánh đầu vào một và hai, bạn có thể nhận được kết quả ổn định hơn nhiều. Bạn cũng có thể đổi những dây cáp nối có khả năng thu tiếng ồn đó bằng những dây cáp nhỏ và thêm một vài tụ điện khi sử dụng nó. Giá trị chiết áp của bạn cũng có thể tạo ra sự khác biệt.
Ngoài ra, bạn còn có các tùy chọn phần mềm. Bạn có thể tạo mức trung bình luân phiên, hoặc đơn giản là bỏ qua những thay đổi nhỏ. Nhược điểm là mã bổ sung sẽ gây ra chi phí tính toán. Nếu bạn đang viết các câu lệnh có điều kiện bằng ngôn ngữ cấp cao như Python và lấy hàng nghìn mẫu mỗi giây, những chi phí này sẽ tăng lên nhanh chóng.
Thế là xong! Hi vọng bài viết hữu ích với các bạn!