选用串行总线技能能够使体系的硬件规划大大简化,体系的体积减小,可靠性进步,一起体系更简单更改和扩大
常用的串行扩展总线有:I2c总线,单总线,SPI总线,以及microwire、Plus等等
I2c总线只要两根双向信号线,一根是数据线SDA,另一根是时钟线SCL
I2c总线经过上拉电阻接正电源。因而I2C总线的设备都要接上拉电阻
当总线搁置的时分,两根线均为高电平,连接到总线上的任何一个器材输出的低电平,都将使得总线得到信号变低,及各个器材的SDA和SCL都是线与的联系
每个接入到I2C总线都有仅有的地址,主机与其他器材间的数据传送可所以由主机发送数据到其他器材,这时主机便是发送器,由总线上接纳数据的器材称为是接纳器。
在多主机体系中,或许一起由几个主机妄图发动总线传送数据,为了防止紊乱,I2C总线要经过总线裁定,已决议由哪台主机操控总线
数据位的有效性
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据有必要保持安稳,只要时钟线上的信号为低电平期间,数据线上的高电平和低电平状况才答应改变
开端信号和中止信号
SCL线为高电平期间,SDA线由高电平向低电平的改变表明开端信号,SCL线为高电平期间,SDA线由低电平向高电平改变表明中止信号
数据传送的格局
(1)字节传送与应对
每一个字节有必要确保是8位长度,数据传送时,先传送的是最高位(MSB),每一个被传送的字节后边都有必要跟从一位应对位,即(一帧共有9位),应对信号由从机发送给主机
每次数据传送总是由主机发生的中止信号完毕,可是若主机期望持续占用总线进行新的数据传送,则能够不发生中止信号,立刻再次宣布开端信号对另一个从机进行寻址
在总线的一个数据传上进程中,能够有一下几种传送方法的组合方法
a,主机向从机发送数据,数据传送的方向在整个传送进程中不变
A表明应对,A非表明非应对,s表明其实信号,p表明中止信号
主机发送地址时,总线上的每一个从机都将这7位地址码与自己的地址进行比较,假如相同,则以为自己正在被主机寻址,依据R/T位将自己承认为发送器或接纳器
从机地址由固定部分和可编程部分组成,可编程的部分决议了可接入总线该器材的最大数目。
由操作时序可知要进行必要的延时
开端操作示例代码:
void T2CStart(void)
{
SDA = 1;
SomeNop();//大于微秒等级
SCL = 1;
SomeNop();
SDA = 0;
SomeNop();
}
中止指令:
void I2CStop(void)
{
SDA = 0;//data由0变到1为中止指令
SomeNop();
SCL = 1;
SomeNop();
SDA = 1;
SomeNop();
}
I2C总线扩展
串行E2PROM的扩展
(2)写入进程:AT24CEEPROM的固定地址为1010,A2,A1A0引脚接入凹凸电平能够得到承认的3位编码,构成的7位编码即为该器材的地址码
单片机进行写操作的时分,首要
发送该器材的7位地址吗和写方向的方向码0,发送完今后开释SDA线并在SCL线上发生第九个时钟信号,被选中的存储器再承认自己的地址后,在SDA上发生一个应对信号作为呼应
,单片机接纳到信号就能够传送数据了
传送数据时,单片机首要发送一个字节的被写入器材的存储区的首地址,收到存储器器材的应对后,单片机就逐一发送各个数据的字节,可是每次发送一个字节后都要等候应对
收到每个字节的地址后,芯片上的地址会主动加一
写入n个字节的数据格局
读出进程
单片机首要发送该器材的7位地址码和写方向位0(伪写),发送完后开释SDA线并在SCL线上发生9个时钟信号,被选中的存储器器材在承认自己的地址之后,在SDA上发生一个应对信号作为回应
然后在发送一个字节的要读出存储去的首地址,收到应对,单片机要重复一次开端信号并宣布器材地址的读方向位(1),收到器材应对就能够读出字节,每次读出一个字节,单片机都要回复一个应对信号,但最终读出一个字节,单片机应回来非应对信号(高电平)并宣布中止信号以完毕读出操作
示例代码:
#include
#define uchar unsigned char
#define uint unsigned int
sbit sda = P2^3;
sbit scl = P2^2;
sbit wp = P2^1;
void delay()//奇妙等级的延时函数
{;;}
void start()//开端信号
{
sda = 1;
delay();
scl = 1;
delay();
sda = 0;
delay();
}
void stop()//中止信号
{
sda = 0;
delay();
scl = 1;
delay();
sda = 1;
delay();
}
void respons()//应对信号
{
uchar i;
scl = 1;
delay();
while((sda ==1)&&(i<250))//比及第九个时钟周期的时分,还没有变为0,
//那么scl将主动的变为0,表明收到信号
{
i++;
}
scl = 0;
}
void init()
{
sda = 1;
scl = 1;//把线悉数开释
}
void write_byte(uchar date)
{
uchar i,temp;
temp = date;
scl = 0;
delay();
for(i = 0;i<8;i++)//写8次
{
temp = temp<<1;//表明将temp左移1位,将最高位移入psw寄存器中的cy位,
//然后将最高位赋值给sda,送走数据
scl = 1;//数据安稳了
delay();
sda = CY;
delay();
scl = 0;//读走数据
delay();
}
sda = 1;//留意养成开释总线的习气
delay();
}
uchar read_byte()
{
uchar i,j,k;
scl = 0;
delay();
sda = 1;//开释数据总线
delay();
for(i=0;i<8;i++)
{
scl = 1;
delay();
j = sda ;//读取数据
k =(k<<1)"j;
scl = 0;
delay();
}
return k;
}
uchar read_add(uchar address)
{
uchar date;
start();
write_byte(0xa0);//表明写入器材的地址
respons();
write_byte(address);
respons();
start();
write_byte(0xa1);
respons();
date=read_byte();
stop();
return date;
}
void write_add(uchar address,uchar date)
{
init();//初始化信号总线和地址总线
start();//发动信号
write_byte(0xa0);//表明写入器材的地址
respons();
write_byte(address);//表明往这个器材内部的第三个地址处写入地址
respons();
write_byte(date);//表明器材内部的数据
respons();
stop();
}
void delay1(uint z)
{
uint x,y;
for(x= z;x>0;x–)
for(y=110;y>0;y–);
}
void main()
{
init();
write_add(23,125);
delay1(100);
P1=read_add(23);
while(1);
}