I2C总线的介绍(这个就是摘抄拉):
I I2 2C C总线( 总线(Inter Integrated Circuit Bus Inter Integrated Circuit Bus):是 ):是Philips Philips公司 公司 推出的串行总线标准(为二线制)。总线上扩展的外围器件及外设接 推出的串行总线标准(为二线制)。总线上扩展的外围器件及外设接 口通过总线寻址,是具备总线仲裁和高低速设备同步等功能的高性能 口通过总线寻址,是具备总线仲裁和高低速设备同步等功能的高性能 多主机总线。 多主机总线。
? ? I I2 2C C总线工作原理 总线工作原理
? ? 串行数据线 串行数据线SDA SDA和串行时钟线 和串行时钟线SCL SCL构成的,可发送和接收数据。 构成的,可发送和接收数据。
? ? 所有挂接在 所有挂接在I I2 2C C总线上的器件和接口电路都应具有 总线上的器件和接口电路都应具有I I2 2C C总线接口,且所 总线接口,且所 有的 有的SDA/SCL SDA/SCL同名端相连。总线上所有器件要依靠 同名端相连。总线上所有器件要依靠SDA SDA发送的地址 发送的地址 信号寻址,不需要片选线。 信号寻址,不需要片选线。
? ? 特点:组成系统结构简单,占用空间小,芯片管脚的数量少,无需片 特点:组成系统结构简单,占用空间小,芯片管脚的数量少,无需片 选信号,价格低。允许若干兼容器件共享总线,应用比较广泛。总线 选信号,价格低。允许若干兼容器件共享总线,应用比较广泛。总线 的长度可达 的长度可达7.6m 7.6m,传送速度可达 ,传送速度可达400kbps 400kbps,标准速率为 ,标准速率为 100kbps 100kbps。支持多个组件。支持多主控器件(某时刻只能有一个主 。支持多个组件。支持多主控器件(某时刻只能有一个主 控器件)。 控器件)。I I2 2C C总线上所有设备的 总线上所有设备的SDA, SCL SDA, SCL引脚必须外接上拉电阻。
单片机很多内部都集成了关于I2C的模块,但是有的并没有,就需要软件的模拟。I2C总线主要两条线SDA 数据线,SCL时钟线。OK,言归正传,说一下I2C咋用。
一个是四种模式(这是对于实际编程所用模块划分):
(1):start :在SCL=1时,保持SDA=1至SDA=0至少4.7us,4个_nop_()就够了,
(2):end 在SCL=1时,保持SDA=0->SDA=1至少 4.7us,同上_nop_()差不多,;
(3):send 除了start和end ,剩下的这两种都是只能在SCL=0的情况下改变SDA的值,传输的过程中保持4us以上,当SCL=1,SDA恒定4us以上。第二个就是应答,每次传输结束后,一般传输用的是一个字节,发送方结束后需要拉高SDA(SDA=1),给出接收方做出应答的机会(呵呵)。
(4):recieve 对于接收的设备,结束时,需要判定要不要给出应答信号,如果继续有传输就给出应答信号(拉低SDA),如果没有就SDA=1,()。
二.控制寄存器:
控制字节
在起始条件之后,必须是器件的控制字节,其中,高四位 为器件类型识别符(不同的芯片类型有不同的定义,E2PROM 为1010),接着三位为片选,最低位为读写控制位,为“1”时为 读操作,为“0”时为写操作。
D3 D2 D1 D0 A2 A1 A0 W/R
前面4位(高四位)就是器件地址,EEPROM(我记得是0xah),这个是可以查到的,许多外部配件都是I2C总线控制,A2~A0,这个是实际地址,具体视电路而为,w0,r1(这是最后一位)
三总结:
最近在弄这个方面所以有了一些心得。
1.应答方面,一定要严格按照要求执行应答机制,因为应答是一个结束还是重新开始的判断。
2.
发送::::start-->(发送地址)-->控制字节--->send; 接收: ;start-->地址--->给出控制字节---->start-->地址--->接收
3.好吧还是上程序我不是很会说(这个是将PCF8591用于转换电压,然后转换数据用一排二极管显示)。
如果有人很想学,有正好看到我的这个杂文,我建议你多注意那个延时nops(),他的位置,还有应答的机制,这个往往决定你能不能好好运行,不好理解可以换成串口显示,比较容易
#include <reg52.h>
#include <intrins.h>
#define nops() do {_nop_();_nop_();_nop_();_nop_();}while(0);
unsigned char LSAVE=0x90;
sbit SDA=P2^0;
sbit SCL=P2^1;
sbit DS1302 = P2^4;
sbit WE=P2^7;
sbit DU=P2^6;//共阴LED
//函数声明
bit ACK();
void doACK(bit b);
void LEDstart();
void LEDend();
unsigned char Recieve();
void Senddata(unsigned char y);
void doACK(bit b){ //判断应答
if(b){
SDA=0;
SCL=1;
nops();
}
else
{ SDA=1;
SCL=1;
nops();
}
SCL=0;
}
bit ACK(){
SCL=1;
SDA=1;
nops();
if(SDA)
{
SCL=0;
LEDend();
return 1;
}
else{
SCL=0;
return 0;
}
}
void LEDstart(){
SDA=1;
SCL=1;
nops();
SDA=0;
nops();
SCL=0;
}
void LEDend(){
SDA=0;
SCL=1;
nops();
SDA=1;
nops();
SDA=0;
}
unsigned char Recieve(){
unsigned char i,dee;
dee=0x00;
for(i=0;i<8;i++){
dee<<=1;
dee|=(unsigned char)SDA;
SCL=1;
nops();
SCL=0;
}
return dee;
}
void Senddata(unsigned char y){
unsigned char i;
for(i=0;i<8;i++){
if (y & 0x80)
SDA = 1;
else
SDA = 0;
SCL=1;
y<<=1;
nops();
SCL=0;
}
}
bit ADdata(unsigned char com,unsigned char *dat){ //AD的关键调用函数
unsigned char dee;
LEDstart();
Senddata(LSAVE);//发送数值之后就要给定回应否则没办法继续下去
if(ACK())
return 1;
Senddata(com);
if(ACK())
return 1;
LEDstart();
Senddata(LSAVE+1);
if(ACK())
return 1;
dee=Recieve();
doACK(0);//必须要不给回应
LEDend();
nops();
*dat=dee;
}
void Serial(){//串口寄存器初始化
SCON=0x50;
PCON=0x00;
TMOD=0x20;
TL1=0xfd;
TH1=0xfd;
TR1=1;
}
void send(unsigned char ans){//传输
SBUF=ans;
while(TI==0);
TI=0;
}
void main(){
unsigned char i=0;
unsigned char ans=0;
//Serial();
DS1302 = 0;
while(1){
i=ans;//记住ans值做判断
ADdata(0x42,&ans);//获得新的ans值
if(i!=ans)//如果ans值改变时才能改变P1的值
P1=ans;
}
}