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

  1. 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);

}

 

  1. 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;

}