51单片机——I2C总线
扫描二维码
随时随地手机看文章
UART 属于异步通信,比如电脑发送给单片机,电脑只负责把数据通过TXD 发送出来即可,接收数据是单片机自己的事情。而 I2C 属于同步通信, SCL 时钟线负责收发双方的时钟节拍, SDA 数据线负责传输数据。 I2C 的发送方和接收方都以 SCL 这个时钟节拍为基准进行数据的发送和接收。
I2C总线包括SCL,SDA 两根信号线,其中SCL是时钟线,SDA是数据线。
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
#include
#defineI2CDelay(){_nop_();_nop_();_nop_();_nop_();}
sbitI2C_SCL=P3^7;
sbitI2C_SDA=P3^6;
/*产生总线起始信号*/
voidI2CStart()
{
I2C_SDA=1;//首先确保SDA、SCL都是高电平
I2C_SCL=1;
I2CDelay();
I2C_SDA=0;//先拉低SDA
I2CDelay();
I2C_SCL=0;//再拉低SCL
}
/*产生总线停止信号*/
voidI2CStop()
{
I2C_SCL=0;//首先确保SDA、SCL都是低电平
I2C_SDA=0;
I2CDelay();
I2C_SCL=1;//先拉高SCL
I2CDelay();
I2C_SDA=1;//再拉高SDA
I2CDelay();
}
/*I2C总线写操作,dat-待写入字节,返回值-从机应答位的值*/
bitI2CWrite(unsignedchardat)
{
bitack;//用于暂存应答位的值
unsignedcharmask;//用于探测字节内某一位值的掩码变量
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总线读操作,并发送非应答信号,返回值-读到的字节*/
unsignedcharI2CReadNAK()
{
unsignedcharmask;
unsignedchardat;
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完成非应答位,并保持住总线
returndat;
}
/*I2C总线读操作,并发送应答信号,返回值-读到的字节*/
unsignedcharI2CReadACK()
{
unsignedcharmask;
unsignedchardat;
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完成应答位,并保持住总线
returndat;
}