I2C总线是菲利普公司推出的一种串行总线,具备多主机系统所需总线裁决和高低速期间同步的高性能总线。
I2C总线具有两个双向传输的信号线,一根是数据线SDA,一根是时间线SCL。
每个接到I2C总线上的器件都有唯一的地址。主机与其它器件间的数据传送可以是由主机发送数据到其它器件,这时主机即为发送器。由总线上接收数据的器件则为接收器。
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
/*
** 一下为80C51为例,说明通过I2C总线控制EEPROM的存取。
*/
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit sda=P2^0;
sbit scl=P2^1;
void delay() {;;}
void init();
void i2c_start();
void i2c_stop();
void snd_byte(uchar dat)
void write(uchar addr, uchar info);
void ack();
uchar read(uchar addr);
uchar rec_byte();
/*
** 驱动主程序
*/
void main() { ...}
/*
** 初始化
*/
void init()
{
scl=1;
delay();
sda=1;
delay();
}
/*
** SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号。
*/
void i2c_start()
{
sda=1
delay();
scl=1;
delay();
sda=0;
}
/*
** SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号
*/
void i2c_stop()
{
sda=0
delay();
scl=1;
delay();
sda=1;
}
/*
** 写EEPROM,时序流程为发送设备地址,并告诉从机要写数据(0为写入,
** 1为读出)。从设备响应后发送写入地址,从设备响应后发送写入数据
** 从设备响应后停止,具体见下图:
*/
/*
** 向EEPROM写一字节数据,以串行方式从高位(MSB)开始按位发送。
*/
void snd_byte(uchar dat)
{
uchar temp,i;
i=0;
temp=dat;
while(i++<8)
{
temp=temp<<1;
scl=0;
delay();
sda=CY; //CY是PSW溢出位寄存器
delay();
scl=1;
delay();
}
/*
** 拉高SDA,释放总线
*/
scl=0;
delay();
sda=1;
delay();
}
/*
** EEPROM从设备响应信号。
*/
void ack()
{
uchar i;
i=0;
scl=1;
delay();
/*
** 若从设备sda不发生跳变并且没有发送完LSB,
** 则持续轮询sda
*/
while((sda==1)&&(i++<255));
scl=0;
delay();
}
/*
** 从EEPROM读取数据,时序为主设备寻找设备,从设备响应,
** 主设备寻址,从设备响应。重新启动I2C总线,发送设备地址,
** 并设置读/位为读,从设备响应后发送数据,停止总线
** 时序如下图:
*/
void read(uchar addr)
{
uchar info;
i2c_start();
write(0xa0); //寻找设备,设置为写模式
ack();
write(addr); //设备寻址
ack();
i2c_start(); //重新启动I2C总线
write(0xa1); //寻找设备,设置为读模式
ack();
info=rec_byte();
i2c_stop;
return
}
/*
** 从EEPROM读一字节数据,以串行方式从高位(MSB)开始按位发送。
*/
uchar rec_byte()
{
int i;
uchar j,k;
scl=0;
delay();
sda=1;
for(i=0;i<8;i++) // 一字节有八位,循环八次依次读取数据
{
scl=1; // 在一个时钟周期内读取sda总线数据
delay();
j=sda;
k=(k<<1)|j; // 移位存储从EEPROM读回的数据
scl=0;
delay();
}
return k;
}
发表评论 评论 (2 个评论)