访问手机版页面
你的位置:老古开发网 > 51单片机与I2C总线 > 正文  
51单片机——I2C总线
内容导读:
UART 属于异步通信,比如电脑发送给单片机,电脑只负责把数据通过TXD 发送出来即可,接收数据是单片机自己的事情。而 I2C 属于同步通信, SCL 时钟线负责收发双方的时钟节拍, SDA 数据线负责传输数据。 I2C 的发送方和接收方都以 SCL 这个时钟节拍为基准进行数据的发送和接收。I2C总线包括SCL,SDA 两根信号线,其中SCL是时钟线,SDA是数据线。

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

#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;

}

标签: 51单片机,i2c总线,
来源:21ic 作者:wuq 时间:2019/7/15 20:14:04
相关阅读
推荐阅读
阅读排行
最近更新
商品推荐