Cơ bản về giao thức truyền thông I2C
Bài viết này đơn giản hóa giao thức truyền thông I2C, giải thích các nguyên tắc cơ bản và hoạt động của nó để giao tiếp thiết bị hiệu quả.
Bạn có thể thấy mình đang sử dụng I2C nếu bạn từng xây dựng các dự án sử dụng màn hình OLED , cảm biến áp suất khí quyển hoặc mô-đun con quay hồi chuyển/gia tốc kế .
Giới thiệu về giao tiếp I2C
I2C kết hợp những tính năng tốt nhất của SPI và UART. Với I2C, bạn có thể kết nối nhiều slave với một master duy nhất (như SPI) và bạn có thể có nhiều master điều khiển một hoặc nhiều slave. Điều này thực sự hữu ích khi bạn muốn có nhiều hơn một vi điều khiển ghi dữ liệu vào một thẻ nhớ hoặc hiển thị văn bản lên một màn hình LCD.
Giống như giao tiếp UART, I2C chỉ sử dụng hai dây để truyền dữ liệu giữa các thiết bị:

SDA (Dữ liệu nối tiếp) – Đường truyền để thiết bị chủ và thiết bị tớ gửi và nhận dữ liệu.
SCL (Serial Clock) – Đường truyền tín hiệu đồng hồ.
I2C là giao thức truyền thông nối tiếp, do đó dữ liệu được truyền từng bit trên một dây duy nhất (đường SDA).
Giống như SPI, I2C là giao thức đồng bộ, nghĩa là đầu ra của các bit được đồng bộ với việc lấy mẫu các bit bằng tín hiệu xung nhịp được chia sẻ giữa thiết bị chủ và thiết bị tớ. Tín hiệu xung nhịp luôn được điều khiển bởi thiết bị chủ.

I2C hoạt động như thế nào
Với I2C, dữ liệu được truyền dưới dạng tin nhắn. Tin nhắn được chia thành các khung dữ liệu. Mỗi tin nhắn có một khung địa chỉ chứa địa chỉ nhị phân của thiết bị phụ thuộc và một hoặc nhiều khung dữ liệu chứa dữ liệu đang đượ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 mỗi khung dữ liệu:

Điều kiện bắt đầu: Đường SDA chuyển từ mức điện áp cao sang mức điện áp thấp trước khi đường SCL chuyển từ cao sang thấp.
Điều kiện dừng: Đường SDA chuyển từ mức điện áp thấp sang mức điện áp cao sau khi đường SCL chuyển từ thấp lên cao.
Khung địa chỉ: Chuỗi 7 hoặc 10 bit duy nhất cho mỗi thiết bị phụ giúp xác định thiết bị phụ khi thiết bị chính muốn giao tiếp với nó.
Bit Đọc/Ghi: Một bit duy nhất xác định xem thiết bị chủ đang gửi dữ liệu đến thiết bị tớ (mức điện áp thấp) hay yêu cầu dữ liệu từ thiết bị tớ (mức điện áp cao).
Bit ACK/NACK: Mỗi khung trong tin nhắn được theo sau bởi một bit xác nhận/không xác nhận. Nếu khung địa chỉ hoặc khung dữ liệu được nhận thành công, một bit ACK sẽ được trả về cho bên gửi từ thiết bị nhận.
Địa chỉ
I2C không có các đường chọn slave như SPI, vì vậy nó cần một cách khác để cho slave biết rằng dữ liệu đang được gửi đến nó, chứ không phải một slave khác. Nó thực hiện điều này bằng cách định địa chỉ . Khung địa chỉ luôn là khung đầu tiên sau bit bắt đầu trong một tin nhắn mới.
Thiết bị chủ gửi địa chỉ của thiết bị tớ mà nó muốn giao tiếp đến tất cả các thiết bị tớ được kết nối với nó. Sau đó, mỗi thiết bị tớ sẽ 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, nó sẽ gửi một bit ACK điện áp thấp trở lại thiết bị chủ. Nếu địa chỉ không khớp, thiết bị tớ không làm gì cả và đường SDA vẫn ở mức cao.
Đọc/Ghi Bit
Khung địa chỉ bao gồm một bit duy nhất ở cuối, thông báo cho thiết bị phụ thuộc biết thiết bị chủ muốn ghi dữ liệu vào hay nhận dữ liệu từ thiết bị phụ thuộc. Nếu thiết bị chủ muốn gửi dữ liệu đến thiết bị phụ thuộc, bit đọc/ghi sẽ ở mức điện áp thấp. Nếu thiết bị chủ yêu cầu dữ liệu từ thiết bị phụ thuộc, bit này sẽ ở mức điện áp cao.
Khung dữ liệu
Sau khi thiết bị chủ phát hiện bit ACK từ thiết bị phụ, khung dữ liệu đầu tiên đã sẵn sàng để gửi.
Khung dữ liệu luôn dài 8 bit và được gửi với bit có trọng số cao nhất trước. Mỗi khung dữ liệu được theo sau ngay lập tức bởi một bit ACK/NACK để xác minh khung đã được nhận thành công. Bit ACK phải được nhận bởi thiết bị chủ hoặc thiết bị tớ (tùy thuộc vào thiết bị gửi dữ liệu) trước khi khung dữ liệu tiếp theo có thể được gửi.
Sau khi tất cả các khung dữ liệu đã được gửi, thiết bị chủ có thể gửi lệnh dừng đến thiết bị phụ để dừng truyền. Lệnh dừng này là sự chuyển đổi điện áp từ thấp lên cao trên đường SDA sau khi chuyển đổi từ thấp lên cao trên đường SCL, trong khi đường SCL vẫn ở mức cao.
Các bước truyền dữ liệu I2C
1. Thiết bị chủ gửi điều kiện bắt đầu đến mọi thiết bị phụ được kết nối bằng cách chuyển đường SDA từ mức điện áp cao xuống mức điện áp thấp trước khi chuyển đường SCL từ cao xuống thấp:

2. Thiết bị chủ gửi cho mỗi thiết bị tớ địa chỉ 7 hoặc 10 bit của thiết bị tớ mà nó muốn giao tiếp, cùng với bit đọc/ghi:

3. Mỗi slave so sánh địa chỉ được gửi từ master với địa chỉ của chính nó. Nếu địa chỉ trùng khớp, slave trả về bit ACK bằng cách kéo đường SDA xuống thấp một bit. Nếu địa chỉ từ master không trùng khớp với địa chỉ của slave, slave sẽ giữ đường SDA ở mức cao.

4. Máy chủ gửi hoặc nhận khung dữ liệu:

5. Sau khi mỗi khung dữ liệu được truyền đi, thiết bị nhận sẽ trả về một bit ACK khác cho người gửi để xác nhận đã nhận được khung thành công:

6. Để dừng truyền dữ liệu, thiết bị chủ gửi điều kiện dừng tới thiết bị phụ bằng cách chuyển SCL lên cao trước khi chuyển SDA lên cao:

Một Master với nhiều Slave
Vì I2C sử dụng địa chỉ, nhiều slave có thể được điều khiển từ một master duy nhất. Với địa chỉ 7 bit, có thể có 128 (27) địa chỉ duy nhất. Việc sử dụng địa chỉ 10 bit không phổ biến, nhưng cung cấp 1.024 (210) địa chỉ duy nhất. Để kết nối nhiều slave với một master duy nhất, hãy đấu dây chúng như sau, với các điện trở kéo lên 4,7K Ohm nối các đường SDA và SCL với Vcc:

Nhiều Master với nhiều Slave
Nhiều master có thể được kết nối với một slave hoặc nhiều slave. Vấn đề với nhiều master trong cùng một hệ thống xảy ra khi hai master cố gắng gửi hoặc nhận dữ liệu cùng lúc qua đường SDA. Để giải quyết vấn đề này, mỗi master cần kiểm tra xem đường SDA ở mức thấp hay cao trước khi truyền tin. Nếu đường SDA ở mức thấp, điều này có nghĩa là một master khác đang điều khiển bus, và master nên đợi để gửi tin. Nếu đường SDA ở mức cao, thì việc truyền tin là an toàn. Để kết nối nhiều master với nhiều slave, hãy sử dụng sơ đồ sau, với điện trở kéo lên 4,7K Ohm kết nối các đường SDA và SCL với Vcc:

Ưu điểm và nhược điểm của I2C
I2C có nhiều điểm khiến nó có vẻ phức tạp hơn so với các giao thức khác, nhưng có một số lý do chính đáng tại sao bạn có thể muốn hoặc không muốn sử dụng I2C để kết nối với một thiết bị cụ thể:
Thuận lợi
- Chỉ sử dụng hai dây
- Hỗ trợ nhiều máy chủ và nhiều máy khách
- Bit ACK/NACK xác nhận rằng mỗi khung được truyền thành công
- Phần cứng ít phức tạp hơn so với UART
- Giao thức được biết đến rộng rãi và sử dụng rộng rãi
Nhược điểm
- Tốc độ truyền dữ liệu chậm hơn SPI
- Kích thước của khung dữ liệu được giới hạn ở 8 bit
- Cần phần cứng phức tạp hơn để triển khai so với SPI