1.总线
在前面我们讲过了串口通信,串口通信只能在两个设备之间进行传输。如果是三个设备互相通信的话,那么每个设备需要两组串口设备,他其实是三组相互独立的串口通讯。
如果是四个设备相互通信那么就更麻烦了。主要最突出的问题就是线路复杂
因此,为了解决这个问题,总线也就孕育而生了。
总线的目的:采用串行总线技术可以使系统的硬件设计大大简化、系统的体积减小、可靠性提高,同时,系统的更改和扩充变的极为容易。
常用的串行拓展总线
I2C (Inter-Integrated Circuit )总线【两线】
RS485总线【两线】
单总线(1-WIRE BUS)【一线】
SPI(Serial Peripheral Interface)总线【四线】
CAN总线【两线】
LIN总线【一线】
2.I2C总线
I2C总线是Philips公司推出的一种同步串行总线,是具备多主机系统所需的包括总线裁决和高低速器件同步功能的高性能串行总线。I2C一般采用的是一主多从的工作模式,比如单片机是主机,其他都是从机。
I2C总线有两根信号线,SDA、SCL
SDA线称为串行数据线,传输双向的数据;
SCL线称为串行时钟线,传输时钟信号,用来同步串行数据线上的数据;
由于SDA和SCL引脚都是漏极开路输出结构,故SDA 和SCL接上拉电阻到电源,一般上拉电阻取值3-10K。当总线空闲时,两根线均为高电平,连接到总线的任一器件输出低电平,都将使总线的信号变低,各器件的SDA及SCL都是“线与”关系。
I2C总线数据传输速率:标准模式:100kbit/s,快速模式:400kbit/s,高速模式:3.4Mbit/s
3.通信方式
3.1写数据方式
上图是一种标准的写数据帧。由上面学过的知识可以知道,这一帧数据是受到SDA和SCL(数据线和时钟线共同控制的),也就是说在同一时间,他要不是在发送信息就是在接收信息。
当处于空闲状态时,数据线和时钟线都处于高电平。
起始位
当开始传递信息时候,比如先传递第一位起始位时候,此时必须要在时钟信号在高电平期间,数据信号完成从高电平到低电平间的跳变,也就是下降沿。这样起始信号就发送完成
寻找设备地址
因为我们由很多从设备, 每个接到I2C总线上的从机器件都有唯一的地址。主机与其它器件间的数据传送可以由主机发送数据到其它器件,也可以由主机读取其它器件的数据,发送数据的一方为发送器,接收数据的一方接收器。 在多主机系统中,可能同时有几个主机企图启动总线传送数据。为了避免混乱,I2C总线要通过总线仲裁,以决定由哪一台主机控制总线。
在51单片机应用系统的电路中,我们经常遇到的是以单片机为主机,其它器件为从机的单主机情况。
所以为了区别和哪一设备进行通信,我们就需要先发送地址码,因为设备地址码是唯一的。
数据位有效性规定
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,不得变化,只有在时钟线上的信号为低电平期间,数据线上的电平状态才允许发生变化。
读写数据位置
主机发送完起始信号后,需要先传送一个寻址字节,其格式如下图所示,其中高7 位为从器件地址,最低位D0是控制数据接下来传送方向的方向位R/W ̅, R/W ̅=1 表示主机向从机读数据, R/W ̅=0 表示主机向从机写数据。
应答信号
应答信号,是从机发送给主机的信号。如果从机收到之前的信号就回复0,没收到或者读取完成回复1
由于某种原因从机不对主机寻址信号应答时(如从机正在进行实时性的处理工作而无法接收总线上的数据),它必须将数据线置于高电平,而由主机产生一个终止信号以结束总线的数据传送。
如果从机对主机进行了应答,但在数据传送一段时间后无法继续接收更多的数据时,从机可以通过对无法接收的第一个数据字节的“非应答”通知主机,主机则应发出终止信号以结束数据的继续传送。
当主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束传送的信号。这个信号是由对从机的“非应答”来实现的。然后,从机释放SDA线,以允许主机产生终止信号。
设备寄存器地址
因为我们是给24C02通信的,24C02是一个存储器,它可以存储256个字节。而我们发送的8位寄存器地址正好可以访问这256个字节
比如我们写的寄存器地址是0x01那么他就会向0x01地址中写入数据
然后单片机需要存储器返回一个应答信号0
数据位
接下来的8位是给这个存储器中写入的数据,加入我们写入的是00001111,那么这八位数据就会被写入0x01地址中。这8位在存储器中的信息即使断电也会永久保存。
发送完数据后还需要给主机再发送一个应带信号0,告诉主机写入完成
停止位
他和起始位正好相反,是当时钟信号是高电平时,数据信号从低电平向高电平跳变。也就是上升沿
3.2读数据方式
读数据和写数据其实差不多,也是首先写入设备地址,再写入寄存器地址,再写入设备地址,设备地址后给一个读数据的信号,最后存储器就会把存储器中的数据发给单片机。
3.3 单片机中需要实现的函数
1、起始信号
2、终止信号
3、写地址/数据
4、读数据
5、指定地址写数据
6、指定地址读数据
//起始信号
void I2C_Start()
{
//时钟信号,数据信号都设为高电平
SCL=1;
SDA=1;
Delay5us();
//数据信号一个下降沿信号
SDA=0;
Delay5us();
}
//结束信号
void I2C_End()
{
//时钟信号是高电平,数据信号是低电平
SDA=0;
SCL=1;
Delay5us();
//数据信号上升沿
SDA=1;
Delay5us();
}
//写一个字节
void I2C_WriteByte(uchar date)
{
uchar i =0;
SCL=0;
Delay5us();
for(i=0;i<8;i++)
{
date=date<<1;
SDA=CY;
Delay5us();
SCL=1;
Delay5us();
SCL=0;
Delay5us();
}
}
//应答信号
void respons()
{
SDA=1;//释放总线
SCL=1;//第九个时钟
Delay5us();
while(SDA==1&&i<200)
{
i++;
}
SCL=0;
Delay5us();
}
//读一个字节
uchar ReadByte()
{
int i,j;
SCL=0;
Delay5us();
SDA=1;//释放总线
for(i=0;i<8;i++)
{
SCL=1;
Delay5us();
j=SDA|(j<<1);//0000 0000||1
SCL=0;
Delay5us();
}
Delay5us();
return k;
}