博主福利:100G+电子设计学习资源包!

​http://mp.weixin.qq.com/mp/homepage?__biz=MzU3OTczMzk5Mg==&hid=7&sn=ad5d5d0f15df84f4a92ebf72f88d4ee8&scene=18#wechat_redirect​​ --------------------------------------------------------------------------------------------------------------------------

 

UART 属于异步通信,比如电脑发送给单片机,电脑只负责把数据通过TXD 发送出来即可,接收数据是单片机自己的事情。而 I2C 属于同步通信, SCL 时钟线负责收发双方的时钟节拍, SDA 数据线负责传输数据。 I2C 的发送方和接收方都以 SCL 这个时钟节拍为基准进行数据的发送和接收。
       

I2C总线包括SCL,SDA 两根信号线,其中SCL是时钟线,SDA是数据线。

51单片机入门 - IIC(I2C)总线_停止信号

1、起始信号
       

UART 通信是从一直持续的高电平出现一个低电平标志起始位;而 I2C 通信的起始信号的定义是 SCL 为高电平期间, SDA 由高电平向低电平变化产生一个下降沿,表示起始信号。

 
2、数据传输
     

 UART 是低位在前,高位在后;而 I2C 通信是高位在前,低位在后。UART 通信数据位是固定长度,波特率分之一,一位一位固定时间发送完毕就可以了。而 I2C 没有固定波特率,但是有时序的要求,要求当 SCL 在低电平的时候, SDA 允许变化。

 
3、停止信号
       

UART 通信的停止位是一位固定的高电平信号; 而 I2C 通信停止信号的定义是 SCL 为高电平期间, SDA 由低电平向高电平变化产生一个上升沿,表示结束信号。

 
4、写完从器件之后等待从器件的应答
         

在主器件完成对从器件的写操作时候(每次会有一个字节的数据),主器件会等待从器件发送指示信号,这个指示信号是说从器件已经接受到了主器件的数据,这是由从器件的硬件来完成的,不需要主器件来软件操作,只需要等待;

 
5、主器件读完数据后向从器件发送应答信号
         

这其实包括两种情况,一种是主器件读完后还要继续读就要发送一个继续读的信号(其实就是发送0),另一种就是不再继续读了,就要发送停止读信号(其实就是发送1)。

 
6、I2C寻址模式
       

I2C 通信的起始信号(Start)后,首先要发送一个从机的地址,这个地址一共有 7位,紧跟着的第 8 位是数据方向位(R/W),“ 0”表示接下来要发送数据(写),‘“ 1”表示接下来是请求数据(读)。第九位 ACK应答。 

 

#include<reg52.h>

#include<intrins.h>



#define I2CDelay() {_nop_();_nop_();_nop_();_nop_();}

sbit I2C_SCL = P3 ^ 7;

sbit I2C_SDA = P3 ^ 6;



/* 产生总线起始信号 */

void I2CStart()

{

I2C_SDA = 1; //首先确保SDA、SCL都是高电平

I2C_SCL = 1;

I2CDelay();

I2C_SDA = 0; //先拉低SDA

I2CDelay();

I2C_SCL = 0; //再拉低SCL

}

/* 产生总线停止信号 */

void I2CStop()

{

I2C_SCL = 0; //首先确保SDA、SCL都是低电平

I2C_SDA = 0;

I2CDelay();

I2C_SCL = 1; //先拉高SCL

I2CDelay();

I2C_SDA = 1; //再拉高SDA

I2CDelay();

}

/* I2C总线写操作,dat-待写入字节,返回值-从机应答位的值 */

bit I2CWrite(unsigned char dat)

{

bit ack; //用于暂存应答位的值

unsigned char mask; //用于探测字节内某一位值的掩码变量



for (mask = 0x80; mask != 0; mask >>= 1) //从高位到低位依次进行

{

if ((mask & dat) == 0) //该位的值输出到SDA上

{

I2C_SDA = 0;

}

else

{

I2C_SDA = 1;

}

I2CDelay();

I2C_SCL = 1; //拉高SCL

I2CDelay();

I2C_SCL = 0; //再拉低SCL,完成一个位周期

}

I2C_SDA = 1; //8位数据发送完后,主机释放SDA,以检测从机应答

I2CDelay();

I2C_SCL = 1; //拉高SCL

ack = I2C_SDA; //读取此时的SDA值,即为从机的应答值

I2CDelay();

I2C_SCL = 0; //再拉低SCL完成应答位,并保持住总线



return (~ack); //应答值取反以符合通常的逻辑:

//0=不存在或忙或写入失败,1=存在且空闲或写入成功

}

/* I2C总线读操作,并发送非应答信号,返回值-读到的字节 */

unsigned char I2CReadNAK()

{

unsigned char mask;

unsigned char dat;



I2C_SDA = 1; //首先确保主机释放SDA

for (mask = 0x80; mask != 0; mask >>= 1) //从高位到低位依次进行

{

I2CDelay();

I2C_SCL = 1; //拉高SCL

if(I2C_SDA == 0) //读取SDA的值

{

dat &= ~mask; //为0时,dat中对应位清零

}

else

{

dat |= mask; //为1时,dat中对应位置1

}

I2CDelay();

I2C_SCL = 0; //再拉低SCL,以使从机发送出下一位

}

I2C_SDA = 1; //8位数据发送完后,拉高SDA,发送非应答信号

I2CDelay();

I2C_SCL = 1; //拉高SCL

I2CDelay();

I2C_SCL = 0; //再拉低SCL完成非应答位,并保持住总线



return dat;

}

/* I2C总线读操作,并发送应答信号,返回值-读到的字节 */

unsigned char I2CReadACK()

{

unsigned char mask;

unsigned char dat;



I2C_SDA = 1; //首先确保主机释放SDA

for (mask = 0x80; mask != 0; mask >>= 1) //从高位到低位依次进行

{

I2CDelay();

I2C_SCL = 1; //拉高SCL

if(I2C_SDA == 0) //读取SDA的值

{

dat &= ~mask; //为0时,dat中对应位清零

}

else

{

dat |= mask; //为1时,dat中对应位置1

}

I2CDelay();

I2C_SCL = 0; //再拉低SCL,以使从机发送出下一位

}

I2C_SDA = 0; //8位数据发送完后,拉低SDA,发送应答信号

I2CDelay();

I2C_SCL = 1; //拉高SCL

I2CDelay();

I2C_SCL = 0; //再拉低SCL完成应答位,并保持住总线



return dat;

}