23 Giới thiệu giao thức IIC (I2C) 
Tài liệu :
- Understanding the I 2C Bus Application report from Texas Instruments các bạn có thể đọc để hiểu rõ hơn, các hình minh họa được lấy nguồn từ tài liệu này.
- I2C Design Mathematics: Capacitance and Resistance
- Getting Started with STM32 - How to Use SPI
Một số hình ảnh từ bài viết lấy từ tài liệu trên.
Tổng quan về giao thức IIC 
IIC (I2C) là gì? 
IIC (Inter-Integrated Circuit), còn gọi là I2C bus, là một giao thức truyền thông nối tiếp được sử dụng phổ biến để kết nối các thiết bị ngoại vi tốc độ thấp. Giao thức này được phát triển bởi hãng Philips (nay là NXP Semiconductors) vào đầu những năm 1980 và hiện nay đã trở thành một tiêu chuẩn công nghiệp.
I2C chỉ cần 2 dây truyền tín hiệu:
- SDA (Serial Data) – Dây truyền dữ liệu nối tiếp
- SCL (Serial Clock) – Dây truyền xung nhịp
Nhờ thiết kế chỉ dùng 2 dây, giao thức này rất đơn giản và tiết kiệm chân IO, đặc biệt thích hợp cho các ứng dụng giao tiếp giữa chip như: cảm biến, bộ nhớ EEPROM, hay các bộ xử lý tín hiệu số (DSP).
Nguyên lý hoạt động của giao thức I2C 
Trong hệ thống I2C:
- Chỉ có một thiết bị chủ (Master), điều khiển toàn bộ quá trình giao tiếp: phát lệnh, điều phối xung nhịp, bắt đầu và kết thúc giao tiếp.
- Các thiết bị còn lại là thiết bị tớ (Slave), chờ lệnh từ Master để gửi hoặc nhận dữ liệu.
Quá trình trao đổi dữ liệu diễn ra theo định dạng khung (frame) bao gồm:
- Địa chỉ thiết bị tớ
- Dữ liệu
- Thông tin điều khiển (Start/Stop/Acknowledge)
Master sẽ chọn thiết bị tớ cần giao tiếp thông qua địa chỉ, và tớ sẽ phản hồi hoặc thực hiện lệnh tùy vào yêu cầu.
I2C hỗ trợ nhiều thiết bị tớ trên cùng một bus, mang lại sự linh hoạt cao trong thiết kế hệ thống nhúng.

Cách I2C hoạt động ở mức phần cứng 
Bus I2C hoạt động với hai mức điện áp logic:
- Mức cao (VH): từ 2.5V đến 5.5V
- Mức thấp (VL): từ 0V đến 0.3V
Các mức này tuân theo chuẩn I2C quốc tế. Bus I2C hỗ trợ nhiều tốc độ truyền khác nhau:
- Chế độ chuẩn: 100 kbps
- Chế độ nhanh: 400 kbps
- Chế độ tốc độ cao: (lên đến vài Mbps, tùy thiết bị)
Tốc độ cụ thể phụ thuộc vào yêu cầu ứng dụng và khả năng hỗ trợ của thiết bị.
Vì sao phải dùng chế độ open-drain (mở cực) 
Các chân SDA (data) và SCL (clock) không được phép xuất mức cao chủ động, mà chỉ được phép kéo xuống mức thấp (open-drain). Lý do:
- Chống nhiễu: Nhiều thiết bị cùng chia sẻ SDA và SCL. Nếu dùng chế độ push-pull (đẩy-kéo), khi một thiết bị xuất HIGH và thiết bị khác xuất LOW cùng lúc sẽ gây xung đột → hỏng chip hoặc lỗi truyền.
- Tránh đoản mạch: Trong open-drain, tất cả thiết bị chỉ kéo LOW hoặc không tác động → nếu hai thiết bị cùng kéo LOW thì vẫn ổn. Nhưng nếu dùng push-pull, một thiết bị kéo HIGH và thiết bị khác kéo LOW → chập điện.

Vì sao cần điện trở kéo lên (pull-up resistor) 
Do các chân I2C không tự đẩy mức cao, nên phải dùng điện trở kéo lên (pull-up) để giữ tín hiệu ở mức HIGH khi không ai kéo xuống.
- Mỗi chân SDA và SCL cần một điện trở pull-up (thường là 4.7kΩ hoặc 10kΩ).
- Trị số cụ thể phụ thuộc vào: dung kháng của bus, độ dài dây, số thiết bị.

Giới hạn vật lý của bus I2C 
- Chiều dài cáp tối đa (gợi ý):- Chế độ chuẩn (100 kbps): ~1 mét
- Chế độ nhanh (400 kbps): ~0.3 mét
 
- Dung kháng của dây dẫn (bus capacitance) cũng ảnh hưởng đến tốc độ và ổn định tín hiệu.

Truyền dữ liệu trong giao thức I2C 
Giao thức I2C chỉ sử dụng 2 đường tín hiệu nên quá trình truyền dữ liệu được đồng bộ hóa bằng tín hiệu xung nhịp (SCL). Các thiết bị sẽ gửi và nhận dữ liệu theo nhịp xung này.
Dưới đây là một số tín hiệu thời gian quan trọng (timing) trong giao tiếp I2C:
Tín hiệu bắt đầu (Start Condition) 
- Khi SCL đang ở mức cao, nếu SDA chuyển từ mức cao xuống mức thấp → đây là tín hiệu bắt đầu giao tiếp.
- Sau tín hiệu này, các thiết bị trên bus sẽ biết rằng một phiên giao tiếp mới sắp bắt đầu.

Mã bắt đầu I2C
void IIC_Start(void)
{
    SDA_OUT();   // Cấu hình chân SDA làm đầu ra
    SDA(1);      // SDA ở mức cao
    SCL(1);      // SCL ở mức cao
    delay_us(5); // Delay nhỏ để ổn định
    SDA(0);      // SDA chuyển từ HIGH -> LOW khi SCL đang HIGH => START
    delay_us(5);
    SCL(0);      // Kết thúc pha START
    delay_us(5);
}Tín hiệu kết thúc (Stop Condition) 
Tín hiệu STOP dùng để kết thúc một phiên truyền dữ liệu I2C. Nó do thiết bị chủ (Master) tạo ra sau khi đã hoàn tất việc gửi hoặc nhận dữ liệu với thiết bị tới.
Điều kiện tạo Stop: Khi SCL đang ở mức cao, SDA chuyển từ LOW → HIGH

Code minh họa
void IIC_Stop(void)
{
    SDA_OUT();   // Đặt SDA làm đầu ra
    SCL(0);      // Đưa SCL xuống thấp
    SDA(0);      // Đưa SDA xuống thấp - chuẩn bị cho Stop
    SCL(1);      // Đưa SCL lên cao
    delay_us(5); // Đợi một chút
    SDA(1);      // SDA chuyển từ LOW → HIGH khi SCL đang HIGH => STOP
    delay_us(5);
}Truyền dữ liệu trong I2C 
Sau khi phát tín hiệu Start và địa chỉ thiết bị, master có thể bắt đầu truyền hoặc nhận dữ liệu với thiết bị slave. Dữ liệu được truyền từng byte (8 bit), mỗi bit được đồng bộ theo nhịp SCL.


Gửi một byte dữ liệu
void IIC_Send_Byte(uint8_t dat)
{
    int i = 0;
    SDA_OUT();   // Đặt SDA làm đầu ra
    SCL(0);      // Đảm bảo SCL ở mức thấp trước khi bắt đầu
    for(i = 0; i < 8; i++)
    {
        // Gửi bit cao nhất trước
        SDA( (dat & 0x80) >> 7 );  // Lấy bit thứ 7
        delay_us(1);
        SCL(1);                    // Tạo xung clock để gửi bit
        delay_us(5);
        SCL(0);                    // Kết thúc xung
        delay_us(5);
        dat <<= 1;                 // Dịch sang bit tiếp theo
    }
}Cơ chế xác nhận: ACK / NACK trong I2C 
Để đảm bảo dữ liệu được truyền chính xác, I2C sử dụng một cơ chế phản hồi gọi là ACK/NACK (Acknowledge / Not Acknowledge):
- ACK (xác nhận): Khi thiết bị đã nhận thành công một byte, nó sẽ kéo SDA xuống LOW trong chu kỳ xung tiếp theo để báo cho bên gửi biết là OK, đã nhận.
- NACK (không xác nhận): Nếu thiết bị không nhận được dữ liệu (do lỗi, hoặc kết thúc truyền), nó sẽ giữ SDA ở mức HIGH, tức là không trả lời.
Việc kiểm tra ACK rất quan trọng với master, để biết có nên tiếp tục truyền hay dừng lại.

Hàm gửi tín hiệu ACK
void IIC_Send_Ack(void)
{
    SDA_OUT();   // Đặt SDA làm đầu ra
    SCL(0);      // Chuẩn bị cho xung clock
    SDA(1);      // Đảm bảo SDA ở HIGH ban đầu
    SDA(0);      // Kéo SDA xuống LOW => tạo tín hiệu ACK
    SCL(1);      // Phát xung để gửi ACK
    delay_us(5);
    SCL(0);      // Kết thúc xung
    SDA(1);      // Thả SDA về lại HIGH
}

Hàm gửi tín hiệu NACK:
void IIC_Send_Nack(void)
{
    SDA_OUT();   // Đặt SDA làm đầu ra
    SCL(0);      // Chuẩn bị phát xung clock
    SDA(0);      // Đưa về LOW tạm thời
    SDA(1);      // Giữ SDA ở HIGH => NACK
    SCL(1);      // Phát xung xác nhận
    delay_us(5);
    SCL(0);      // Kết thúc xung
    SDA(0);      // Thả SDA
}Tổng kết 
| Trạng thái/Hành động | Mô tả | Bên thực hiện | 
|---|---|---|
| Start | SDA chuyển từ 1xuống ↓0khi SCL ở1Báo hiệu bắt đầu giao dịch. | Master | 
| Stop | SDA chuyển từ 0lên ↑1khi SCL ở1. Báo hiệu kết thúc giao dịch. | Master | 
| ACK | Kéo SDA xuống THẤP sau khi nhận 8 bit dữ liệu. Xác nhận nhận thành công. | Bên nhận | 
| NACK | Để SDA ở CAO sau khi nhận 8 bit dữ liệu. Báo hiệu không nhận hoặc không xử lý được. | Bên nhận | 
| Truyền (Write) | Master gửi dữ liệu đến Slave, chờ ACK sau mỗi byte. | Master | 
| Nhận (Read) | Slave gửi dữ liệu đến Master. Master ACK sau mỗi byte, NACK ở byte cuối cùng. | Slave (gửi), Master (nhận) | 
Kiểm soát thời gian và tốc độ truyền trong I2C 
Trên bus I2C, đường xung nhịp SCL do thiết bị chủ (Master) điều khiển. Mỗi bit dữ liệu chỉ được cập nhật hoặc lấy giá trị tại cạnh của xung clock (thường là cạnh lên hoặc cạnh xuống của SCL).
Tốc độ truyền bị giới hạn bởi 
- Thiết bị chậm nhất trên bus
- Chiều dài dây dẫn và dung kháng (capacitance)
- Trở kháng kéo lên và nhiễu môi trường
I2C không dành cho tốc độ cao 
Thông thường:
- Giao tiếp I2C chỉ đạt tốc độ khoảng 100–400 kbps
- Trong một số chế độ đặc biệt có thể đạt tới vài Mbps (High-Speed mode), nhưng hiếm dùng trong thực tế vi điều khiển
Nếu cần tốc độ cao hơn? 
Nếu ứng dụng yêu cầu tốc độ truyền dữ liệu cao, nên xem xét sử dụng các giao thức khác:
| Giao thức | Tốc độ thường gặp | Ghi chú | 
|---|---|---|
| SPI | Lên tới 10+ Mbps | Tốc độ cao, đồng bộ, 4 dây | 
| CAN | Khoảng 1 Mbps | Chống nhiễu mạnh, dùng trong ô tô | 
| UART | Tùy chỉnh (115200+ bps) | Đơn giản, phổ biến | 
Quy trình giao tiếp I2C 
Quy trình gửi dữ liệu (Master → Slave) 
- Phát tín hiệu Start → Bắt đầu truyền dữ liệu.
- Gửi địa chỉ thiết bị + bit ghi (R/W = 0) → Xác định thiết bị cần ghi dữ liệu.
- Chờ phản hồi ACK từ thiết bị → Nếu không có ACK → lỗi truyền.
- Gửi byte dữ liệu (8 bit) → Master gửi từng byte một.
- Chờ ACK từ thiết bị sau mỗi byte → Slave xác nhận đã nhận thành công.
- Lặp lại bước 4–5 nếu còn dữ liệu → Gửi thêm byte nếu cần.
- Phát tín hiệu Stop → Kết thúc phiên truyền.

Quy trình nhận dữ liệu (Slave → Master) 
- Phát tín hiệu Start
- Gửi địa chỉ thiết bị + bit đọc (R/W = 1) → Xác định thiết bị cần đọc dữ liệu.
- Chờ phản hồi ACK từ thiết bị
- Chuyển SDA sang chế độ đầu vào → Chuẩn bị nhận dữ liệu.
- Slave gửi byte dữ liệu đầu tiên
- Master phản hồi ACK nếu muốn nhận thêm → Nếu chỉ nhận 1 byte cuối cùng → gửi NACK.
- Tiếp tục bước 5–6 nếu còn dữ liệu
- Phát tín hiệu Stop → Kết thúc phiên đọc.

Thông số cơ bản của I2C 
Tốc độ truyền: Bus I2C hỗ trợ hai chế độ truyền chính:
- Chế độ tiêu chuẩn (Standard Mode) với tốc độ 100 kbit/s
- Chế độ nhanh (Fast Mode) với tốc độ 400 kbit/s Ngoài ra còn có các chế độ mở rộng như Fast Mode Plus và High-Speed Mode cho tốc độ cao hơn.
Địa chỉ thiết bị: Mỗi thiết bị trên bus I2C có một địa chỉ riêng biệt, có thể là 7 bit hoặc 10 bit. Địa chỉ này được dùng để xác định thiết bị nào sẽ tham gia vào quá trình giao tiếp.
Trạng thái bus: Bus I2C có 5 trạng thái chính:
- Trạng thái rảnh (Idle)
- Tín hiệu bắt đầu (Start condition)
- Tín hiệu kết thúc (Stop condition)
- Tín hiệu phản hồi (Acknowledge/NACK)
- Truyền dữ liệu (Data Transfer)
Định dạng dữ liệu: I2C hỗ trợ hai kiểu định dạng dữ liệu:
- Định dạng chuẩn: gồm 1 byte dữ liệu (8 bit) kèm theo 1 bit phản hồi ack/nack
- Định dạng nhanh: cho phép truyền hai byte liên tục trong một khung truyền
Do cả hai dây SCL và SDA đều là đường truyền hai chiều, tín hiệu trên đó có thể bị ảnh hưởng bởi các yếu tố ngoại vi như điện dung đường dây, gây ra sai số mức điện áp và dẫn đến lỗi giao tiếp. Vì vậy, trong bus I2C, người ta thường sử dụng điện trở kéo lên (pull-up resistor) để đảm bảo các đường tín hiệu ở mức cao khi ở trạng thái rảnh.
Giới thiệu về phần cứng I2C trên STM32 
Trên vi điều khiển STM32F407VET6, có 3 ngoại vi I2C phần cứng được tích hợp sẵn. Đây là các mạch bên trong cho phép giao tiếp trực tiếp với thiết bị bên ngoài thông qua giao thức I2C.
Phần cứng I2C này sử dụng các chân GPIO ở chế độ chức năng thay thế (Alternate Function) để truyền tín hiệu dữ liệu (SDA) và xung nhịp (SCL). Việc chọn đúng chân là bắt buộc vì mỗi I2C tương ứng với các chân cố định đã định nghĩa sẵn.
Việc điều khiển thời gian (timing) trong quá trình giao tiếp I2C được thực hiện bởi các mạch và thanh ghi chuyên dụng, đảm bảo tín hiệu tuân theo đúng chuẩn giao thức I2C. Các khối phần cứng này có thể tự động sinh ra tín hiệu clock và điều khiển mức điện áp trên dây dữ liệu, giúp truyền và nhận dữ liệu đúng thời điểm, từ đó nâng cao độ chính xác và độ ổn định của truyền thông.
Ngoài ra, I2C phần cứng trên STM32 còn hỗ trợ giao tiếp thông qua ngắt (interrupt) hoặc DMA (Direct Memory Access). Điều này giúp CPU có thể thực hiện các tác vụ khác trong khi dữ liệu đang được truyền qua I2C, tăng hiệu suất tổng thể của hệ thống.
Sơ đồ khối phần cứng I2C 
Trên vi điều khiển STM32F407VET6, mô-đun I2C phần cứng chỉ hỗ trợ hai chế độ truyền:
- Chế độ tiêu chuẩn (Standard Mode): 100 kHz
- Chế độ nhanh (Fast Mode): 400 kHz
Hai chế độ này đáp ứng nhu cầu giao tiếp trong các ứng dụng phổ thông, từ các cảm biến tốc độ thấp đến các thiết bị cần tốc độ truyền nhanh hơn nhưng vẫn đảm bảo độ ổn định.
Quy trình gửi dữ liệu bằng phần cứng I2C 
(1) Khởi tạo phần mềm Cấu hình các tham số cho bộ điều khiển I2C để phù hợp với yêu cầu giao tiếp của thiết bị. Bao gồm:
- Tốc độ truyền I2C (100 kHz hoặc 400 kHz)
- Chế độ địa chỉ (7 bit hoặc 10 bit)
- Địa chỉ thiết bị slave cần giao tiếp
(2) Thiết lập tín hiệu START Gửi tín hiệu bắt đầu (Start Condition) lên bus I2C bằng cách đặt bit START trong thanh ghi điều khiển. Có thể kiểm tra cờ SBSEND – khi bit này được phần cứng set lên mức 1, nghĩa là tín hiệu START đã được gửi thành công.
(3) Xử lý cờ SBSEND Cờ SBSEND chỉ báo tín hiệu bắt đầu đã gửi xong.
- Trong chế độ địa chỉ 10 bit, cần xóa cờ này để tiếp tục bước kế tiếp.
- Trong chế độ địa chỉ 7 bit, KHÔNG được xóa cờ SBSEND, nếu không quá trình truyền sẽ lỗi và không tiếp tục được.
(4) Xử lý cờ ADDSEND
- Với chế độ 10 bit, địa chỉ được gửi thành 2 phần: byte cao và byte thấp. Sau mỗi lần gửi, phần cứng sẽ set cờ ADD10SEND và ADDSEND. Cần xóa cả hai cờ để tiếp tục.
- Với chế độ 7 bit, chỉ cần gửi một byte địa chỉ. Sau đó, đợi phần cứng set cờ ADDSEND, rồi xóa cờ này.
(5) Gửi dữ liệu (ghi byte dữ liệu) Trước khi gửi, cần kiểm tra thanh ghi truyền (data register) có trống không bằng cách đọc cờ TBE (Transmit Buffer Empty):
- Khi TBE = 1: có thể ghi dữ liệu vào. Sau khi gửi, cần kiểm tra xem slave có phản hồi không thông qua cờ BTC (Byte Transfer Complete):
- BTC = 1: dữ liệu đã gửi thành công và có phản hồi ACK.
(6) Gửi tín hiệu STOP Cuối cùng, gửi tín hiệu kết thúc truyền thông bằng cách set bit STOP. Điều này giải phóng bus và kết thúc phiên giao tiếp.
Sơ đồ quy trình gửi dữ liệu I2C

Quy trình nhận dữ liệu bằng phần cứng I2C 
Các bước từ (1) đến (4) trong sơ đồ hình 2-2-1 tương tự như quy trình gửi dữ liệu, đặc biệt là xử lý cờ ADDSEND, nên phần này sẽ không lặp lại. Chúng ta bắt đầu từ bước thiết lập lại tín hiệu START.
(1) Gửi lại tín hiệu START Trước khi gửi lại tín hiệu bắt đầu, phải gửi tín hiệu STOP trước để giải phóng bus, đưa I2C về trạng thái nhàn rỗi. Nếu bỏ qua bước này, phần cứng sẽ không cho phép gửi lại START, và quá trình nhận sẽ không thể tiếp tục.
(2) Xử lý cờ SBSEND Tương tự như khi gửi, khi tín hiệu START được gửi thành công, phần cứng sẽ tự động set cờ SBSEND = 1.
- Nếu dùng chế độ địa chỉ 10 bit, cần xóa cờ SBSEND để tiếp tục bước tiếp theo.
- Nếu dùng chế độ 7 bit, KHÔNG xóa SBSEND, nếu không phần cứng sẽ không cho phép nhận tiếp.
(3) Xử lý cờ ADDSEND
- Chế độ 10 bit: Cần gửi địa chỉ 2 lần (byte cao trước, byte thấp sau). Sau mỗi lần gửi, phần cứng sẽ set cờ ADD10SEND và ADDSEND, và ta cần xóa cả hai cờ này.
- Chế độ 7 bit: Chỉ gửi một lần địa chỉ, sau đó đợi cờ ADDSEND = 1, rồi xóa ADDSEND.
(4) Đọc dữ liệu Để biết có thể đọc dữ liệu hay chưa, kiểm tra cờ RBNE (Receive Buffer Not Empty):
- RBNE = 1: dữ liệu đã có trong thanh ghi, có thể đọc ra. Sau khi đọc xong mỗi byte, phần cứng sẽ tự động gửi ACK nếu bit ACKEN được bật. Điều này thông báo với slave rằng master đã nhận được dữ liệu và sẵn sàng nhận byte tiếp theo.
(5) Dừng nhận – Tắt ACK và gửi STOP Khi đọc byte cuối cùng, nếu không muốn nhận thêm dữ liệu, cần tắt bit ACK (clear ACKEN) để gửi tín hiệu NACK (không phản hồi). Ngay sau đó, gửi tín hiệu STOP để kết thúc quá trình nhận dữ liệu.
Sơ đồ quy trình nhận dữ liệu I2C

So sánh giữa I2C phần mềm và I2C phần cứng 
Giao thức I2C có thể được triển khai bằng phần mềm (software I2C) hoặc phần cứng (hardware I2C). Hai phương pháp này khác nhau về cách thực hiện và yêu cầu tài nguyên phần cứng.
I2C phần mềm (Software I2C) 
I2C phần mềm là cách triển khai giao tiếp I2C thông qua lập trình trực tiếp, sử dụng các chân GPIO thông thường để mô phỏng hai đường SDA (dữ liệu) và SCL (xung nhịp). Bằng cách điều khiển mức điện áp của các chân này thông qua phần mềm, ta có thể tạo ra tín hiệu và dữ liệu theo chuẩn I2C.
Ưu điểm của I2C phần mềm:
- Không phụ thuộc vào phần cứng I2C tích hợp, có thể chạy trên bất kỳ vi điều khiển nào có chân GPIO.
- Linh hoạt cao: dễ tùy chỉnh theo yêu cầu, hỗ trợ nhiều thiết bị slave hoặc môi trường nhiều master.
- Tiết kiệm tài nguyên: rất phù hợp với các hệ thống MCU tài nguyên thấp.
Nhược điểm:
- Tốc độ thấp hơn do xử lý hoàn toàn bằng phần mềm.
- Dễ sai lệch thời gian (timing) nếu hệ thống bận xử lý tác vụ khác.
Phù hợp cho các ứng dụng đơn giản, giao tiếp tốc độ thấp hoặc trong môi trường cần nhiều thiết bị nhưng ít tài nguyên phần cứng.
I2C phần cứng (Hardware I2C) 
I2C phần cứng sử dụng bộ ngoại vi tích hợp sẵn trong vi điều khiển, cho phép xử lý toàn bộ giao thức I2C bằng phần cứng chuyên dụng. Các chip STM32 hiện đại, ví dụ STM32F407, đều có module I2C tích hợp.
Ưu điểm của I2C phần cứng:
- Tốc độ cao, ổn định hơn.
- Tự động xử lý tín hiệu đồng bộ, xung nhịp, lỗi và phản hồi ACK/NACK.
- Giảm tải cho CPU, có thể dùng ngắt hoặc DMA để tối ưu hiệu suất.
Nhược điểm:
- Phụ thuộc vào phần cứng: chỉ sử dụng được nếu vi điều khiển hỗ trợ I2C phần cứng.
- Chiếm dụng các chân cố định: không thể linh hoạt chọn bất kỳ GPIO nào.
Kết luận 
| Tiêu chí | I2C phần mềm | I2C phần cứng | 
|---|---|---|
| Phụ thuộc phần cứng | Không | Có | 
| Tốc độ truyền | Thấp | Cao | 
| Độ ổn định | Trung bình | Cao | 
| Linh hoạt GPIO | Tự do chọn chân | Bắt buộc chân cố định | 
| Độ phức tạp lập trình | Cao (phải viết code mô phỏng) | Thấp (sử dụng API/hardware support) | 
| Ứng dụng phù hợp | Hệ thống tài nguyên thấp | Ứng dụng cần hiệu suất cao | 
Tùy vào nhu cầu và tài nguyên hệ thống, người lập trình có thể chọn phương án phù hợp nhất.
Ưu và nhược điểm của I2C (IIC) 
Ưu điểm 
- Truyền song công (hai chiều): Bus I2C hỗ trợ truyền dữ liệu hai chiều giữa thiết bị master và slave thông qua một dây dữ liệu SDA duy nhất, giúp tiết kiệm số chân sử dụng.
- Tích hợp dễ dàng: Giao thức I2C dễ dàng được tích hợp trong vi điều khiển hoặc chip ngoại vi, giảm độ phức tạp khi thiết kế mạch và lập trình.
- Hỗ trợ nhiều thiết bị: Cho phép nhiều thiết bị cùng kết nối trên một bus thông qua địa chỉ riêng biệt, giúp chia sẻ dữ liệu hiệu quả.
- Độ tin cậy cao: Dữ liệu được truyền theo mức logic chuẩn, giúp giảm nhiễu và tăng độ ổn định của đường truyền.
Nhược điểm 
- Băng thông thấp: Tốc độ truyền tối đa thường chỉ đạt 100–400 kbps, chậm hơn nhiều so với SPI hoặc CAN.
- Yêu cầu khắt khe về thời gian: Giao tiếp I2C đòi hỏi tuân thủ chính xác về xung nhịp và thời gian, đặc biệt ở tốc độ cao dễ gây lỗi do nhiễu.
- Chiều dài dây giới hạn: Dây bus I2C thường chỉ hoạt động ổn định trong khoảng 1–2 mét, do ảnh hưởng của nhiễu, suy hao và yêu cầu về đồng bộ xung.
Ứng dụng thực tế của I2C 
I2C là một trong những chuẩn giao tiếp phổ biến nhất trong hệ thống nhúng. Dưới đây là một số ví dụ thực tế:
- Cảm biến nhiệt độ: Các cảm biến như SHT31, LM75 sử dụng I2C để truyền dữ liệu nhiệt độ đến vi điều khiển.
- Mạch điều khiển LED (LED Driver):PCA9685 là một chip điều khiển PWM phổ biến sử dụng I2C, giúp điều khiển độ sáng hoặc màu sắc của LED.
- Màn hình OLED: Màn hình OLED nhỏ gọn thường giao tiếp qua I2C để hiển thị văn bản hoặc đồ họa trong các thiết bị như đồng hồ, máy đo huyết áp,...
- Bộ điều khiển cảm ứng (Touch Controller): Ví dụ như STMPE610, dùng I2C để đọc tọa độ X/Y từ màn hình cảm ứng dưới 15 inch.
- Đo điện áp/dòng (Power Monitor): Chip như INA219 dùng I2C để thu thập dữ liệu điện áp và dòng, ứng dụng trong các hệ thống quản lý điện hoặc điều khiển công nghiệp.
I2C là một giao tiếp hiệu quả, dễ triển khai và tiết kiệm tài nguyên, phù hợp với nhiều loại thiết bị ngoại vi trong hệ thống nhúng.