IIC詳解,包括原理、過程,最后一步步教你實現IIC


1、I2C總線具有兩根雙向信號線,一根是數據線SDA,另一根是時鍾線SCL  
 
 
2、IIC總線上可以掛很多設備:多個主設備,多個從設備(外圍 設備)。上圖中主設備是兩個單片機,剩下的都是從設備。 
 
3、多主機會產生總線裁決問題。當多個主機同時想占用總線時,企圖啟動總線傳輸數據,就叫做總線競爭。I2C通過總線仲裁,以決定哪台主機控制總線
 
4、上拉電阻一般在4.7k~10k之間
       
 
5、每個接到I2C總線上的器件都有唯一的地址。主機與其它器件間的數據傳輸可以是由主機發送數據到其它器件,這時主機 即為發送器,總線上收數據的器件則為接收器。
 
6、I2C總線的數據傳送:
     (1)、數據位的有效性規定:
          
 
      (2)、起始與終止信號:SCL為高期間,
             SDA : 由高到低,起始信號
             SDA:由低到高,終止信號
            
 
7、起始信號和終止信號都是由主機發送的。在起始信號產生之后,總線就處於被占用的狀態,在終止信號產生之后,總線就處於空閑狀態。
 
8、連接到I2C總線上的器件,若具有I2C總線的硬件接口,則很容易檢測到起始和終止信號。
 
9、每當發送器傳輸完一個字節的數據之后,發送端會等待一定的時間,等接收方的應答信號。接收端通過拉低SDA數據線,給發送端發送一個應答信號,以提醒發送端我這邊已經接受完成,數據可以繼續傳輸,接下來,發送端就可以繼續發送數據了。
 
10、數據傳送格式:主機發送給從機
        
    
 
11、I2C模擬方式 的特殊情況:
      
 
12、總線尋址:
       (1)、主機向從機發送8位數據,這8位數據是在起始信號之后發送的第一個字節,后面的字節都是數據,不再是尋址,除非又重新來一個起始信號。
         
    
     (2)、主機給從機發送第一個字節(總線尋址那個字節),若是讀命令,則從機接收到該 命令之后,主動往主機發送數據。
     
     (3)、主機發送地址時,總線上的每個從機都將這7位地址碼與自己的地址進行比較,若相同,則認為自己正在被主機尋址,根據R/T位將自己確定為發送器和接收器
 
     (4)、從機地址的確定:第0位是讀寫位。(如對於24C02這塊存儲器,它若作為從機,那么它的地址中7~4位是固定的,更改不了,第3~1位是可以更改的,每一位根據硬件的管教連接來確定,連接高電平那就是1,低電平就是0)
             
 
13、在起始信號后必須傳送一個從機的地址(7位),第8位是數據的傳送方向位(R/T),用“0”表示主機發送數據(T),“1”表示主機接收數據(R)。
 
14、每次數據傳送總是由主機產生的終止信號來結束。但是,若主機希望繼續占用總線進行新的數據傳送,則可以不產生終止信號,馬上再次發出起始信號對另一從機進行尋址。
 
15、在總線的一次數據傳輸中,可以有一下幾種組合方式:
 
       (1)、主機向從機發送數據,數據傳送方向在整個傳遞過程中不變:
        
 
        (2)、主機在第一個字節后,立即從從機讀數據(傳輸方向不變):
                
 
         (3)、在傳送過程中,當需要改變傳遞方向時,起始信號和從機地址都被重復一次產生一次,但兩次讀/寫方向位正好相反
                 
 
16、時序:
       
 
注:主機做的都是編程控制,從機做的都是自主控制,也可以說是硬件控制,如主機給應答信號是編程控制,但是從機給應答信號是硬件控制,我們只需要檢查在SDA為高期間,SCL保持低電平一些時間,即可判定從機給了主機應答信號。
 
17、模擬IIC編程
       (1)、開引腳的時鍾:RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
       (2)、宏定義: 
    • #define I2C_SCL    GPIO_Pin_6
    • #define I2C_SDA   GPIO_Pin_7
    • #define GPIO_I2C  GPIOB
    • #define I2C_SCL_H GPIO_SetBits(GPIO_I2C, I2C_SCL)  //把PB6置高
    • #define I2C_SCL_L  GPIO_ResetBits(GPIO_I2C, I2C_SCL)  //把PB6置低
    • #define I2C_SDA_H  GPIO_ResetBits(GPIO_I2C, I2C_SDA)  //把PB7置高
    • #define I2C_SCL_L  GPIO_ResetBits(GPIO_I2C, I2C_SDA)  //把PB7置低
      
        (3)、配置函數
               void I2C_Init(void)
               {
                    GPIO_InitTypeDef GPIO_InitStructure;
 
                    GPIO_InitStructure.GPIO_Pin=I2C_SCL | I2C_SDA;
                    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
                    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;  //推挽輸出模式
                    GPIO_Init(GPIOB,&GPIO_InitStructure);
               }
 
       (4)、SDA有輸出方向和輸入方向,配置SDA的這兩個模式:
               
               void I2C_OUT(void)    //SDA是輸出方向
               {
                    GPIO_InitTypeDef GPIO_InitStructure;
 
                    GPIO_InitStructure.GPIO_Pin=I2C_SDA;
                    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
                    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;  //推挽輸出模式
                    GPIO_Init(GPIOB,&GPIO_InitStructure);
 
                    I2C_SCL_H;
                    I2C_SDA_H;   //把兩條線都變成高電平
                }
 
                void I2C_IN(void)    //SDA是輸入方向
                {
                    GPIO_InitTypeDef GPIO_InitStructure;
 
                    GPIO_InitStructure.GPIO_Pin=I2C_SDA;
                    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
                    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_IPU;  //輸入上拉模式
                    GPIO_Init(GPIOB,&GPIO_InitStructure);
                }
 
          (5)、產生起始信號:  看上面的時序圖寫
                 void I2C_Start(void)  //在SCL高電平,SDA由高到低,在此之前,SDA的高電平必須保持>4.7us,起始信號變成低電平之后,還要延時>4us
               {
                    I2C_SDA_OUT();    //SDA是輸出方向,即由主機發送的
                    I2C_SDA_H;
                    I2C_SCL_H;
                    delay_us(5);    //延時5個微妙
                    I2C_SDA_L;  //起始信號
                    delay_us(5);
                    I2C_SCL_L;
               }
 
          (6)、主機產生停止信號:
                void I2C_Stop(void)
               {
                    I2C_SDA_OUT(); 
 
                    I2C_SCL_L;
                    I2C_SDA_L;
                    I2C_SCL_H;                   
                    delay_us(5);
 
                    I2C_SDA_H;
                    delay_us(5);
               }
 
          (7)、主機產生應答信號:
                 void I2C_ACK(void)
                 {
                     I2C_SDA_OUT();
 
                     I2C_SCL_L;
                     I2C_SDA_L;
                     delay_us(2);
                     I2C_SCL_H;
                     delay_us(5);
                     I2C_SCL_L;
       //           I2C_SDA_H;
                 }
 
          (8)、主機不發送應答信號:
                void I2C_NACK(void)
               {
                    I2C_SDA_OUT();
 
                    I2C_SCL_L;
                    I2C_SDA_H;
                    delay_us(2);
                    I2C_SCL_H;
                    delay_us(5);
                    I2C_SCL_L;
               }
 
          (9)、等待信號,當發送器發送一個數據之后,需要等待從接收端發過來的應答信號,主機等待從機應答
             
 
                 u8 I2C_Wait_ACK(void)    //SDA為低電平時,表明從機給了應答
                {
                    int time=0;   //計數器
 
                    I2C_SDA_IN();  //表明是從機的SDA
                    I2C_SDA_H;
                    delay_us((1);
                    I2C_SCL_H;
                    delay_us(1);
 
                    while(GPIO_ReadInputDataBit(GPIO_I2C,I2CC_SDA))   //等待應答信號
                    {
                         time++;
                         if(time>250)  //等待時間過長,產生停止信號,返回1,表示接收應答失敗
                         {
                              I2C_Stop();
                              return 1;
                         }
 
                         //應答成功,則SCL變低
                         I2C_SCL_L;
                         return 0;                       
                    }
                }
 
          (10)、主機發送一個字節的數據,從高位開始發送。SCL位高電平的時候,數據必須保持穩定,所以可以在SCL為低電平時組織數據,SCL為高電平時發送或者接收數據
                    void send_Byte(u8 data)
                    {
                          I2C_SDA_OUT();
                         //數據准備
                         I2C_SCL_L;
                         delay_us(2);
                         for(int i=0;i<8;i++)   //從高位開始一位一位地傳送
                         {
                              //發數據放到數據線上
                              if((data & 0x80)>0)  //當前的最高位為1
                                   I2C_SDA_H;   //拉高數據線
                              else
                                   I2C_SDA_L;
                              
                              data<<1;   //數據左移一位
 
                              //開始發送數據
                              I2C_SCL_H;
                              delay_us(2);
                              
                              //上一個數據發送完畢,為下一個數據發送准備
                              I2C_SCL_L;
                              delay_us(2);
                        }
                    }
 
          (11)、主機接收一個字節數據
                    u8 rev_Byte(u8 ack)
                    {
                         u8 rev_Data;  //接收到的數據
 
                         I2C_SDA_IN();
 
                         for(int i=0;i<8;i++)
                         {
                              //數據准備 
                              I2C_SCL_L;
                              delay_us(2);
                              I2C_SCL_H;   //主機開始讀數據,從機不能再改變數據了,即改變SDA的電平
                              if(GPIO_ReadInputDataBit(GPIO_I2C,I2CC_SDA) )  //接收到的是1
                                   rev_Data++;
                              rev_Data<<1;
                              delay_us(1);
                          }
 
                         if(ack==0)  //說明主機不需要給從機應答
                              I2C_NACK();
                         else                 //主機需要給應答
                              I2C_ACK();  
 
                         return rec_Data;
                     }

轉自:IIC時序詳解——http://blog.csdn.net/drivermonkey/article/details/7695547

AT24C02是由ATMEL公司提供的,IIC總線串行EEPROM(electronic eraser programmer read only memory),其容量為2kbit(256B),工作電壓在2.7v"5.5v之間,生產工藝是CMOS。  


  
一般數字芯片都在左下角和右上角為GND,VCC。容量的計算方法:AT24Cxx :01"1024  
容量 = xx * 1kbit。  

寫入過程:  

AT24C系列EEPROM芯片的固定部分為1010,A2,A1,A0引腳接高低電平后得到確定的3位編碼,形成7位編碼即為該器件的地址碼。  

單片機進行寫操作時,首先發送該器件的7位地址碼和寫方向位”0”(共8位,即一個字節),發送完后釋放SDA線並在SCL線上產生第9個時鍾信號。被選中的存儲器器件在確認是自己的地址后,在SDA線上產生一個應答信號作為響應,單片機收到應答后就可以傳送數據了。傳送數據時,單片機首先發送一個字節的被寫入存儲器的首地址,收到存儲器器件的應答后,單片機就逐個發送數據字節,但每發送一個字節后都要等待應答。AT24C系列片內地址在接收到每一個數據字節地址后自動加1,在芯片的“一次裝載字節數”限度內,只需輸入首地址。裝載字節數超過芯片的“一次裝載字節數”時,數據地址將“上卷”,前面的數據將被覆蓋。  


  
  
字節寫:  


   
  
頁寫:  


   
讀入過程:   

單片機先發送該器件的7位地址碼和寫方向位“0”(“偽寫”),發送完后釋放SDA線並在SCL線上產生第9個時鍾信號。被選中的存儲器器件在確認是自己的地址后,在SDA線上產生一個應答信號作為回應。      

然后,再發一個字節的要讀出器件的存儲區的首地址,收到應答后,單片機要重復一次起始信號並發出器件地址和讀方向位(“1”),收到器件應答后就可以讀出數據字節,每讀出一個字節,單片機都要回復應答信號。當最后一個字節數據讀完后,單片機應返回以“非應答”(高電平),並發出終止信號以結束讀出操作。   


  
當前地址讀:   


   
  
隨機讀:  


   
  
有序讀:  


   
  
IIC總線模擬時序圖:  


   
IIC總線應答時序圖:  


  
設備地址:  


   
寫周期:  


   

兩次寫之間要有一個10ms的twR間隔  

轉自:http://bbs.21ic.com/icview-236765-1-1.html

 

終於弄出來了,用IO口模擬的,但是最后一位不知道為什么總是為0呢
#include<avr/io.h>

#define uint unsigned int
#define uchar unsigned char
#define BIT(x) (1<<x)

//PORTA0=SCL
//PORTA1=SDA
void delay1(uint n)
{  uint i,j;
for(i=0;i<n;i++)
        for(j=0;j<367;j++);
}

void delay()
{  asm("NOP"); asm("NOP");asm("NOP"); }

void start()  //開始信號
{        
        PORTA|=BIT(1);
        delay();
        PORTA|=BIT(0);
        delay(); asm("NOP");asm("NOP");
        PORTA&=~BIT(1);
        delay(); asm("NOP");asm("NOP");
        PORTA&=~BIT(0);
    delay();

}

void stop()   //停止
{
        PORTA&=~BIT(1);
        delay();
        PORTA|=BIT(0);
        delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP");
        PORTA|=BIT(1);
        delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP");
}

void respons()  //應答
{
        //uchar i;
        PORTA&=~BIT(1);
        delay();
        PORTA|=BIT(0);
        delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP");
        PORTA&=~BIT(0);
        delay();

}

/*
void respons_send()  //應答
{
        uchar i;
        PORTA|=BIT(0);
        delay();
        
        while(((PORA&BIT(1))==1)&&(i<250))i++;
        PORTA&=~BIT(0);
        delay();
}
*/

void init()
{
        PORTA|=BIT(1);
        delay();
        PORTA|=BIT(0);
        delay();
}

void write_byte(uchar date)
{
        uchar i,temp;
        
  for(i=0;i<8;i++)  //要傳送的數據長度為8位
    {
     if((date<<i)&0x80)
         PORTA|=BIT(1);  //判斷發送位
       else  PORTA&=~BIT(1);               
      delay();
     PORTA|=BIT(0);               //置時鍾線為高,通知被控器開始接收數據位
     delay(); delay();           //在此期間取走數據
     PORTA&=~BIT(0);
         delay(); delay();   
    }

    PORTA&=~BIT(0);
        delay();
        PORTA|=BIT(1);
        delay();
}

uchar read_byte()
{
        uchar i,k,temp=0;
        PORTA&=~BIT(0);
        delay();
        PORTA|=BIT(1);   //釋放數據線SDA
        delay();

        for(i=0;i<8;i++)
        {
                PORTA|=BIT(0);
                delay();
                DDRA&=~BIT(1);
                PORTA|=BIT(1);
                        
                delay();
                temp=(PINA&0x02);
                k=((k<<1)|temp);
        //        DDRA|=BIT(1);

                PORTA&=~BIT(0);
                delay();        
        }

        DDRA|=BIT(1);
        delay();

        return k;
}

void write_add(uchar address,uchar date)
{
        start();
        write_byte(0x56);
        respons();
        write_byte(address);
        respons();
        write_byte(date);
        respons();
        stop();
}

uchar read_add(uchar address)
{
        uchar date;
        start();
        write_byte(0x57);
        respons();
        write_byte(address);
        respons();
        date=read_byte();
        stop();
        return date;
}

main()
{
    DDRA=0xff;
        DDRB=0xFF;


    init();
        write_add(0x03,0x3f);
        delay();
        write_add(0x00,0x41);
    delay(1);
        write_add(0x08,0xab);
        delay1(10);

        PORTB=read_add(0x08);
        delay();
//        PORTB=0XFF;

        delay();

        while(1);
}

 

 

 
 
 

轉自:AVR模擬IIC總線-https://download.csdn.net/download/iamfengpeng/1913080

#include  <iom128.h>
 
#include  <stdio.h>
#include  "iic.h"
 
#define uchar unsigned char
 
#define uint unsigned int
/********************************************************************
  此程序是I2C操作平台(主方式的軟件平台)的底層的C子程序,如發送數據
及接收數據,應答位發送,並提供了幾個直接面對器件的操作函數,它很方便的
與用戶程序連接並擴展.....
    注意:函數是采用軟件延時的方法產生SCL脈沖,固對高晶振頻率要作
一定的修改....(本例是1us機器周期,即晶振頻率要小於12MHZ)
********************************************************************/
 
#define  uchar unsigned char /*宏定義*/
#define  uint  unsigned int
 
#define  _Nop()  asm("nop")        /*定義空指令*/
 
/* 常,變量定義區 */
 
                                                 /*端口位定義*/
#define SDA  PORTA_Bit1           /*模擬I2C數據傳送位*/
#define SCL  PORTA_Bit0           /*模擬I2C時鍾控制位*/
#define SDA_pin DDRA_Bit1          /*SDA輸入輸出*/
#define SCL_pin DDRA_Bit0
#define SDA_in PINA_Bit1
 
#define iic_delay() delay_us(1)        // 根據系統時鍾進行調整
 
uchar TAB_T[]={ 0x31,0x06,0x10,//秒,分,時
 
0x13,0x01,0x07,0x08};//日,星期,月,年.
 
void	delay_us( uchar us )
{
	uchar dly;
    while ( us -- )
    {
        for(dly=0;dly<8;dly++);
    }
}
                                                 /*狀態標志*/
uchar ack;	         /*應答標志位*/
 
/*******************************************************************
                     起動總線函數
函數原型: void  Start_I2c();
功能:       啟動I2C總線,即發送I2C起始條件.
********************************************************************/
void Start()
{
 
    SCL_pin=0;
    SDA_pin=0;
    SDA=1;      /*發送起始條件的數據信號*/
    _Nop();
    SCL=1;
    iic_delay();/*起始條件建立時間大於4.7us,延時*/
    SDA_pin=1;
    SDA=0;      /*發送起始信號*/
    iic_delay();/* 起始條件鎖定時間大於4μs*/
    SCL=0;      /*鉗住I2C總線,准備發送或接收數據 */
    SCL_pin=1;
    iic_delay();
}
/*******************************************************************
                      結束總線函數
函數原型: void  Stop_I2c();
功能:       結束I2C總線,即發送I2C結束條件.
********************************************************************/
void Stop()
{
    SDA=0;          /*發送結束條件的數據信號*/
    SDA_pin=1;
    iic_delay();    /*發送結束條件的時鍾信號*/
    SCL_pin=0;
    SCL=1;
    iic_delay();    /*結束條件建立時間大於4μs*/
    SDA_pin=0;
    SDA=1;          /*發送I2C總線結束信號*/
    iic_delay();
}
/*******************************************************************
                 字節數據傳送函數
函數原型: void  SendByte(uchar c);
功能:  將數據c發送出去,可以是地址,也可以是數據,發完后等待應答,並對
     此狀態位進行操作.(不應答或非應答都使ack=0 假)
     發送數據正常,ack=1; ack=0表示被控器無應答或損壞。
********************************************************************/
void  WriteByte(uchar c)
{
    uchar BitCnt;
 
    for(BitCnt=0;BitCnt<8;BitCnt++)  /*要傳送的數據長度為8位*/
    {
        if((c<<BitCnt)&0x80)
        {
            SDA_pin=0;
            SDA=1;   /*判斷發送位*/
        }
        else
        {
            SDA=0;
            SDA_pin=1;
        }
        _Nop();
        SCL_pin=0;
        SCL=1;               /*置時鍾線為高,通知被控器開始接收數據位*/
        iic_delay();         /*保證時鍾高電平周期大於4μs*/
        SCL=0;
        SCL_pin=1;
 
    }
 
    iic_delay() ;
    SDA_pin=0;
    SDA=1;               /*8位發送完后釋放數據線,准備接收應答位*/
    iic_delay() ;
    SCL_pin=0;
    SCL=1;
    iic_delay();
    if(SDA_in==1)
        ack=0;
    else
        ack=1;        /*判斷是否接收到應答信號*/
    SCL=0;
    SCL_pin=1;
    iic_delay() ;
}
 
/*******************************************************************
                 字節數據傳送函數
函數原型: uchar  RcvByte();
功能:  用來接收從器件傳來的數據,並判斷總線錯誤(不發應答信號),
     發完后請用應答函數。
********************************************************************/	
uchar  ReadByte()
{
    uchar retc;
    uchar BitCnt;
 
    retc=0;
    SDA_pin=0;
    SDA=1;             /*置數據線為輸入方式*/
    for(BitCnt=0;BitCnt<8;BitCnt++)
    {
        SCL=0;       /*置時鍾線為低,准備接收數據位*/
        SCL_pin=1;
        iic_delay();  /*時鍾低電平周期大於4.7μs*/
        SCL_pin=0;
        SCL=1;       /*置時鍾線為高使數據線上數據有效*/
        iic_delay();
        retc=retc<<1;
        if(SDA_in==1)retc=retc+1; /*讀數據位,接收的數據位放入retc中 */
            iic_delay();
    }
    SCL=0;
    SCL_pin=1;
    iic_delay();
    return(retc);
}
 
 
 
 
/********************************************************************
                     應答子函數
原型:  void Ack_I2c(bit a);
功能:主控器進行應答信號,(可以是應答或非應答信號)
********************************************************************/
void Ack_I2c(uchar a)
{
    if(a==0)
    {
        SDA_pin=1;
        SDA=0;     /*在此發出應答或非應答信號 */
    }
    else
    {
        SDA_pin=0;
        SDA=1;
    }
    iic_delay();
    SCL_pin=0;
    SCL=1;
    iic_delay();   /*時鍾低電平周期大於4μs*/
    iic_delay();
    SCL=0;         /*清時鍾線,鉗住I2C總線以便繼續接收*/
    SCL_pin=1;
    iic_delay();
}
 
 
 
void Write8563(uchar ucAddr,uchar ucData)
 
{
 
    Start();
 
    WriteByte(0xa2);
 
    WriteByte(ucAddr);
 
    WriteByte(ucData);
 
    Stop();
 
}
 
 
uchar Read8563(uchar ucAddr)
 
{
 
    uchar ucData;
 
    Start();
 
    WriteByte(0xa2); //寫器件地址
 
    WriteByte(ucAddr); //寫字節地址
 
    Start();
 
    WriteByte(0xa3); //寫器件地址,最低為1表示讀
 
    ucData=ReadByte(); //寫字節地址
 
    Stop();
 
    return ucData; //讀數據
 
}
 
 
void Init8563(void)
 
{
 
    uchar i,ucAddr=0x02;
 
    Write8563(0x0d,0x80);
    i = Read8563(0x0D);
    Write8563(0x00,0x00);
    Write8563(0x01,0x11);
 
    i = Read8563(0x00);
    i = Read8563(0x01);
 
    for(i=0;i<7;i++)
 
    {
 
        Write8563(ucAddr,TAB_T[i]);
 
        ucAddr++;
 
    }
 
}
 
 
void GetTime(void)
 
{
 
    uchar i,ucData1,ucData2,ucAddr=0x02;
 
    uchar *pTime=TAB_T;
 
    for(i=0;i<7;i++)
 
    {
 
        pTime[i]=Read8563(ucAddr);
 
        ucAddr++;
 
    }
 
    pTime[0]&=0x7f; //屏蔽無效位
 
    pTime[1]&=0x7f;
 
    pTime[2]&=0x3f;
 
    pTime[3]&=0x3f;
 
    pTime[4]&=0x07;
 
    pTime[5]&=0x1f;
 
// for(i=0;i<7;i++)
//
// {
//
// ucData1=pTime[i]/16; //BCD碼轉十六進制
//
// ucData2=pTime[i]%16;
//
// pTime[i]=ucData1*10+ucData2;
//
// }
 
}
 
/*    完畢      */

  

轉自:http://bbs.21ic.com/icview-236765-1-1.html

 

終於弄出來了,用IO口模擬的,但是最后一位不知道為什么總是為0呢
#include<avr/io.h>

#define uint unsigned int
#define uchar unsigned char
#define BIT(x) (1<<x)

//PORTA0=SCL
//PORTA1=SDA
void delay1(uint n)
{  uint i,j;
for(i=0;i<n;i++)
        for(j=0;j<367;j++);
}

void delay()
{  asm("NOP"); asm("NOP");asm("NOP"); }

void start()  //開始信號
{        
        PORTA|=BIT(1);
        delay();
        PORTA|=BIT(0);
        delay(); asm("NOP");asm("NOP");
        PORTA&=~BIT(1);
        delay(); asm("NOP");asm("NOP");
        PORTA&=~BIT(0);
    delay();

}

void stop()   //停止
{
        PORTA&=~BIT(1);
        delay();
        PORTA|=BIT(0);
        delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP");
        PORTA|=BIT(1);
        delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP");
}

void respons()  //應答
{
        //uchar i;
        PORTA&=~BIT(1);
        delay();
        PORTA|=BIT(0);
        delay();asm("NOP");asm("NOP");asm("NOP");asm("NOP");
        PORTA&=~BIT(0);
        delay();

}

/*
void respons_send()  //應答
{
        uchar i;
        PORTA|=BIT(0);
        delay();
        
        while(((PORA&BIT(1))==1)&&(i<250))i++;
        PORTA&=~BIT(0);
        delay();
}
*/

void init()
{
        PORTA|=BIT(1);
        delay();
        PORTA|=BIT(0);
        delay();
}

void write_byte(uchar date)
{
        uchar i,temp;
        
  for(i=0;i<8;i++)  //要傳送的數據長度為8位
    {
     if((date<<i)&0x80)
         PORTA|=BIT(1);  //判斷發送位
       else  PORTA&=~BIT(1);               
      delay();
     PORTA|=BIT(0);               //置時鍾線為高,通知被控器開始接收數據位
     delay(); delay();           //在此期間取走數據
     PORTA&=~BIT(0);
         delay(); delay();   
    }

    PORTA&=~BIT(0);
        delay();
        PORTA|=BIT(1);
        delay();
}

uchar read_byte()
{
        uchar i,k,temp=0;
        PORTA&=~BIT(0);
        delay();
        PORTA|=BIT(1);   //釋放數據線SDA
        delay();

        for(i=0;i<8;i++)
        {
                PORTA|=BIT(0);
                delay();
                DDRA&=~BIT(1);
                PORTA|=BIT(1);
                        
                delay();
                temp=(PINA&0x02);
                k=((k<<1)|temp);
        //        DDRA|=BIT(1);

                PORTA&=~BIT(0);
                delay();        
        }

        DDRA|=BIT(1);
        delay();

        return k;
}

void write_add(uchar address,uchar date)
{
        start();
        write_byte(0x56);
        respons();
        write_byte(address);
        respons();
        write_byte(date);
        respons();
        stop();
}

uchar read_add(uchar address)
{
        uchar date;
        start();
        write_byte(0x57);
        respons();
        write_byte(address);
        respons();
        date=read_byte();
        stop();
        return date;
}

main()
{
    DDRA=0xff;
        DDRB=0xFF;


    init();
        write_add(0x03,0x3f);
        delay();
        write_add(0x00,0x41);
    delay(1);
        write_add(0x08,0xab);
        delay1(10);

        PORTB=read_add(0x08);
        delay();
//        PORTB=0XFF;

        delay();

        while(1);
}

轉自:AVR模擬IIC總線-https://download.csdn.net/download/iamfengpeng/1913080

  1.  
    #include <iom128.h>
  2.  
     
  3.  
    #include <stdio.h>
  4.  
    #include "iic.h"
  5.  
     
  6.  
    #define uchar unsigned char
  7.  
     
  8.  
    #define uint unsigned int
  9.  
    /********************************************************************
  10.  
    此程序是I2C操作平台(主方式的軟件平台)的底層的C子程序,如發送數據
  11.  
    及接收數據,應答位發送,並提供了幾個直接面對器件的操作函數,它很方便的
  12.  
    與用戶程序連接並擴展.....
  13.  
     
  14.  
    注意:函數是采用軟件延時的方法產生SCL脈沖,固對高晶振頻率要作
  15.  
    一定的修改....(本例是1us機器周期,即晶振頻率要小於12MHZ)
  16.  
     
  17.  
    ********************************************************************/
  18.  
     
  19.  
    #define uchar unsigned char /*宏定義*/
  20.  
    #define uint unsigned int
  21.  
     
  22.  
    #define _Nop() asm("nop") /*定義空指令*/
  23.  
     
  24.  
    /* 常,變量定義區 */
  25.  
     
  26.  
    /*端口位定義*/
  27.  
    #define SDA PORTA_Bit1 /*模擬I2C數據傳送位*/
  28.  
    #define SCL PORTA_Bit0 /*模擬I2C時鍾控制位*/
  29.  
    #define SDA_pin DDRA_Bit1 /*SDA輸入輸出*/
  30.  
    #define SCL_pin DDRA_Bit0
  31.  
    #define SDA_in PINA_Bit1
  32.  
     
  33.  
    #define iic_delay() delay_us(1) // 根據系統時鍾進行調整
  34.  
     
  35.  
    uchar TAB_T[]={ 0x31, 0x06, 0x10, //秒,分,時
  36.  
     
  37.  
    0x13, 0x01, 0x07, 0x08}; //日,星期,月,年.
  38.  
     
  39.  
    void delay_us( uchar us )
  40.  
    {
  41.  
    uchar dly;
  42.  
    while ( us -- )
  43.  
    {
  44.  
    for(dly= 0;dly< 8;dly++);
  45.  
    }
  46.  
    }
  47.  
    /*狀態標志*/
  48.  
    uchar ack; /*應答標志位*/
  49.  
     
  50.  
    /*******************************************************************
  51.  
    起動總線函數
  52.  
    函數原型: void Start_I2c();
  53.  
    功能: 啟動I2C總線,即發送I2C起始條件.
  54.  
     
  55.  
    ********************************************************************/
  56.  
    void Start()
  57.  
    {
  58.  
     
  59.  
    SCL_pin= 0;
  60.  
    SDA_pin= 0;
  61.  
    SDA= 1; /*發送起始條件的數據信號*/
  62.  
    _Nop();
  63.  
    SCL= 1;
  64.  
    iic_delay(); /*起始條件建立時間大於4.7us,延時*/
  65.  
    SDA_pin= 1;
  66.  
    SDA= 0; /*發送起始信號*/
  67.  
    iic_delay(); /* 起始條件鎖定時間大於4μs*/
  68.  
    SCL= 0; /*鉗住I2C總線,准備發送或接收數據 */
  69.  
    SCL_pin= 1;
  70.  
    iic_delay();
  71.  
    }
  72.  
    /*******************************************************************
  73.  
    結束總線函數
  74.  
    函數原型: void Stop_I2c();
  75.  
    功能: 結束I2C總線,即發送I2C結束條件.
  76.  
    ********************************************************************/
  77.  
    void Stop()
  78.  
    {
  79.  
    SDA= 0; /*發送結束條件的數據信號*/
  80.  
    SDA_pin= 1;
  81.  
    iic_delay(); /*發送結束條件的時鍾信號*/
  82.  
    SCL_pin= 0;
  83.  
    SCL= 1;
  84.  
    iic_delay(); /*結束條件建立時間大於4μs*/
  85.  
    SDA_pin= 0;
  86.  
    SDA= 1; /*發送I2C總線結束信號*/
  87.  
    iic_delay();
  88.  
    }
  89.  
    /*******************************************************************
  90.  
    字節數據傳送函數
  91.  
    函數原型: void SendByte(uchar c);
  92.  
    功能: 將數據c發送出去,可以是地址,也可以是數據,發完后等待應答,並對
  93.  
    此狀態位進行操作.(不應答或非應答都使ack=0 假)
  94.  
    發送數據正常,ack=1; ack=0表示被控器無應答或損壞。
  95.  
    ********************************************************************/
  96.  
    void WriteByte(uchar c)
  97.  
    {
  98.  
    uchar BitCnt;
  99.  
     
  100.  
    for(BitCnt= 0;BitCnt< 8;BitCnt++) /*要傳送的數據長度為8位*/
  101.  
    {
  102.  
    if((c<<BitCnt)& 0x80)
  103.  
    {
  104.  
    SDA_pin= 0;
  105.  
    SDA= 1; /*判斷發送位*/
  106.  
    }
  107.  
    else
  108.  
    {
  109.  
    SDA= 0;
  110.  
    SDA_pin= 1;
  111.  
    }
  112.  
    _Nop();
  113.  
    SCL_pin= 0;
  114.  
    SCL= 1; /*置時鍾線為高,通知被控器開始接收數據位*/
  115.  
    iic_delay(); /*保證時鍾高電平周期大於4μs*/
  116.  
    SCL= 0;
  117.  
    SCL_pin= 1;
  118.  
     
  119.  
    }
  120.  
     
  121.  
    iic_delay() ;
  122.  
    SDA_pin= 0;
  123.  
    SDA= 1; /*8位發送完后釋放數據線,准備接收應答位*/
  124.  
    iic_delay() ;
  125.  
    SCL_pin= 0;
  126.  
    SCL= 1;
  127.  
    iic_delay();
  128.  
    if(SDA_in== 1)
  129.  
    ack= 0;
  130.  
    else
  131.  
    ack= 1; /*判斷是否接收到應答信號*/
  132.  
    SCL= 0;
  133.  
    SCL_pin= 1;
  134.  
    iic_delay() ;
  135.  
    }
  136.  
     
  137.  
    /*******************************************************************
  138.  
    字節數據傳送函數
  139.  
    函數原型: uchar RcvByte();
  140.  
    功能: 用來接收從器件傳來的數據,並判斷總線錯誤(不發應答信號),
  141.  
    發完后請用應答函數。
  142.  
    ********************************************************************/
  143.  
    uchar ReadByte()
  144.  
    {
  145.  
    uchar retc;
  146.  
    uchar BitCnt;
  147.  
     
  148.  
    retc= 0;
  149.  
    SDA_pin= 0;
  150.  
    SDA= 1; /*置數據線為輸入方式*/
  151.  
    for(BitCnt= 0;BitCnt< 8;BitCnt++)
  152.  
    {
  153.  
    SCL= 0; /*置時鍾線為低,准備接收數據位*/
  154.  
    SCL_pin= 1;
  155.  
    iic_delay(); /*時鍾低電平周期大於4.7μs*/
  156.  
    SCL_pin= 0;
  157.  
    SCL= 1; /*置時鍾線為高使數據線上數據有效*/
  158.  
    iic_delay();
  159.  
    retc=retc<< 1;
  160.  
    if(SDA_in== 1)retc=retc+ 1; /*讀數據位,接收的數據位放入retc中 */
  161.  
    iic_delay();
  162.  
    }
  163.  
    SCL= 0;
  164.  
    SCL_pin= 1;
  165.  
    iic_delay();
  166.  
    return(retc);
  167.  
    }
  168.  
     
  169.  
     
  170.  
     
  171.  
     
  172.  
    /********************************************************************
  173.  
    應答子函數
  174.  
    原型: void Ack_I2c(bit a);
  175.  
     
  176.  
    功能:主控器進行應答信號,(可以是應答或非應答信號)
  177.  
    ********************************************************************/
  178.  
    void Ack_I2c(uchar a)
  179.  
    {
  180.  
    if(a== 0)
  181.  
    {
  182.  
    SDA_pin= 1;
  183.  
    SDA= 0; /*在此發出應答或非應答信號 */
  184.  
    }
  185.  
    else
  186.  
    {
  187.  
    SDA_pin= 0;
  188.  
    SDA= 1;
  189.  
    }
  190.  
    iic_delay();
  191.  
    SCL_pin= 0;
  192.  
    SCL= 1;
  193.  
    iic_delay(); /*時鍾低電平周期大於4μs*/
  194.  
    iic_delay();
  195.  
    SCL= 0; /*清時鍾線,鉗住I2C總線以便繼續接收*/
  196.  
    SCL_pin= 1;
  197.  
    iic_delay();
  198.  
    }
  199.  
     
  200.  
     
  201.  
     
  202.  
    void Write8563(uchar ucAddr,uchar ucData)
  203.  
     
  204.  
    {
  205.  
     
  206.  
    Start();
  207.  
     
  208.  
    WriteByte( 0xa2);
  209.  
     
  210.  
    WriteByte(ucAddr);
  211.  
     
  212.  
    WriteByte(ucData);
  213.  
     
  214.  
    Stop();
  215.  
     
  216.  
    }
  217.  
     
  218.  
     
  219.  
    uchar Read8563(uchar ucAddr)
  220.  
     
  221.  
    {
  222.  
     
  223.  
    uchar ucData;
  224.  
     
  225.  
    Start();
  226.  
     
  227.  
    WriteByte( 0xa2); //寫器件地址
  228.  
     
  229.  
    WriteByte(ucAddr); //寫字節地址
  230.  
     
  231.  
    Start();
  232.  
     
  233.  
    WriteByte( 0xa3); //寫器件地址,最低為1表示讀
  234.  
     
  235.  
    ucData=ReadByte(); //寫字節地址
  236.  
     
  237.  
    Stop();
  238.  
     
  239.  
    return ucData; //讀數據
  240.  
     
  241.  
    }
  242.  
     
  243.  
     
  244.  
    void Init8563(void)
  245.  
     
  246.  
    {
  247.  
     
  248.  
    uchar i,ucAddr= 0x02;
  249.  
     
  250.  
    Write8563( 0x0d, 0x80);
  251.  
    i = Read8563( 0x0D);
  252.  
    Write8563( 0x00, 0x00);
  253.  
    Write8563( 0x01, 0x11);
  254.  
     
  255.  
    i = Read8563( 0x00);
  256.  
    i = Read8563( 0x01);
  257.  
     
  258.  
    for(i= 0;i< 7;i++)
  259.  
     
  260.  
    {
  261.  
     
  262.  
    Write8563(ucAddr,TAB_T[i]);
  263.  
     
  264.  
    ucAddr++;
  265.  
     
  266.  
    }
  267.  
     
  268.  
    }
  269.  
     
  270.  
     
  271.  
    void GetTime(void)
  272.  
     
  273.  
    {
  274.  
     
  275.  
    uchar i,ucData1,ucData2,ucAddr= 0x02;
  276.  
     
  277.  
    uchar *pTime=TAB_T;
  278.  
     
  279.  
    for(i= 0;i< 7;i++)
  280.  
     
  281.  
    {
  282.  
     
  283.  
    pTime[i]=Read8563(ucAddr);
  284.  
     
  285.  
    ucAddr++;
  286.  
     
  287.  
    }
  288.  
     
  289.  
    pTime[ 0]&= 0x7f; //屏蔽無效位
  290.  
     
  291.  
    pTime[ 1]&= 0x7f;
  292.  
     
  293.  
    pTime[ 2]&= 0x3f;
  294.  
     
  295.  
    pTime[ 3]&= 0x3f;
  296.  
     
  297.  
    pTime[ 4]&= 0x07;
  298.  
     
  299.  
    pTime[ 5]&= 0x1f;
  300.  
     
  301.  
    // for(i=0;i<7;i++)
  302.  
    //
  303.  
    // {
  304.  
    //
  305.  
    // ucData1=pTime[i]/16; //BCD碼轉十六進制
  306.  
    //
  307.  
    // ucData2=pTime[i]%16;
  308.  
    //
  309.  
    // pTime[i]=ucData1*10+ucData2;
  310.  
    //
  311.  
    // }
  312.  
     
  313.  
    }
  314.  
     
  315.  
    /* 完畢 */
  316.  
     
  317.  
     
  318.  
     
  319.  
     
  320.  
     
  321.  
     
  322.  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM