I2C总线驱动程序

时间:2022-05-08 19:14:02
  1  /*************************此部分为I2C总线的驱动程序*************************************/
  2 
  3 #include<reg52.h>
  4 #include <intrins.h>
  5 
  6 //#define  NOP()   _nop_()   /* 定义空指令 */
  7 #define  _Nop()  _nop_()   /*定义空指令*/
  8 
  9  
 10 sbit     SCL=P2^1;     //I2C  时钟 
 11 sbit     SDA=P2^0;     //I2C  数据 
 12 
 13 bit ack;                 /*应答标志位*/
 14    
 15 
 16 //起动总线函数
 17 extern void Start_I2c();
 18 
 19 //结束总线函数  
 20 extern void Stop_I2c();
 21 
 22 //应答子函数
 23 extern void Ack_I2c(bit a);
 24 
 25 //字节数据发送函数
 26 extern void  SendByte(unsigned char  c);
 27 
 28 /*******************************************************************
 29                      起动总线函数               
 30 函数原型: void  Start_I2c();  
 31 功能:     启动I2C总线,即发送I2C起始条件.  
 32 ********************************************************************/
 33 void Start_I2c()
 34 {
 35   SDA=1;         /*发送起始条件的数据信号*/
 36   _Nop();
 37   SCL=1;
 38   _Nop();        /*起始条件建立时间大于4.7us,延时*/
 39   _Nop();
 40   _Nop();
 41   _Nop();
 42   _Nop();    
 43   SDA=0;         /*发送起始信号*/
 44   _Nop();        /* 起始条件锁定时间大于4μs*/
 45   _Nop();
 46   _Nop();
 47   _Nop();
 48   _Nop();       
 49   SCL=0;       /*钳住I2C总线,准备发送或接收数据 */
 50   _Nop();
 51   _Nop();
 52 }
 53 
 54 /*******************************************************************
 55                       结束总线函数               
 56 函数原型: void  Stop_I2c();  
 57 功能:     结束I2C总线,即发送I2C结束条件.  
 58 ********************************************************************/
 59 void Stop_I2c()
 60 {
 61   SDA=0;      /*发送结束条件的数据信号*/
 62   _Nop();       /*发送结束条件的时钟信号*/
 63   SCL=1;      /*结束条件建立时间大于4μs*/
 64   _Nop();
 65   _Nop();
 66   _Nop();
 67   _Nop();
 68   _Nop();
 69   SDA=1;      /*发送I2C总线结束信号*/
 70   _Nop();
 71   _Nop();
 72   _Nop();
 73   _Nop();
 74 }
 75 
 76 /*******************************************************************
 77                  字节数据发送函数               
 78 函数原型: void  SendByte(UCHAR c);
 79 功能:     将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
 80           此状态位进行操作.(不应答或非应答都使ack=0)     
 81            发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
 82 ********************************************************************/
 83 void  SendByte(unsigned char  c)
 84 {
 85  unsigned char  BitCnt;
 86  
 87  for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/
 88     {
 89      if((c<<BitCnt)&0x80)SDA=1;   /*判断发送位*/
 90        else  SDA=0;                
 91      _Nop();
 92      SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/
 93       _Nop(); 
 94       _Nop();             /*保证时钟高电平周期大于4μs*/
 95       _Nop();
 96       _Nop();
 97       _Nop();         
 98      SCL=0; 
 99     }
100     
101     _Nop();
102     _Nop();
103     SDA=1;                /*8位发送完后释放数据线,准备接收应答位*/
104     _Nop();
105     _Nop();   
106     SCL=1;
107     _Nop();
108     _Nop();
109     _Nop();
110     if(SDA==1)ack=0;     
111        else ack=1;        /*判断是否接收到应答信号*/
112     SCL=0;
113     _Nop();
114     _Nop();
115 }
116 
117 /*******************************************************************
118                  字节数据接收函数               
119 函数原型: UCHAR  RcvByte();
120 功能:        用来接收从器件传来的数据,并判断总线错误(不发应答信号),
121           发完后请用应答函数应答从机。  
122 ********************************************************************/    
123 unsigned char   RcvByte()
124 {
125   unsigned char  retc;
126   unsigned char  BitCnt;
127   
128   retc=0; 
129   SDA=1;                       /*置数据线为输入方式*/
130   for(BitCnt=0;BitCnt<8;BitCnt++)
131       {
132         _Nop();           
133         SCL=0;                  /*置时钟线为低,准备接收数据位*/
134         _Nop();
135         _Nop();                 /*时钟低电平周期大于4.7μs*/
136         _Nop();
137         _Nop();
138         _Nop();
139         SCL=1;                  /*置时钟线为高使数据线上数据有效*/
140         _Nop();
141         _Nop();
142         retc=retc<<1;
143         if(SDA==1)retc=retc+1;  /*读数据位,接收的数据位放入retc中 */
144         _Nop();
145         _Nop(); 
146       }
147   SCL=0;    
148   _Nop();
149   _Nop();
150   return(retc);
151 }
152 
153 /********************************************************************
154                      应答子函数
155 函数原型:  void Ack_I2c(bit a);
156 功能:      主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
157 ********************************************************************/
158 void Ack_I2c(bit a)
159 {
160   
161   if(a==0)SDA=0;              /*在此发出应答或非应答信号 */
162   else SDA=1;
163   _Nop();
164   _Nop();
165   _Nop();      
166   SCL=1;
167   _Nop();
168   _Nop();                    /*时钟低电平周期大于4μs*/
169   _Nop();
170   _Nop();
171   _Nop();  
172   SCL=0;                     /*清时钟线,钳住I2C总线以便继续接收*/
173   _Nop();
174   _Nop();    
175 }