Khái niệm cơ bản về chuẩn giao tiếp I2C trong Arduino
Ngoài các chuẩn giao tiếp như SPI hay UART, thì giao tiếp I2C được sử dụng rộng rãi trong các ứng dụng của Arduino. Có thể kể đến hàng loạt thiết bị được tiếp hợp chuẩn giao tiếp này như: màn hình OLED 0.96, màn hình LCD, cảm biến áp xuất khí quyển, hoặc module con quay hồi chuyển gia tốc kế…
Giới thiệu về chuẩn giao tiếp I2C
Giao thức I2C (Inter-Integrated Circuit) là một giao thức truyền thông nối tiếp được phát triển bởi Philips (hiện tại là NXP Semiconductors) vào những năm 1980. Nó cho phép truyền dữ liệu giữa các thiết bị điện tử như vi điều khiển, cảm biến,… thông qua hai dây SDA và SCL.
Chuẩn giao tiếp I2C được xây dựng trên nguyên tắc Master-Slave, trong đó một Master điều khiển quá trình truyền và nhận dữ liệu từ các Slave. Một Master có thể kết nối với nhiều Slave, và mỗi Slave được xác định bằng một địa chỉ duy nhất.
SDA và SCL của giao thức I2C sử dụng cơ chế truyền thông đồng bộ, trong đó tín hiệu (SCL) được Master điều khiển. Dữ liệu (bit) được truyền từng bit một qua đường SDA.
Xem thêm: Chuẩn giao tiếp SPI là gì? Giao thức SPI trong Arduino
Giao thức I2C hoạt động như thế nào?
Với I2C, dữ liệu được truyền dưới dạng tin nhắn và được chia thành các khung dữ liệu. Mỗi tin nhắn bao gồm một khung địa chỉ chứa địa chỉ nhị phân của thiết bị Slave và một hoặc nhiều khung dữ liệu chứa dữ liệu được truyền. Tin nhắn cũng bao gồm các điều kiện bắt đầu và dừng, các bit đọc/ghi và các bit ACK/NACK giữa các khung dữ liệu:
Điều kiện bắt đầu: Dây SDA chuyển từ mức điện áp cao xuống mức điện áp thấp trước khi dây SCL chuyển từ mức cao xuống mức thấp.
Điều kiện dừng: Dây SDA chuyển từ mức điện áp thấp lên mức điện áp cao sau khi dây SCL chuyển từ mức thấp lên mức cao.
Khung địa chỉ: Đây là một chuỗi duy nhất gồm 7 hoặc 10 bit để xác định địa chỉ của thiết bị Slave mà Master muốn truyền thông.
Read/Write Bit: Đây là một bit đơn xác định liệu Master đang gửi dữ liệu đến Slave (mức điện áp thấp) hay yêu cầu dữ liệu từ Slave (mức điện áp cao).
ACK/NACK Bit: Mỗi khung dữ liệu trong một tin nhắn được theo sau bởi một bit ACK/NACK. Nếu khung địa chỉ hoặc khung dữ liệu được Slave nhận thành công, một bit ACK sẽ được trả lại cho Master từ Slave để xác nhận.
Giao tiếp I2C arduino sử dụng các tín hiệu điện áp logic để đồng bộ hoạt động giữa các thiết bị trong mạng I2C và cung cấp một phương pháp đơn giản và hiệu quả để truyền thông giữa chủ (Master) và các thiết bị phụ (Slave).
Địa chỉ
Giao thức I2C không sử dụng các dòng chọn thiết bị như giao tiếp SPI, do đó nó cần một phương pháp khác để cho thiết bị nhận (Slave) biết rằng dữ liệu đang được gửi tới nó mà không phải là một thiết bị khác (Slave). I2C thực hiện điều này bằng cách sử dụng khung địa chỉ. Khung địa chỉ luôn là khung đầu tiên sau bit bắt đầu trong mỗi tin nhắn I2C.
Trong giao tiếp I2C arduino, thiết bị chủ (Master) gửi địa chỉ của thiết bị nhận (Slave) mà nó muốn truyền thông tin tới. Tất cả các thiết bị nhận kết nối với thiết bị chủ sau đó so sánh địa chỉ được gửi từ thiết bị chủ với địa chỉ của chính nó. Nếu địa chỉ khớp, thiết bị nhận (Slave) sẽ gửi bit ACK (mức điện áp thấp) trở lại cho thiết bị chủ. Nếu địa chỉ không khớp, thiết bị nhận sẽ không thực hiện bất kỳ hành động nào và đường truyền dữ liệu (SDA) sẽ tiếp tục ở mức điện áp cao.
Đọc/Ghi Bit
Khi thiết bị chủ (Master) muốn đọc dữ liệu từ thiết bị Slave, nó sẽ gửi các bit yêu cầu đọc (Read) liên tiếp qua đường SDA. Sau mỗi bit yêu cầu đọc, thiết bị Slave sẽ gửi một bit dữ liệu trong khung dữ liệu và thiết bị Master sẽ gửi một bit ACK để xác nhận việc nhận dữ liệu.
Quá trình gửi và nhận các bit dữ liệu trong I2C được điều khiển bởi tín hiệu SCL được điều chỉnh bởi thiết bị Master. Các bit dữ liệu được truyền và nhận theo trình tự từ bit MSB (Most Significant Bit) đến bit LSB (Least Significant Bit).
Khung dữ liệu
Mỗi khung dữ liệu bao gồm 8 bit dữ liệu và một bit ACK/NACK (ACKnowledge/Not ACKnowledge) để xác nhận việc nhận dữ liệu. Bit ACK/NACK được gửi bởi thiết bị nhận sau khi nhận mỗi khung dữ liệu. Nếu thiết bị nhận nhận dữ liệu đúng, nó sẽ gửi bit ACK trở lại cho thiết bị truyền. Ngược lại, nếu có lỗi xảy ra, nó sẽ gửi bit NACK để yêu cầu truyền lại dữ liệu.
Các khung dữ liệu được gửi từ thiết bị Master đến thiết bị Slave hoặc ngược lại. Mỗi khung dữ liệu được gắn kết sau khung địa chỉ, xác định thiết bị Slave mà thiết bị Master muốn truyền dữ liệu tới.
Sau khi các khung dữ liệu được truyền hoặc nhận, một điều kiện dừng được tạo ra bằng cách thiết bị Master hoặc Slave chuyển đường dữ liệu (SDA) từ mức điện áp cao lên mức điện áp thấp trước khi SCL từ mức thấp lên mức cao.
Xem ngay: Giao tiếp Arduino với máy tính thông qua Serial (UART) (Cập nhật 2023)
Các bước truyền dữ liệu trong giao tiếp I2C
Thiết bị Master tạo điều kiện bắt đầu bằng cách chuyển đường dữ liệu (SDA) từ mức điện áp cao xuống mức điện áp thấp trong khi đường SCL đang ở mức điện áp cao.
Sau khi bắt đầu, thiết bị Master gửi địa chỉ của thiết bị Slave mà nó muốn truyền dữ liệu đến. Địa chỉ này được gửi dưới dạng 7 hoặc 10 bit và đi kèm với một bit đọc/ghi (R/W) để xác định hoạt động là ghi (0) hay đọc (1).
Sau khi gửi địa chỉ, thiết bị nhận (Slave) kiểm tra địa chỉ được gửi và gửi lại một bit ACK (mức điện áp thấp) nếu địa chỉ khớp. Nếu địa chỉ không khớp, thiết bị nhận sẽ không gửi bất kỳ gì và đường dữ liệu (SDA) sẽ vẫn ở mức điện áp cao.
Master gửi hoặc nhận khung dữ liệu
Sau khi xác nhận địa chỉ, thiết bị Master có thể truyền hoặc nhận dữ liệu từ thiết bị nhận. Dữ liệu được truyền theo từng byte (8 bit) và sau mỗi byte, thiết bị nhận sẽ gửi một bit ACK (mức điện áp thấp) nếu dữ liệu được nhận thành công.
Khi quá trình truyền dữ liệu hoàn thành, thiết bị chủ tạo điều kiện dừng bằng cách chuyển đường dữ liệu (SDA) từ mức điện áp thấp lên mức điện áp cao trong khi đường SCL đang ở mức điện áp cao.
Một Master với nhiều Slave
I2C cho phép một master điều khiển nhiều slave bằng cách sử dụng địa chỉ. Với địa chỉ 7 bit, có thể sử dụng tối đa 128 (2^7) địa chỉ khác nhau. Mặc dù sử dụng địa chỉ 10 bit không phổ biến, nhưng nó cung cấp 1.024 (2^10) địa chỉ khác nhau. Để kết nối nhiều slave với một master, có thể sử dụng đường dẫn như sau, và kết nối các đường SDA và SCL với Vcc thông qua điện trở kéo lên 4,7K Ohm:
Cấu trúc trên giúp đảm bảo rằng đường SDA và SCL luôn có mức điện áp cao khi không có truyền thông I2C xảy ra. Điều này đảm bảo sự ổn định của mạng I2C và tránh các xung đột trong quá trình truyền dữ liệu.
Nhiều Master với nhiều Slave
Giao tiếp I2C cũng hỗ trợ kết nối nhiều master với nhiều slave trong cùng một mạng. Trong trường hợp này, cần sử dụng các cơ chế chia sẻ tài nguyên để tránh xung đột và đảm bảo quyền truy cập hợp lý.
Mỗi master trong mạng I2C phải tuân thủ quy tắc chia sẻ tài nguyên, chẳng hạn như sử dụng giao thức trao đổi tín hiệu như “Bus Arbitration” để xác định master nào có quyền truy cập vào mạng. Master giành được quyền truy cập sẽ trở thành “bus master” và điều khiển quá trình truyền thông.
Các slave trong mạng I2C phải tuân thủ lệnh điều khiển từ master và phản hồi đúng các yêu cầu. Mỗi slave có địa chỉ duy nhất để master có thể xác định và gửi yêu cầu đến slave cụ thể.
Khi có nhiều master trong mạng I2C, cần thực hiện cơ chế chia sẻ tài nguyên và kiểm soát quyền truy cập để tránh xung đột và đảm bảo sự ổn định của giao tiếp.
Ưu và nhược điểm của giao thức I2C
Ưu điểm của giao tiếp I2C:
- Giao tiếp I2C chỉ sử dụng hai dây, SDA và SCL, giúp tiết kiệm số lượng chân kết nối
- I2C cho phép kết nối nhiều thiết bị trong một mạng duy nhất, bằng cách sử dụng các địa chỉ duy nhất cho từng thiết bị.
- Giao thức I2C hỗ trợ nhiều tốc độ truyền thông, cho phép điều chỉnh tốc độ truyền dữ liệu phù hợp với yêu cầu của ứng dụng.
- I2C sử dụng các quy tắc truyền thông điều khiển và kiểm soát xung đột, giúp đảm bảo tính tin cậy và chính xác của dữ liệu truyền qua mạng.
Nhược điểm của giao tiếp I2C:
- So với các giao thức truyền thông khác như SPI hay UART, I2C có tốc độ truyền thông thấp hơn, điều này có thể ảnh hưởng đến hiệu suất chuyển dữ liệu trong các ứng dụng yêu cầu tốc độ cao.
- Do sử dụng dây truyền thông, khoảng cách truyền thông trong giao tiếp I2C arduino có hạn chế. Trong các ứng dụng yêu cầu kết nối xa hoặc chịu ảnh hưởng nhiễu, cần phải xem xét các giải pháp bù nhiễu và tăng cường tín hiệu.
- Chuẩn giao tiếp I2C yêu cầu việc triển khai đúng các tín hiệu điều khiển và quy tắc truyền thông, điều này có thể làm tăng phức tạp trong việc thiết kế phần cứng của hệ thống.
Tuy nhiên, với sự tiện lợi và linh hoạt trong kết nối nhiều thiết bị, I2C vẫn là một giao thức phổ biến được sử dụng rộng rãi trong các ứng dụng nhúng và viễn thông.