Chào mừng đến với Câu Lạc Bộ Sáng Tạo
Chia sẻ kinh nghiệm
Kết nối đam mê
Đang cập nhật thời gian...
BÀI VIẾT NỔI BẬT
Xin chào! Tôi là Ếch Sáng Tạo :-)
Chia sẻ trang




Chuyên mục
Bài mới
Xem nhiều
Thống kê
  • Bài viết: 334/334
  • Thành viên: 10.084
  • Đang online: 20
  • Khách hôm nay: 2.948
  • Khách hôm qua: 2.269
  • Tổng khách: 16.109.011
Bài viết
Bài 10: Giao tiếp I2C cho vi điều khiển 8051 - SangTaoClub.Net
Bài 10: Giao tiếp I2C cho vi điều khiển 8051
Đăng bởi: Vũ Văn Thái - Thời gian: 27-11-2013, 16:06
Chuyên mục: Học lập trình 8051 - Lượt xem: 37.309

Giao tiếp I2C cho vi điều khiển 8051

Cũng như giao tiếp UART, I2C là chuẩn giao tiếp nối tiếp sử dụng 2 dây phát triển bởi Philips... cái này có thể tra google để biết thêm, mình sẽ ko giới thiệu về lịch sử phát triển mà hương dẫn bạn code luôn :)

I2C được ứng dụng rất nhiều trong tất cả các thiết bị do lường, cảm biến, module, VDK, IC thời gian thực, EEPROM 24Cxx ...... nên khi học VDK bạn sẽ ko thể bỏ qua nó vì các ứng dụng sau này sẽ phải cần đến nó.

Để giao tiếp được với các thiết bị trên ta phải kết nối chúng với nhau qua 2 dây là SDA (dữ liệu 2 chiều) và SCL (xung nhịp). I2C cho phép tất cả các thiết bị có I2C nối chung đường giao tiếp tức là VD có 3 thiết bị có I2C thì có thể dùng chung 2 dây giao tiếp SDA và SCL, tại sao có thể chung như vậy dc là vì tất cả các thiết bị I2C đều phải có 1 địa chỉ riêng(như là mỗi ng có 1 tên vậy - gọi tới ai thì ng đó mới dc giao tiếp) đây là mối quan hệ Chủ-Tớ (Master-Slave)

Giao tiếp I2C cho vi điều khiển 8051 - SangTaoClub.Net

Khác với PIC và AVR dc tích hợp sẵn 1 cổng I2C thì 8051 hơi thiệt thòi một chút nhưng ko sao ta vẫn có thể giao tiếp bình thường khi xây dựng Hàm thư viện viết sẵn.

Giao tiếp I2C cho vi điều khiển 8051 - SangTaoClub.Net

Dưới đây là các hàm giao tiếp I2C cho 8051:

/****************Khai báo chân giao tiep I2C***************************/

#define SCL    P0_3
#define SDA    P0_2

/****************Cac ham giao tiep I2C***************************/
void I2C_time_start(){
          SCL = 1;
          SDA = 1;
          SDA = 0;
          SCL = 0;
}
void I2C_time_stop(){
          SCL = 1;
          SDA = 0;
          SDA=1;
          SCL=1;
}
unsigned char I2C_write(unsigned char dat){
          unsigned char i;
          for (i=0;i<8;i++){
                    SDA = (dat & 0x80); ///? 1:0;
                    SCL=1;
                    SCL=0;
                    dat<<=1;
          }
          SCL = 1;
          SCL = 0;
          return dat;
}
unsigned char I2C_read(void){
          bit rd_bit;
          unsigned char i, dat;
          dat = 0x00;
          for(i=0;i<8;i++){ /* For loop read data 1 byte */
                    SCL = 1;
                    rd_bit = SDA; /* Keep for check acknowledge */
                    dat = dat<<1;
                    dat = dat | rd_bit; /* Keep bit data in dat */
                    SCL = 0; /* Clear SCL */
          }
          return dat;
}

Như code trên ta chỉ cần viết I2C_write(dữ liệu); để gửi dữ liệu đi và I2C_read(); để lấy dữ liệu về

Code I2C giao tiếp IC thời gian thực DS1307:

/***************Dia chi giao tiep DS1307*********************/
#define DS1307_SEC      0x00 //Giay
#define DS1307_MIN       0x01 //Phut
#define DS1307_HOUR     0x02 //Gio
#define DS1307_DAY        0x03 //Thu
#define DS1307_DATE      0x04 //Ngay
#define DS1307_MONTH    0x05 //Thang
#define DS1307_YEAR       0x06 //Nam

void DS1307_Write(unsigned char addr,unsigned char dat){
          unsigned int temp;
          temp = dat ; /*HEX to BCD*/
          dat = (((dat/10)*16)|(temp %10)); /*for Led 7seg*/
          I2C_time_start(); /* time_start i2c bus */
          I2C_write(0XD0); /* Connect to DS1307 */
          I2C_write(addr); /* Requetime_5 RAM address on DS1307 */
          I2C_write(dat);
          I2C_time_stop();
}
unsigned char DS1307_Read(unsigned char addr){
          unsigned int tm,ret;
          I2C_time_start(); /* time_start i2c bus */
          I2C_write(0xD0); /* Connect to DS1307 */
          I2C_write(addr); /* Requetime_5 RAM address on DS1307 */
          I2C_time_start(); /* time_start i2c bus */
          I2C_write(0XD1); /* Connect to DS1307 for Read */
          ret = I2C_read(); /* Receive data */
          I2C_time_stop();
          tm = ret; /*BCD to HEX*/
          ret = (((ret/16)*10)+ (tm & 0x0f)); /*for Led 7seg*/
          return ret;
}
void DS1307_Set(){
          //Ghi du lieu ngay gio vao DS1307
          DS1307_Write(DS1307_SEC,sec);
          DS1307_Write(DS1307_MIN,min);
          DS1307_Write(DS1307_HOUR,hour);
          DS1307_Write(DS1307_DATE,day);
          DS1307_Write(DS1307_MONTH,month);
          DS1307_Write(DS1307_YEAR,year);
}
void DS1307_GetTime(){
          //Doc du lieu gio tu DS1307
          hour=DS1307_Read(DS1307_HOUR);
          min=DS1307_Read(DS1307_MIN);
          sec=DS1307_Read(DS1307_SEC);
}
void DS1307_GetDate(){
          //Doc du lieu ngay tu DS1307
          day=DS1307_Read(DS1307_DATE);
          month=DS1307_Read(DS1307_MONTH);
          year=DS1307_Read(DS1307_YEAR);
}//End code DS1307


  • Bạn chưa đăng nhập, không thể viết bình luận!
    Bấm vào đây để Đăng nhập hoặc Đăng ký!
  • Vũ Văn Thái lúc 22-12-2016, 19:01
    Có mà bạn, đoạn 0xD0 là ghi, 0xD1 là đọc
  • nhthucdtvt lúc 22-12-2016, 12:19
    Sao không thấy code truyền địa chỉ DS1307 và chế độ R/W trước khi giao tiếp nhỉ?
  • Vũ Văn Thái lúc 06-04-2016, 16:07
    Bạn viết một hàm ghi một byte vào eeprom, rồi thêm một hàm bắn buffer vào bao nhiêu byte cũng lưu được
    • bizzuu lúc 08-04-2016, 09:35
      BẠn có thể cho mình một code như bạn nói để mình tham khảo với . Thanks
  • bizzuu lúc 06-04-2016, 15:53
    Làm sao để thêm byte vào đoạn code bên dưới vậy các bạn . Bản thân nó đã thêm 4 byte vào 24c04 bây giờ mình muốn thêm 5 hoặc 6 byte nữa thì phải làm sao ? Mình mới tập làm code c nên còn mờ quá . Mong sự giúp đỡ của các bạn

        void start(void) //dk start: 1 su cdoi tthai tu cao xuong thap tren duong sda trong khi
        {                        //duong scl dang o muc cao
          scl=1;
          sda=1;     
          _nop_();
          _nop_();
          sda=0;
          scl=0;
        }
    void stop(void)      //dk stop: 1 su cdoi trang thai tu muc thap len cao tren duong sda trong khi duong                       
        {                        // slc dang o muc cao
          sda=0;
          scl=1;
          _nop_();
          _nop_();
          sda=1;
          }
    bit write(unsigned char x)      // gui du lieu va nhan ACK
        {     
          unsigned char i;     
          for(i=0;i<8;i++)
             {
                sda=(x&0x80)? 1:0; //dua bit du lieu ra chan SDA
                scl=1;                                
             _nop_();
             _nop_();                    
                scl=0;
                x<<=1;                     //bit co trong so *ẩn* hon dc truyen truoc
             }
          sda=1;
          scl=1;                      //nhan bit ACK tu SLAVER      bao hieu ket thuc mot byte du lieu
          _nop_();
          _nop_();
          i=sda;
          scl=0;
          return i;
        }
    unsigned char read(bit ACK) // nhan du lieu va gui ACK
    {     
          unsigned char Data,i;     
          for(i=0;i<8;i++) // nhan vao 8 bit
            {
                scl=1;
                Data<<=1;
                Data=Data|sda;
                scl=0;
                }      
          sda=ACK;      // gui bit ACK=> sda=0
          scl=1; //master nhan/gui bit du lieu(sda) khi scl o muc cao
          _nop_();// lay mau du lieu
          scl=0;
          _nop_();//du lieu(sda) thay doi khi scl muc thap/
          sda=1;
          return Data;//tra gia tri cho ham
    }
    unsigned *ẩn*g read_24(unsigned char diachi)
    {      // doc 4 byte lien tiep tu 24c04
               
          unsigned *ẩn*g Data;
          diachi=diachi*4;
          start();
          write(0xa0);
          write(diachi);
          start();
          write(0xa1);
          Data = read(0);
          Data = (Data<< 8) + read(0);
          Data = (Data<< 8) + read(0);
          Data = (Data<< 8) + read(1);
          stop();//Stop I2C
          return Data;
    }
    void write_24(unsigned char diachi,unsigned *ẩn*g x)
    {      // ghi 4 byte lien tiep x vao 24c04     
          unsigned char d;
          diachi=diachi-4;
          start();
          write(0xa0);
          write(diachi);
          d = x>>24;
          write(d);
          d = x>>16;
          write(d);
          d = x>>8;
          write(d);
          d = x;
          write(d);
          stop();//Stop I2C
          delay(100);
    }
    void save_ram(void) // luu code tu 24c04 vao ram     
        {
        unsigned char i;
        for(i=0;i<6;i++)
              du_lieu[i] = read_24(i);
        }
    void save(void) // luu code tu ram vao 24c04     
        {
              write_24(number_code,data_);
          du_lieu[number_code/4 -1] = data_;     
          number_code=number_code +4;
          if( number_code >=24)     
            {
            number_code = 0;
            led = 1; // stop luu code.
            }
        }

    //                   CAC CHUONG TRINH CON GIAI MA REMOTE                   //
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
    void ngat_0 (void) interrupt 0            //ngat ngoai 0 ( remote )
        {   
        unsigned short do_rong_xung, min;
          {
          TR0 = 0;// stop timer 0
          if(step==0)// bit start
                {
                step = 1;
                data_=0;
                TL0 = max_start_0;
                TH0 = max_start_1;
                TR0 = 1;// khoi dong timer 0     
                }
          else if(step==1)// bit data
                {
                do_rong_xung = TH0-max_start_1;
                do_rong_xung = (do_rong_xung<<8) + TL0-max_start_0;
                min = min_start;
                if(do_rong_xung > min)
                {
                step = 2;
                TL0 = max_data_0;
                TH0 = max_data_1;
                TR0 = 1;// khoi dong timer 0     
                }
                else step = 0;
                }
          else if(step==2)// bit data
                {        
                do_rong_xung = TH0 - max_data_1 ;
                do_rong_xung = (do_rong_xung<<8) + TL0- max_data_0;
                TL0 = max_data_0;
                TH0 = max_data_1;
                TR0 = 1;// khoi dong timer 0
                data_=data_<<1; // bit 0
                if (do_rong_xung >      0x5DC) data_= data_+1;// neu do rong *ẩn* hong 1500us thi la bit 1     
                }}}
  • bizzuu lúc 06-04-2016, 15:51
    Làm sao để thêm byte vào đoạn code bên dưới vậy các bạn . Bản thân nó đã thêm 4 byte vào 24c04 bây giờ mình muốn thêm 5 hoặc 6 byte nữa thì phải làm sao ? Mình mới tập làm code c nên còn mờ quá . Mong sự giúp đỡ của các bạn


           /****************Khai báo chân giao tiep I2C***************************/
    #include "regx51.h"
    #define SCL      P0_0
    #define SDA      P0_1
    int hour,min,i,j,k;

    /****************Khai báo chân giao tiep I2C***************************/

    #define SCL      P0_3
    #define SDA      P0_2

    /****************Cac ham giao tiep I2C***************************/
    void I2C_time_start(){
                    SCL = 1;
                    SDA = 1;
                    SDA = 0;
                    SCL = 0;
    }
    void I2C_time_stop(){
                    SCL = 1;
                    SDA = 0;
                    SDA=1;
                    SCL=1;
    }
    unsigned char I2C_write(unsigned char dat){
                    unsigned char i;
                    for (i=0;i<8;i   {
                                   SDA = (dat & 0x80); ///? 1:0;
                                   SCL=1;
                                   SCL=0;
                                   dat<<=1;
                    }
                    SCL = 1;
                    SCL = 0;
                    return dat;
    }
    unsigned char I2C_read(void){
                    bit rd_bit;
                    unsigned char i, dat;
                    dat = 0x00;
                    for(i=0;i<8;i   { /* For loop read data 1 byte */
                                   SCL = 1;
                                   rd_bit = SDA; /* Keep for check acknowledge */
                                   dat = dat<<1;
                                   dat = dat | rd_bit; /* Keep bit data in dat */
                                   SCL = 0; /* Clear SCL */
                    }
                    return dat;
    }

    /***************Dia chi giao tiep DS1307*********************/

    #define DS1307_HOUR       0x02 //Gio
    #define DS1307_MIN         0x01 //Phut


    unsigned char DS1307_Read(unsigned char addr){
                    unsigned int tm,ret;
                    I2C_time_start(); /* time_start i2c bus */
                    I2C_write(0xD0); /* Connect to DS1307 */
                    I2C_write(addr); /* Requetime_5 RAM address on DS1307 */
                    I2C_time_start(); /* time_start i2c bus */
                    I2C_write(0XD1); /* Connect to DS1307 for Read */
                    ret = I2C_read(); /* Receive data */
                    I2C_time_stop();
                    tm = ret; /*BCD to HEX*/
                    ret = (((ret/16)*10)   (tm & 0x0f)); /*for Led 7seg*/
                    return ret;
    }
    void delay(unsigned char n){ // 10==>1s thach anh 12m
    while(n--)
    for ( i=1;i<100;i   
    for ( j=1;j<=165;j   ;}
    void delay_ms(unsigned int x){
    unsigned int TGIAN_TRE1;      
              while(x!=0)
                 {      
                 TGIAN_TRE1=121;
                 while(TGIAN_TRE1!=0)
                 {               
                                TGIAN_TRE1=TGIAN_TRE1-1;
                 }
                 x=x-1;
              }
    }
    void DS1307_GetTime(){
                    //Doc du lieu gio tu DS1307
                    hour=DS1307_Read(DS1307_HOUR);
                    min=DS1307_Read(DS1307_MIN);
    }

    int main(void)
           {            
                      P2=0X00;
                      while (1)
                       {
                       P0=0X00;
                       DS1307_GetTime();
                       if (min<59)
                             {
                             P2_0=1;
                             }
                       delay_ms(1000);
                       }
           }
  • DINHMINH lúc 08-10-2015, 23:37
    Cho mình hỏi bit ACK do DS1307 trả về cho 8051 được kiểm tra như thế nào?
  • thanhphuongdt2 lúc 16-04-2014, 18:23
    mình đang làm đồ án tốt nghiệp có liên quan đến thời gian thực, mình đang giả lập chu kì mặt trời. nên chỉ cần đọc dữ liệu từ con DS1307 thôi, chương trình mình test thử như sau, mô phỏng trên protues thì được nhưng test mạch thì nó không như mình mong muốn. bạn coi chương trình của mình có gì không đúng thì giúp mình với nghe cảm ơn nhiều


                 /****************Khai báo chân giao tiep I2C***************************/
    #include "regx51.h"
    #define SCL    P0_0
    #define SDA    P0_1
    int hour,min,i,j,k;

    /****************Khai báo chân giao tiep I2C***************************/

    #define SCL    P0_3
    #define SDA    P0_2

    /****************Cac ham giao tiep I2C***************************/
    void I2C_time_start(){
              SCL = 1;
              SDA = 1;
              SDA = 0;
              SCL = 0;
    }
    void I2C_time_stop(){
              SCL = 1;
              SDA = 0;
              SDA=1;
              SCL=1;
    }
    unsigned char I2C_write(unsigned char dat){
              unsigned char i;
              for (i=0;i<8;i ){
                       SDA = (dat & 0x80); ///? 1:0;
                       SCL=1;
                       SCL=0;
                       dat<<=1;
              }
              SCL = 1;
              SCL = 0;
              return dat;
    }
    unsigned char I2C_read(void){
              bit rd_bit;
              unsigned char i, dat;
              dat = 0x00;
              for(i=0;i<8;i ){ /* For loop read data 1 byte */
                       SCL = 1;
                       rd_bit = SDA; /* Keep for check acknowledge */
                       dat = dat<<1;
                       dat = dat | rd_bit; /* Keep bit data in dat */
                       SCL = 0; /* Clear SCL */
              }
              return dat;
    }

    /***************Dia chi giao tiep DS1307*********************/

    #define DS1307_HOUR    0x02 //Gio
    #define DS1307_MIN      0x01 //Phut


    unsigned char DS1307_Read(unsigned char addr){
              unsigned int tm,ret;
              I2C_time_start(); /* time_start i2c bus */
              I2C_write(0xD0); /* Connect to DS1307 */
              I2C_write(addr); /* Requetime_5 RAM address on DS1307 */
              I2C_time_start(); /* time_start i2c bus */
              I2C_write(0XD1); /* Connect to DS1307 for Read */
              ret = I2C_read(); /* Receive data */
              I2C_time_stop();
              tm = ret; /*BCD to HEX*/
              ret = (((ret/16)*10) (tm & 0x0f)); /*for Led 7seg*/
              return ret;
    }
    void delay(unsigned char n){ // 10==>1s thach anh 12m
    while(n--)
    for ( i=1;i<100;i )
    for ( j=1;j<=165;j );}
    void delay_ms(unsigned int x){
    unsigned int TGIAN_TRE1;   
          while(x!=0)
           {   
             TGIAN_TRE1=121;
             while(TGIAN_TRE1!=0)
             {         
                      TGIAN_TRE1=TGIAN_TRE1-1;
             }
             x=x-1;
          }
    }
    void DS1307_GetTime(){
              //Doc du lieu gio tu DS1307
              hour=DS1307_Read(DS1307_HOUR);
                  min=DS1307_Read(DS1307_MIN);
    }

    int main(void)
          {        
                   P2=0X00;
                   while (1)
                      {
                      P0=0X00;
                      DS1307_GetTime();
                      if (min<59)
                            {
                            P2_0=1;
                            }
                      delay_ms(1000);
                      }
          }
    • thanhphuongdt2 lúc 16-04-2014, 18:31
      cái định nghĩa SCL và SDA của bạn là P0_3 và P0_2 ở trên mình quên xóa. bạn đừng quan tâm cái đó nha.vì mình sữa lại rồi
  • giusetung71 lúc 27-02-2014, 13:19
    quá tuyệt vời, xin cảm ơn bạn rất nhiều
  • mrcuongntu lúc 17-02-2014, 10:32
    rất cảm ơn
  • Trang 1/1: 1

    Bài viết cùng chuyên mục
    Điều khiển tốc độ động cơ Motor DC sử dụng PWM Điều khiển tốc độ động cơ Motor DC sử dụng PWM
    Đăng bởi: kienvuce - Thời gian: 04-11-2021, 22:40
    Chuyên mục: Học lập trình 8051 - Lượt xem: 3.035
    Chia sẻ bộ thư viện Driver chuẩn cho LCD Gphone và Home Phone Chia sẻ bộ thư viện Driver chuẩn cho LCD Gphone và Home Phone
    Đăng bởi: Vũ Văn Thái - Thời gian: 22-02-2017, 14:54
    Chuyên mục: Học lập trình 8051 - Lượt xem: 6.597
    Led 7 thanh 4 số điều khiển bằng nút bấm Led 7 thanh 4 số điều khiển bằng nút bấm
    Đăng bởi: HoangQuan69 - Thời gian: 09-10-2016, 15:08
    Chuyên mục: Học lập trình 8051 - Lượt xem: 5.842
    Chia sẻ Code đồng hồ số hiển thị trên LED 7 đoạn dùng 89S52 và DS1307 Chia sẻ Code đồng hồ số hiển thị trên LED 7 đoạn dùng 89S52 và DS1307
    Đăng bởi: Vũ Văn Thái - Thời gian: 13-05-2015, 09:00
    Chuyên mục: Học lập trình 8051 - Lượt xem: 28.578
    Bài 15: Lập trình quét phím matrix 4x4 hiển thị lên LCD 16x2 Bài 15: Lập trình quét phím matrix 4x4 hiển thị lên LCD 16x2
    Đăng bởi: Vũ Văn Thái - Thời gian: 20-11-2014, 08:57
    Chuyên mục: Học lập trình 8051 - Lượt xem: 31.515
    [Share] Code giao tiếp Graphic LCD 12864 SPI của máy GPHONE ZTE [Share] Code giao tiếp Graphic LCD 12864 SPI của máy GPHONE ZTE
    Đăng bởi: Vũ Văn Thái - Thời gian: 12-11-2014, 22:06
    Chuyên mục: Học lập trình 8051 - Lượt xem: 19.211
    [Share] Code C đo nhiệt độ dùng DS18B20 hiển thị lên LED 7 thanh [Share] Code C đo nhiệt độ dùng DS18B20 hiển thị lên LED 7 thanh
    Đăng bởi: Vũ Văn Thái - Thời gian: 12-11-2014, 09:02
    Chuyên mục: Học lập trình 8051 - Lượt xem: 19.496
    Bài 14: Đo nhiệt độ dùng cảm biến DS18B20 với 8051 Bài 14: Đo nhiệt độ dùng cảm biến DS18B20 với 8051
    Đăng bởi: Vũ Văn Thái - Thời gian: 19-10-2014, 10:11
    Chuyên mục: Học lập trình 8051 - Lượt xem: 25.312
    Bài 13: Đo nhiệt độ dùng LM35 kết hợp IC ADC0808 với 8051 Bài 13: Đo nhiệt độ dùng LM35 kết hợp IC ADC0808 với 8051
    Đăng bởi: Vũ Văn Thái - Thời gian: 22-08-2014, 22:18
    Chuyên mục: Học lập trình 8051 - Lượt xem: 45.860
    Bài 12: Tạo xung PWM dùng ngắt timer 8051 Bài 12: Tạo xung PWM dùng ngắt timer 8051
    Đăng bởi: Vũ Văn Thái - Thời gian: 02-03-2014, 20:45
    Chuyên mục: Học lập trình 8051 - Lượt xem: 24.001
    
    Chào mừng Hungnguyen123 đã tham gia câu lạc bộ sáng tạo!
    Vũ Văn Thái - vuthai
    Hôm nay là sinh nhật của ngoisao_bang1016, nguyenngoctram, thaospkt2012, hugo_8x, baodtcn, thanhphong, nguyenphuongnam, Hoan123, Forget, ← Gửi tin nhắn chúc mừng
    Múi giờ: UTC+07:00 - Asia/Ho Chi Minh ***** IP của bạn: 35.170.66.78 ***** Status: Cache Update thành công!