Giao tiếp I2C với DS1307 dùng CCS
I2C là viết tắt của cụm từ Inter-Integrated Circuit là 1 chuẩn truyền thông để giao tiếp giữa các thiết bị, do hãng điện tử Philips Semiconductor sáng lập và xây dựng thành chuẩn vào năm 1990.
Giao tiếp I2C với DS1307 dùng CCS
Tất cả thông tin bên dưới đây được test trên 16F887, các dòng khác có thể không hữu ích
- Về hàm và module I2C
Trong CCS C for PIC có sẵn các hàm ghi và đọc các thiết bị I2C dành cho các dòng PIC có module phần cứng I2C, chẳng hạn như 16F877A, 887 …
Để sử dụng ta chỉ cần khai báo tiền xử lý
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)
PIN_C3 và PIN_C4 là mặc định của phần cứng 15F887 tuy nhiên ta có thể thay bằng hai chân khác cho tiện thiết kế mạch thì vẫn dùng bình thường. Khi đó ta sẽ có 4 hàm cần để sử dụng là
i2c _start();
i2c_stop();
i2c_wrtite(data);
i2c_read(data);
Chi tiết bạn có thể dùng CCS C compiler help để tham khảo
long cmd;
...
i2c_start(); // Start condition
i2c_write(0xa0);// Device address
i2c_write(cmd);// Low byte of command
i2c_write(cmd>>8);// High byte of command
i2c_stop(); // Stop condition
ví dụ sau sử dụng module I2C của 16F887 để ghi dữ liệu vào IC đồng hồ thời gian thực là DS1307
void write_DS1307(byte address, BYTE data)
{
short int status;
i2c_start();
i2c_write(0xd0);
i2c_write(address);
i2c_write(data);
i2c_stop();
i2c_start();
status=i2c_write(0xd0);
while(status==1)
{
i2c_start();
status=i2c_write(0xd0);
}
}
Và đây là hàm dùng để đọc ra từ một địa chỉ của DS1307
BYTE read_DS1307(byte address)
{
BYTE data;
i2c_start();
i2c_write(0xd0);
i2c_write(address);
i2c_start();
i2c_write(0xd1);
data=i2c_read(0);
i2c_stop();
return(data);
}
- Software I2C (I2C mềm)
Vấn đề là nếu không có module I2C master ở trong PIC ta có thể dọc ghi thiết bị được không? Câu trả lời là có thể. Ta sẽ phải viết riêng các hàm ở trên dựa vào lý thuyết giao thức truyền thông tin I2C
Nhưng trước hết nhấn mạnh, không phải dòng chip nào cũng làm được, lý do là gì thì bản thân chưa tìm hiểu tới, tôi mới chỉ thử trên 16f88 không có I2C Master nhưng là dòng có I2C Slave.
Đối với chip không hỗ trợ phần cứng i2c, dĩ nhiên không thể khai báo
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)
Như vậy không dùng được các hàm i2c_read và i2c_write có sẵn trong CCS, để sử dụng ta phải viết riêng hàm thư viện cho nó:
//dinh nghia chan su dung i2c
//co the thay doi tuy theo su dung
//chu y: can bao dam sao cho load các khai bao
// PIN_C3, PIN_C3
// TRISC3 và TRISC4
//lưu ý khi lập trình, theo lý thuyết SCL phải kéo lên cao trước khi thay đổi SDA
#define PIN_SCL PIN_C3
#define PIN_SDA PIN_C4
#define TRIS_SCL TRISC3
#define TRIS_SDA TRISC4
//------------------------
//cac dinh nghia tien xu ly
//phan nay su dung cho code và khong duoc thay doi
#define SDA_IN {TRIS_SDA=1;}
#define SDA_OUT {TRIS_SDA=0;}
#define SCL_0 output_low(PIN_SCL)
#define SCL_1 output_high(PIN_SCL)
#define SDA_0 output_low(PIN_SDA)
#define SDA_1 output_high(PIN_SDA)
#define CHK_SDA input_state(PIN_SDA)
//
void i2c_delay();
void i2c_int();
void i2c_start();
void i2c_stop();
unsigned int i2c_read(unsigned int ack);
unsigned int i2c_write(unsigned int data);
void i2c_delay()
{
delay_us(1);
}
void i2c_init()
{
TRIS_SCL=0;//allway out
SDA_OUT;
SCL_1;
SDA_1;
}
void i2c_start()
{
SCL_1;
SDA_1;
i2c_delay();
SDA_0;
i2c_delay();
SCL_0;
i2c_delay();
}
void i2c_stop()
{
SDA_0;
SCL_0;
i2c_delay();
SCL_1;
i2c_delay();
SDA_1;
i2c_delay();
}
unsigned int i2c_read(unsigned int ack)
{
int8 i,data;
SDA_1;
SDA_IN;
for (i=0; i<8;i++){
data<<=1;
SCL_0;
i2c_delay();
SCL_1;//clock pull
while(input_state(PIN_SCL)==0){;} //while for SCL=1
if(CHK_SDA==1){data|=1;}
i2c_delay();
}
SCL_0;
SDA_OUT;
if(ack) SDA_0; //ACK
else SDA_1; //NACK
i2c_delay();
SCL_1;
i2c_delay();
SCL_0;
return data;
}
unsigned int i2c_write(unsigned int data)
{
unsigned int ret=0, i;
SDA_OUT;
for(i=0;i<8;i++){
SCL_0;
i2c_delay();
// truyền từ bit cao đến thấp
if(data & 0x80) SDA_1;
else SDA_0;
data<<=1;
SCL_1;
i2c_delay();
}
//get ACK
SCL_0;
SDA_1;
i2c_delay();
SDA_IN;//PIN_SDA is input
SCL_1;
ret= CHK_SDA;
i2c_delay();
SDA_OUT;
SCL_0;
return ret;
}