单片机 【I2C 通信】

================================I2C 通信================================

 1-WIRE --------------------  DS18B20

I2C ------------------------(本课)

 

SDA  ----------(serial data I/O)

SCL -----------(serial clock)

 

==================================I2C传输协议

 

=======================================I2C传输起始和终止信号 

 =====================================I2C字节的传送与应答

 

======================应答位的作用

================================I2C写数据流程

========================I2C读数据流程

 

========================软件模拟I2C通信时序

 

1 /*I2C初始化*/
2 void I2C_init()    
3 {
4     SDA = 1;
5     _nop_();
6     SCL = 1;
7     _nop_();
8 }
初始化
 1 /*I2C起始信号*/
 2 void I2C_Start()  
 3 {
 4     SCL = 1;
 5     _nop_();
 6     SDA = 1;
 7     delay_5us();
 8     SDA = 0;
 9     delay_5us();
10 }
开始信号
 1 /*I2C终止信号*/
 2 void I2C_Stop()
 3 {
 4     SDA = 0;
 5     _nop_();
 6     SCL = 1;
 7     delay_5us();
 8     SDA = 1;
 9     delay_5us();
10 }
结束信号
 1 /*主机发送应答*/
 2 void Master_ACK(bit i)        
 3 {
 4     SCL = 0; // 拉低时钟总线允许SDA数据总线上的数据变化
 5     _nop_(); // 让总线稳定
 6     if (i)     //如果i = 1 那么拉低数据总线 表示主机应答
 7     {
 8         SDA = 0;
 9     }
10     else     
11     {
12         SDA = 1;     //发送非应答
13     }
14     _nop_();//让总线稳定
15     SCL = 1;//拉高时钟总线 让从机从SDA线上读走 主机的应答信号
16     delay_5us();
17     SCL = 0;//拉低时钟总线, 占用总线继续通信
18     _nop_();
19     SDA = 1;//释放SDA数据总线。
20     _nop_();
21 }
主机应答
 1 /*检测从机应答*/
 2 bit Test_ACK()
 3 {
 4     SCL = 1;
 5     delay_5us();
 6     if (SDA)
 7     {
 8         SCL = 0;
 9         _nop_();
10         I2C_Stop();
11         return(0);
12     }
13     else
14     {
15         SCL = 0;
16         _nop_();
17         return(1);
18     }
19 }
从机应答
 1 /*发送一个字节*/
 2 void I2C_send_byte(uchar byte)
 3 {
 4     uchar i;
 5     for(i = 0 ; i < 8 ; i++)
 6     {
 7         SCL = 0;
 8         _nop_();
 9         if (byte & 0x80)
10         {                
11             SDA = 1;    
12             _nop_();                   
13         }                
14         else
15         {
16             SDA = 0;
17             _nop_();
18         }
19         SCL = 1;
20         _nop_();
21         byte <<= 1;    // 0101 0100B 
22     }
23     SCL = 0;
24     _nop_();
25     SDA = 1;
26     _nop_();
27 }
发送一字节
 1 /*I2C 读一字节*/
 2 uchar I2C_read_byte()
 3 {
 4     uchar dat,i;
 5     SCL = 0;
 6     _nop_();
 7     SDA = 1;
 8     _nop_();
 9     for(i = 0 ; i < 8 ; i++)
10     {
11         SCL = 1;
12         _nop_();
13         if (SDA)                
14         {
15              dat |= 0x01; //
16         }
17         else
18         {
19             dat &=  0xfe;    //1111 1110
20         }
21         _nop_();
22         SCL = 0 ;
23         _nop_();
24         if(i < 7)
25         {
26             dat = dat << 1;    
27         }
28     }
29     return(dat);
30 }
读取一字节
 1 /*I2C发送数据*/
 2 bit I2C_TransmitData(uchar ADDR, DAT)
 3 {
 4     I2C_Start();
 5     I2C_send_byte(AT24C02_ADDR+0);
 6     if (!Test_ACK())
 7     {
 8         return(0);
 9     }
10     I2C_send_byte(ADDR); 
11     if (!Test_ACK())
12     {
13         return(0);
14     }
15     I2C_send_byte(DAT);
16     if (!Test_ACK())
17     {
18         return(0);
19     }
20     I2C_Stop();
21     return(1);    
22 }
I2C发送数据
 1 /*I2C接收数据*/
 2 uchar I2C_ReceiveData(uchar ADDR)
 3 {
 4     uchar DAT;
 5     I2C_Start();
 6     I2C_send_byte(AT24C02_ADDR+0);
 7     if (!Test_ACK())
 8     {
 9         return(0);
10     }
11     I2C_send_byte(ADDR);
12     Master_ACK(0);
13     I2C_Start();
14     I2C_send_byte(AT24C02_ADDR+1);
15     if (!Test_ACK())
16     {
17         return(0);
18     }
19     DAT = I2C_read_byte();
20     Master_ACK(0);
21     I2C_Stop();
22     return(DAT);    
23 }
I2C接收数据
 1 void main()
 2 {
 3     I2C_init();//I2C初始化
 4     if(!I2C_TransmitData(255,0xf0));    //往AT24C02第255个单元中写入数据0XF0
 5     {
 6         P1 = 0;
 7     }
 8     delay(5);
 9     /**/
10     P1 = I2C_ReceiveData(255);//从AT24C02第255个单元中读取数据
11     while(1);     
12 }
主函数

 

 

  1 # include <reg52.h>
  2 # include <intrins.h>
  3 
  4 #define uchar unsigned char
  5 #define uint unsigned  int
  6 #define AT24C02_ADDR  0xa0    //AT24C02地址
  7 
  8 /*I2C IO口定义*/
  9 sbit SDA = P2^0;
 10 sbit SCL = P2^1;
 11 
 12 /*5us延时*/
 13 void delay_5us()  
 14 {
 15     _nop_();
 16 }
 17 
 18 /*1Ms延时*/
 19 void delay(uint z)
 20 {
 21     uint x,y;
 22     for(x = z; x > 0; x--)
 23         for(y = 114; y > 0 ; y--);
 24 }
 25 
 26 /*I2C初始化*/
 27 void I2C_init()    
 28 {
 29     SDA = 1;
 30     _nop_();
 31     SCL = 1;
 32     _nop_();
 33 }
 34 
 35 /*I2C起始信号*/
 36 void I2C_Start()  
 37 {
 38     SCL = 1;
 39     _nop_();
 40     SDA = 1;
 41     delay_5us();
 42     SDA = 0;
 43     delay_5us();
 44 }
 45 
 46 /*I2C终止信号*/
 47 void I2C_Stop()
 48 {
 49     SDA = 0;
 50     _nop_();
 51     SCL = 1;
 52     delay_5us();
 53     SDA = 1;
 54     delay_5us();
 55 }
 56 
 57 /*主机发送应答*/
 58 void Master_ACK(bit i)        
 59 {
 60     SCL = 0; // 拉低时钟总线允许SDA数据总线上的数据变化
 61     _nop_(); // 让总线稳定
 62     if (i)     //如果i = 1 那么拉低数据总线 表示主机应答
 63     {
 64         SDA = 0;
 65     }
 66     else     
 67     {
 68         SDA = 1;     //发送非应答
 69     }
 70     _nop_();//让总线稳定
 71     SCL = 1;//拉高时钟总线 让从机从SDA线上读走 主机的应答信号
 72     delay_5us();
 73     SCL = 0;//拉低时钟总线, 占用总线继续通信
 74     _nop_();
 75     SDA = 1;//释放SDA数据总线。
 76     _nop_();
 77 }
 78 
 79 /*检测从机应答*/
 80 bit Test_ACK()
 81 {
 82     SCL = 1;
 83     delay_5us();
 84     if (SDA)
 85     {
 86         SCL = 0;
 87         _nop_();
 88         I2C_Stop();
 89         return(0);
 90     }
 91     else
 92     {
 93         SCL = 0;
 94         _nop_();
 95         return(1);
 96     }
 97 }
 98 
 99 /*发送一个字节*/
100 void I2C_send_byte(uchar byte)
101 {
102     uchar i;
103     for(i = 0 ; i < 8 ; i++)
104     {
105         SCL = 0;
106         _nop_();
107         if (byte & 0x80)
108         {                
109             SDA = 1;    
110             _nop_();                   
111         }                
112         else
113         {
114             SDA = 0;
115             _nop_();
116         }
117         SCL = 1;
118         _nop_();
119         byte <<= 1;    // 0101 0100B 
120     }
121     SCL = 0;
122     _nop_();
123     SDA = 1;
124     _nop_();
125 }
126 
127 
128 /*I2C 读一字节*/
129 uchar I2C_read_byte()
130 {
131     uchar dat,i;
132     SCL = 0;
133     _nop_();
134     SDA = 1;
135     _nop_();
136     for(i = 0 ; i < 8 ; i++)
137     {
138         SCL = 1;
139         _nop_();
140         if (SDA)                
141         {
142              dat |= 0x01; //
143         }
144         else
145         {
146             dat &=  0xfe;    //1111 1110
147         }
148         _nop_();
149         SCL = 0 ;
150         _nop_();
151         if(i < 7)
152         {
153             dat = dat << 1;    
154         }
155     }
156     return(dat);
157 }
158 
159 /*I2C发送数据*/
160 bit I2C_TransmitData(uchar ADDR, DAT)
161 {
162     I2C_Start();
163     I2C_send_byte(AT24C02_ADDR+0);
164     if (!Test_ACK())
165     {
166         return(0);
167     }
168     I2C_send_byte(ADDR); 
169     if (!Test_ACK())
170     {
171         return(0);
172     }
173     I2C_send_byte(DAT);
174     if (!Test_ACK())
175     {
176         return(0);
177     }
178     I2C_Stop();
179     return(1);    
180 }
181 
182 /*I2C接收数据*/
183 uchar I2C_ReceiveData(uchar ADDR)
184 {
185     uchar DAT;
186     I2C_Start();
187     I2C_send_byte(AT24C02_ADDR+0);
188     if (!Test_ACK())
189     {
190         return(0);
191     }
192     I2C_send_byte(ADDR);
193     Master_ACK(0);
194     I2C_Start();
195     I2C_send_byte(AT24C02_ADDR+1);
196     if (!Test_ACK())
197     {
198         return(0);
199     }
200     DAT = I2C_read_byte();
201     Master_ACK(0);
202     I2C_Stop();
203     return(DAT);    
204 }
205 
206 void main()
207 {
208     I2C_init();//I2C初始化
209     if(!I2C_TransmitData(255,0xf0))  //往AT24C02第255个单元中写入数据0XF0
210     {
211         P1 = 0;
212     }
213     delay(5);
214     /**/
215     P1 = I2C_ReceiveData(255);//从AT24C02第255个单元中读取数据
216     while(1);     
217 }

 为什么在传输过程中,SCL=0,SDA=1; 在这里解释一下:

      打个比方:SDA相当于琴弦,在最初的初始化时SDA=1;(相当于琴弦放松的时候)

                      SCL只有在SDA传输过程中SCL=1(等于1时相当于开关开启,传送数据),只有SCL=0时数据才可以改变(相当于数据加载开关关闭);         

posted @ 2018-04-06 07:40  Justice-V  阅读(487)  评论(0编辑  收藏  举报