- Giao thức truyền thông I2C là gì?
- I2C Communication hoạt động như thế nào?
- Sử dụng giao tiếp I2C ở đâu?
- I2C với PIC16F877a sử dụng Trình biên dịch XC8
- Lập trình bằng cách sử dụng tệp tiêu đề I2C:
- Mô phỏng Proteus:
Bộ vi điều khiển PIC là một nền tảng mạnh mẽ được cung cấp bởi vi mạch cho các dự án nhúng, tính chất linh hoạt của nó đã khiến nó tìm cách đưa vào nhiều ứng dụng và giai đoạn này vẫn đang tiếp tục. Nếu bạn đã theo dõi các hướng dẫn về PIC của chúng tôi thì bạn sẽ nhận thấy rằng chúng tôi đã bao gồm một loạt các hướng dẫn về vi điều khiển PIC bắt đầu từ những điều cơ bản. Kể từ bây giờ, chúng tôi đã đề cập đến những điều cơ bản mà chúng tôi có thể tham gia vào những thứ thú vị hơn như cổng giao tiếp.
Trong hệ thống rộng lớn của các ứng dụng nhúng, không có vi điều khiển nào có thể tự thực hiện tất cả các hoạt động. Tại một số thời điểm nó phải giao tiếp với các thiết bị khác để chia sẻ thông tin, có nhiều loại giao thức truyền thông khác nhau để chia sẻ những thông tin này, nhưng được sử dụng nhiều nhất là USART, IIC, SPI và CAN. Mỗi giao thức truyền thông đều có ưu và nhược điểm riêng. Bây giờ chúng ta hãy tập trung vào phần IIC vì đó là những gì chúng ta sẽ tìm hiểu trong hướng dẫn này.
Giao thức truyền thông I2C là gì?
Thuật ngữ IIC là viết tắt của “ Inter Integrated Circuits ”. Nó thường được ký hiệu là I2C hoặc I bình phương C hoặc thậm chí là giao thức giao diện 2 dây (TWI) ở một số nơi nhưng tất cả đều có nghĩa giống nhau. I2C là một giao thức truyền thông đồng bộ có nghĩa là cả hai thiết bị đang chia sẻ thông tin phải chia sẻ một tín hiệu đồng hồ chung. Nó chỉ có hai dây để chia sẻ thông tin, trong đó một dây được sử dụng cho tín hiệu vòi và dây kia được sử dụng để gửi và nhận dữ liệu.
I2C Communication hoạt động như thế nào?
Giao tiếp I2C lần đầu tiên được giới thiệu bởi Phillips. Như đã nói trước đó, nó có hai dây, hai dây này sẽ được kết nối trên hai thiết bị. Ở đây một thiết bị được gọi là chủ và thiết bị còn lại được gọi là tớ. Giao tiếp nên và sẽ luôn xảy ra giữa hai Master và một Slave. Ưu điểm của giao tiếp I2C là có thể kết nối nhiều hơn một nô lệ với một Master.
Giao tiếp hoàn chỉnh diễn ra thông qua hai dây này là Đồng hồ nối tiếp (SCL) và Dữ liệu nối tiếp (SDA).
Đồng hồ nối tiếp (SCL): Chia sẻ tín hiệu đồng hồ được tạo ra bởi chính với phụ
Dữ liệu nối tiếp (SDA): Gửi dữ liệu đến và đi giữa Master và slave.
Tại bất kỳ thời điểm nào, chỉ có chủ mới có thể bắt đầu giao tiếp. Vì có nhiều hơn một nô lệ trong xe buýt, chủ phải tham chiếu đến mỗi nô lệ bằng một địa chỉ khác nhau. Khi được giải quyết, chỉ salve với địa chỉ cụ thể đó sẽ trả lời lại thông tin trong khi những người khác tiếp tục bỏ cuộc. Bằng cách này, chúng ta có thể sử dụng cùng một bus để giao tiếp với nhiều thiết bị.
Sử dụng giao tiếp I2C ở đâu?
Giao tiếp I2C chỉ được sử dụng cho giao tiếp khoảng cách ngắn. Nó chắc chắn đáng tin cậy ở một mức độ nào đó vì nó có xung đồng hồ được đồng bộ hóa để làm cho nó trở nên thông minh. Giao thức này chủ yếu được sử dụng để giao tiếp với cảm biến hoặc các thiết bị khác phải gửi thông tin đến chủ. Nó rất tiện dụng khi một bộ vi điều khiển phải giao tiếp với nhiều mô-đun phụ khác bằng cách sử dụng tối thiểu chỉ dây. Nếu bạn đang tìm kiếm một giao tiếp tầm xa, bạn nên thử RS232 và nếu bạn đang tìm kiếm một giao tiếp đáng tin cậy hơn, bạn nên thử giao thức SPI.
I2C với PIC16F877a sử dụng Trình biên dịch XC8
Giới thiệu đủ rồi, hãy cùng tham gia và tìm hiểu cách sử dụng vi điều khiển để thực hiện giao tiếp I2C. Trước khi chúng ta bắt đầu, hãy làm rõ rằng hướng dẫn này chỉ nói về I2C trong PIC16F877a sử dụng trình biên dịch XC8, quy trình sẽ giống như vậy đối với các bộ vi điều khiển khác nhưng có thể cần phải thay đổi một chút. Cũng nên nhớ rằng đối với các bộ vi điều khiển tiên tiến như dòng PIC18F, bản thân trình biên dịch có thể có một số thư viện được tích hợp sẵn để sử dụng các tính năng I2C, nhưng đối với PIC16F877A thì không có thứ gì giống như vậy tồn tại vì vậy chúng ta hãy tự xây dựng một thư viện. Thư viện được giải thích ở đây sẽ được cung cấp dưới dạng tệp tiêu đề để tải xuống ở phía dưới có thể được sử dụng cho PIC16F877A để giao tiếp với các thiết bị I2C khác.
Luôn luôn là nơi tốt nhất để bắt đầu bất cứ điều gì là biểu dữ liệu của chúng tôi. Tìm kiếm chi tiết về I2C trong biểu dữ liệu và kiểm tra xem thanh ghi nào phải được cấu hình. Tôi sẽ không giải thích chi tiết vì biểu dữ liệu đã làm điều đó cho bạn. Dưới đây tôi sẽ giải thích các chức năng khác nhau có trong tệp tiêu đề và trách nhiệm của chúng trong chương trình.
void I2C_Initialize ()
Hàm khởi tạo được sử dụng để nói với bộ vi điều khiển rằng chúng ta sẽ sử dụng giao thức I2C. Điều này có thể được thực hiện bằng cách đặt các bit cần thiết trên thanh ghi SSPCON và SSPCON2. Bước đầu tiên chúng ta sẽ khai báo các chân IIC là chân đầu vào, ở đây chân RC3 và RC4 nên dùng cho giao tiếp I2C nên chúng ta khai báo chúng là chân đầu vào. Tiếp theo, chúng ta nên đặt SSPCON và SSPCON2 là các thanh ghi điều khiển MSSP. Chúng tôi đang vận hành PIC ở chế độ chính IIC với tần số xung nhịp là FOSC / (4 * (SSPADD + 1)). Tham khảo số trang của biểu dữ liệu được đề cập trong các dòng nhận xét bên dưới để hiểu tại sao thanh ghi cụ thể đó được đặt theo cách đó.
Vì vậy, tiếp theo chúng ta phải đặt tần số đồng hồ, tần số đồng hồ cho các ứng dụng khác nhau có thể khác nhau, do đó chúng tôi nhận được sự lựa chọn từ người dùng thông qua biến feq_k và sử dụng nó trong công thức của chúng tôi để đặt thanh ghi SSPADD.
void I2C_Initialize (const unsigned long feq_K) // Bắt đầu IIC là chính { TRISC3 = 1; TRISC4 = 1; // Đặt chân SDA và SCL làm chân đầu vào SSPCON = 0b00101000; // pg84 / 234 SSPCON2 = 0b00000000; // pg85 / 234 SSPADD = (_XTAL_FREQ / (4 * feq_K * 100)) - 1; // Cài đặt Tốc độ Đồng hồ pg99 / 234 SSPSTAT = 0b00000000; // pg83 / 234 }
Void I2C_Hold ()
Chức năng quan trọng tiếp theo là hàm I2C_hold được sử dụng để giữ quá trình thực thi của thiết bị cho đến khi hoàn thành hoạt động I2C hiện tại. Chúng tôi sẽ phải kiểm tra xem các hoạt động I2C có phải được tổ chức hay không trước khi bắt đầu bất kỳ hoạt động mới nào. Điều này có thể được thực hiện bằng cách kiểm tra thanh ghi SSPSTAT và SSPCON2. SSPSTAT chứa thông tin về trạng thái của bus I2C.
Chương trình có vẻ hơi phức tạp vì nó liên quan đến toán tử “và” và “hoặc”. Khi bạn phá vỡ nó như
SSPSTAT & 0b00000100 SSPCON2 & 0b00011111
Các bác sĩ cho biết thêm:
Nó có nghĩa là chúng tôi đang đảm bảo rằng bit thứ 2 trên SSPSTAT là 0 và các bit tương tự từ 0 đến 4 là 0 trên SSPCON2. Sau đó, chúng tôi kết hợp tất cả những điều này để kiểm tra kết quả là số không. Nếu kết quả là zero chương trình sẽ tiến hành nếu không nó sẽ giữ đó cho đến khi nó được không vì nó được sử dụng trong một thời gian vòng lặp.
void I2C_Hold () { while ((SSPCON2 & 0b00011111) - (SSPSTAT & 0b00000100)); // kiểm tra điều này trên thanh ghi để đảm bảo IIC không được xử lý }
Void I2C_Begin () và void I2C_End ()
Mỗi khi chúng ta ghi hoặc đọc bất kỳ dữ liệu nào bằng bus I2C, chúng ta nên bắt đầu và kết thúc kết nối I2C. Để bắt đầu giao tiếp I2C, chúng ta phải đặt bit SEN và để kết thúc giao tiếp chúng ta phải đặt bit trạng thái PEN. Trước khi chuyển đổi bất kỳ bit nào trong số này, chúng ta cũng nên kiểm tra xem bus I2C có bận hay không bằng cách sử dụng hàm I2C_Hold như đã thảo luận ở trên.
void I2C_Begin () { I2C_Hold (); // Giữ chương trình là I2C đang bận SEN = 1; // Bắt đầu IIC pg85 / 234 } void I2C_End () { I2C_Hold (); // Giữ chương trình là I2C đang bận PEN = 1; // Kết thúc IIC pg85 / 234 }
Void I2C_Write ()
Chức năng ghi được sử dụng để gửi bất kỳ dữ liệu nào từ mô-đun chính đến mô-đun cứu. Hàm này thường được sử dụng sau hàm bắt đầu I2C và theo sau là hàm kết thúc I2C. Dữ liệu phải được ghi vào bus IIC được chuyển qua dữ liệu biến. Dữ liệu này sau đó được tải vào thanh ghi bộ đệm SSPBUF để gửi nó qua bus I2C.
Thông thường trước khi ghi dữ liệu, một địa chỉ sẽ được ghi vì vậy bạn sẽ phải sử dụng hàm ghi hai lần, một lần để thiết lập địa chỉ và lần còn lại để gửi dữ liệu thực.
void I2C_Write (dữ liệu chưa dấu) { I2C_Hold (); // Giữ chương trình là I2C đang bận SSPBUF = data; // pg82 / 234 }
I2C_Read () ngắn không dấu
Hàm cuối cùng mà chúng ta phải biết là hàm I2C_Read . Chức năng này được sử dụng để đọc dữ liệu hiện có trên bus I2C. Nó được sử dụng sau khi yêu cầu nô lệ ghi một số giá trị vào xe buýt. Giá trị nhận được sẽ nằm trong SSPBUF, chúng tôi có thể chuyển giá trị đó sang bất kỳ biến nào cho hoạt động của chúng tôi.
Trong quá trình giao tiếp I2C, slave sau khi gửi dữ liệu theo yêu cầu của Master sẽ gửi một bit khác là bit báo nhận, bit này cũng cần được master kiểm tra để đảm bảo giao tiếp thành công. Sau khi kiểm tra bit ACKDT để xác nhận, nó sẽ được kích hoạt bằng cách thiết lập bit ACKEN.
unsigned short I2C_Read (unsigned short ack) { unsigned ngắn đến; I2C_Hold (); RCEN = 1; I2C_Hold (); đến = SSPBUF; // lấy dữ liệu đã lưu trong SSPBUF I2C_Hold (); ACKDT = (ack)? 0: 1; // kiểm tra xem bit ack có nhận được không ACKEN = 1; // pg 85/234 return incoming; }
Đó là, các chức năng này phải đủ để thiết lập giao tiếp I2C và ghi hoặc đọc dữ liệu từ một thiết bị. Cũng lưu ý rằng có nhiều chức năng khác mà giao tiếp I2C có thể thực hiện nhưng vì mục đích đơn giản, chúng tôi không thảo luận chúng ở đây. Bạn luôn có thể tham khảo biểu dữ liệu để biết hoạt động hoàn chỉnh của
Có thể tải xuống mã hoàn chỉnh với tệp tiêu đề cho giao tiếp I2C PIC16F877A I2C từ liên kết.
Lập trình bằng cách sử dụng tệp tiêu đề I2C:
Bây giờ chúng ta đã học cách hoạt động của giao tiếp I2C và cách chúng ta có thể sử dụng tệp tiêu đề được tạo cho nó, chúng ta hãy tạo một chương trình đơn giản, trong đó chúng ta sẽ sử dụng tệp tiêu đề và ghi một số giá trị vào các dòng I2C. Sau đó, chúng tôi sẽ mô phỏng chương trình này và kiểm tra xem các giá trị này có đang được ghi trên bus hay không.
Như mọi khi, chương trình bắt đầu với việc thiết lập các bit Cấu hình và đặt tần số xung nhịp thành 20 MHz như hình dưới đây
#pragma config FOSC = HS // Các bit chọn bộ tạo dao động (bộ tạo dao động HS) #pragma config WDTE = OFF // Bit Enable Watchdog Timer (WDT đã bị vô hiệu hóa) #pragma config PWRTE = ON // Bit Bật bộ hẹn giờ bật nguồn (PWRT đã bật) # pragma config BOREN = ON // Brown-out Reset bit Enable bit (BOR enable) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming bit (RB3 là I / O kỹ thuật số, HV bật MCLR phải được sử dụng để lập trình) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Ghi bảo vệ tắt; tất cả bộ nhớ chương trình có thể được ghi bởi EECON control) #pragma config CP = OFF // Bit bảo vệ mã bộ nhớ chương trình Flash (Tắt bảo vệ mã) #define _XTAL_FREQ 20000000
Bước tiếp theo sẽ là thêm tệp tiêu đề mà chúng ta vừa thảo luận. Tệp tiêu đề được đặt tên là PIC16F877a_I2C.h và có thể được tải xuống từ liên kết mà chúng tôi đã thảo luận ở trên. Đảm bảo rằng tệp tiêu đề được thêm vào tệp tiêu đề của danh sách dự án của bạn, cấu trúc tệp dự án của bạn sẽ giống như thế này
Sau khi đảm bảo rằng tệp tiêu đề được thêm vào tệp dự án của bạn, hãy bao gồm tệp tiêu đề trong tệp C chính
#include
Bên trong vòng lặp while, chúng ta sẽ bắt đầu giao tiếp I2C ghi một vài giá trị ngẫu nhiên vào bus I2C và sau đó Kết thúc giao tiếp I2C. Các giá trị ngẫu nhiên mà tôi đã chọn là D0, 88 và FF. Bạn có thể nhập bất kỳ giá trị nào bạn muốn. Nhưng hãy nhớ những giá trị đó vì chúng tôi sẽ xác minh chúng trong mô phỏng của chúng tôi.
trong khi (1) { I2C_Begin (); I2C_Write (0xD0); I2C_Write (0x88); I2C_Write (0xFF); I2C_End (); __delay_ms (1000); }
Các chương trình đầy đủ có thể được tìm thấy ở dưới cùng của trang, bạn có thể sử dụng hoặc tải về file zip hoàn chỉnh của chương trình tại đây. Sau khi nhận được chương trình biên dịch nó và sẵn sàng để mô phỏng.
Mô phỏng Proteus:
Proteus có một công cụ tuyệt vời được gọi là trình gỡ lỗi I2C có thể được sử dụng để đọc dữ liệu trên bus I2C, vì vậy chúng ta hãy xây dựng một mạch bằng cách sử dụng nó và kiểm tra xem dữ liệu có được ghi thành công hay không. Sơ đồ mạch hoàn chỉnh được hiển thị bên dưới
Tải tệp hex được tạo bởi chương trình của chúng tôi bằng cách nhấp đúp vào Bộ vi điều khiển. Sau đó mô phỏng chương trình. Bạn sẽ thấy một cửa sổ bật lên hiển thị tất cả thông tin về bus I2C. Cửa sổ cho chương trình của chúng tôi được hiển thị bên dưới.
Nếu bạn xem kỹ dữ liệu đang được viết, bạn có thể nhận thấy rằng chúng giống với dữ liệu mà chúng tôi đã viết trong chương trình của mình. Các giá trị là D0, 88 và FF. Các giá trị được ghi sau mỗi 1 giây nên thời gian cũng được cập nhật như hình dưới đây. Mũi tên màu xanh lam chỉ ra rằng nó được viết từ master đến slave, nếu ngược lại, nó sẽ trỏ theo hướng ngược lại. Dưới đây là một cái nhìn sâu hơn về dữ liệu được gửi.
Đây chỉ là một cái nhìn sơ lược về những gì I2C có thể làm, nó cũng có thể đọc và ghi dữ liệu vào nhiều thiết bị. Chúng tôi sẽ trình bày thêm về I2C trong các hướng dẫn sắp tới của chúng tôi bằng cách giao tiếp các mô-đun khác nhau hoạt động với giao thức I2C.
Hy vọng bạn đã hiểu dự án và học được điều gì đó hữu ích từ nó. Nếu bạn có bất kỳ nghi ngờ nào, hãy đăng chúng trong phần bình luận bên dưới hoặc sử dụng diễn đàn để được trợ giúp kỹ thuật.
Mã hoàn chỉnh đã được đưa ra dưới đây; bạn có thể tải xuống tệp tiêu đề với tất cả mã từ đây.