iic

发布时间 2023-12-09 18:24:19作者: 踏浪而来的人

主机主动释放I2C_SDA,为读ack做准备。为什么主机要释放SDA线呢?

因为主机和从机将的SDA线连接是通过&,所以从机在操作总线时,主机要释放总线。(从机在什么时候需要操作总线?1.从机应答2.主机读数据(从机写))

如主机不释放总线的话,那么SDA线上可能是0,也可能是1,假设现在SDA线上是0,那么不论从机是想拉高或拉低SDA线,SDA线都只会为0,因为两器件间是线与(&)的关系。所以在从机要操作总线时,主机要将SDA线释放(即拉高),这样从机就可以根据需要来拉高和拉低SDA线

 1 void i2cstart()//SCL在高电平期间,SDA由高变低表示起始信号
 2 {
 3     I2C_SCL = 1;
 4     I2C_SDA = 1;//空闲时,scl和sda为1
 5     
 6     I2CDelay();//I2C_SCL延时4.7us,然后拉低I2C_SDA,产生起始信号
 7     I2C_SDA = 0;
 8     I2CDelay();//I2C_SDA拉低后,要保持4.7us
 9     
10     I2C_SCL = 0;//拉低I2C_SCL,为下一次做准备
11 }
12 
13 void i2cWriteByte(unsigned char dat)//这个函数是紧跟在start函数的,所以I2C_SCL为0,即I2C_SDA允许变化
14 {
15     unsigned char temp;
16     for(temp = 0x80; temp != 0; temp++){//操作dat的高位
17         if((temp & dat) == 0)
18             I2C_SDA = 0;
19         else
20             I2C_SDA = 1;
21         I2CDelay();    //I2C_SCL为低电平期间,I2C_SDA允许变化
22         
23         I2C_SCL = 1;//主机将I2C_SCL拉高,并保持4.7us,告诉从机从I2C_SDA上读数据
24         I2CDelay();    
25         
26         I2C_SCL = 0;//拉低I2C_SCL,为下一次做准备
27     }
28 }
29 
30 unsigned char i2cReadByte()//这个函数紧跟在读应答函数后,所以I2C_SCL为0,即I2C_SDA允许变化
31 {
32     unsigned char dat = 0,temp;
33     I2C_SDA = 1;//主机主动释放I2C_SDA,让从机往SDA线上放数据。为什么要释放呢?如上
34     for(temp = 0x80; temp != 0; temp++){//操作dat的高位
35         I2CDelay();    //i2cRecAck函数将I2C_SCL拉低,这里是保持I2C_SCL为为4.7us
36         I2C_SCL = 1;
37         if(I2C_SDA == 1)
38             dat |=temp;
39         else
40             dat &= ~temp;
41         I2CDelay();    //SCL高电平期间,主机就能将SDA线上的数据放到dat变量中
42         I2C_SCL = 0;//拉低I2C_SCL,为下一次做准备
43     }
44 }
45 
46 void sendAck(bit ack)//这个函数紧跟在i2cReadByte函数后,所以I2C_SCL为0,即I2C_SDA允许变化
47 {
48     I2C_SDA = ack;//在SCL低电平期间,SDA允许变化
49     I2CDelay();
50     
51     I2C_SCL = 1;//主机将SCL拉高,并在高电平期间将主机将ack发给从机
52     I2CDelay();
53     I2C_SCL = 0;//拉低I2C_SCL,为下一次做准备
54 }
55 
56 unsigned char i2cRecAck()
57 {
58     unsigned char ack;
59     I2C_SDA = 1;//主机主动释放I2C_SDA,为读ack做准备。为什么要释放呢?等下解答
60     I2CDelay();//这个函数紧跟在write函数,所以最后I2C_SCL = 0;,这个是让I2C_SCL保持4.7us
61     
62     I2C_SCL = 1;//拉高I2C_SCL,看SDA线上是高还是低(即是否应答)
63     ack = I2C_SDA;
64     I2CDelay();
65     
66     I2C_SCL = 0;//拉低I2C_SCL,为下一次做准备
67     return ack;
68 }
69 
70 void i2cStop()//SCL在高电平期间,SDA有低电平变为高电平为停止信号
71 {
72     I2C_SCL = 0;
73     I2C_SDA = 0;
74     I2CDelay();
75     
76     I2C_SCL = 1;//I2C_SCL拉高4.7us
77     I2CDelay();
78     I2C_SDA = 1;//再将I2C_SDA拉高,并且保持4.7us
79     I2CDelay();
80 }