当前位置:首页 > 单片机 > 单片机
[导读]I2C总线特点 I2C总线最主要的优点是其简单性和有效性。由于接口直接在组件之上,因此I2C总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最

I2C总线特点

I2C总线最主要的优点是其简单性和有效性。由于接口直接在组件之上,因此I2C总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件。I2C总线的另一个优点是,它支持多主控(multimastering), 其中任何能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主控。

2 I2C总线工作原理
I2C总线上的数据稳定规则,SCL为高电平时SDA上的数据保持稳定,SCL为低电平时允许SDA变化。如果SCL处于高电平时,SDA上产生下降沿,则认为是起始位,SDA上的上升沿认为是停止位。通信速率分为常规模式(时钟频率100kHz)和快速模式(时钟频率400kHz)。同一总线上可以连接多个带有I2C接口的器件,每个器件都有一个唯一的地址,既可以是单接收的器件,也可以是能够接收发送的器件。

每次数据传输都是以一个起始位开始,而以停止位结束。传输的字节数没有限制。最高有效位将首先被传输,接收方收到第8位数据后会发出应答位。数据传输通常分为两种:主设备发送从设备接收和从设备发送主设备接收。这两种模式都需要主机发送起始位和停止位,应答位由接收方产生。从设备地址一般是1或2个字节,用于区分连接在同一I2C上的不同器件。

I2C总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。
开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
结束信号:SCL为低电平时,SDA由低电平向高电平跳变,结束传送数据。
应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。

在I2C总线中只有主发送和主接收两种操作方式。在系统初始化时,由指令控制CPU送出相关的数据,经接口送到I2C寄存器内。通过初始化这些寄存器,可以实现I2C总线的主模式控制,以及实现I2C总线上的从设备读写。

当主设备和其中的一个从设备交换数据时,主设备首先发出一个启动Start信号,这个信号被所有的从设备接收。即从设备准备接收CPU的信号,然后主设备再发出它要通信的从设备地址。接下来,所有的从设备将收到的这个地址和它们自己的地址进行比较。

如果收到的地址和它们自己的地址不同,则什么都不做,只是等待主设备发出停止stop信号;如果收到的地址和它自己的地址相同,它就发出一个信号给主设备,这个信号称为应答Acknowledge信号。当主设备收到应答信号后,它就开始向从设备发送数据或者从从设备接收数据。当所有操作都进行完毕时,主设备发出一个Stop信号,通信完毕,释放I2C总线;然后所有的从设备都等待下一次Start信号的到来。

3 总线基本操作
I2C规程运用主/从双向通讯。器件发送数据到总线上,则定义为发送器,器件接收数据则定义为接收器。主器件和从器件都可以工作于接收和发送状态。 总线必须由主器件(通常为微控制器)控制,主器件产生串行时钟(SCL)控制总线的传输方向,并产生起始和停止条件。SDA线上的数据状态仅在SCL为低电平的期间才能改变,SCL为高电平的期间,SDA状态的改变被用来表示起始和停止条件。
3.1 控制字节
在起始条件之后,必须是器件的控制字节,其中高四位为器件类型识别符(不同的芯片类型有不同的定义,EEPROM一般应为1010),接着三位为片选,最后一位为读写位,当为1时为读操作,为0时为写操作。

1.写过程

(1)上电后等待一个延时(1ms)。

(2)器件寻址,给一个起始信号(SCL为高电平时SDA给一个下降沿)。发送从器件地址,高5位为10110,然后根据A1/A0(如果和器件的地址相同则那个器件会应答)进行读/写控制(O为读)。

(3)应答,器件在SCL的第9个周期时SDA给出一个低电平,作为应答信号。

(4)开始写有两种模式:字节写模式和页写模式。

·字节模式:给出A15~A8应答,给出A7~A0应答;然后给出DATA和停止信号 (SCL为高电平时,SDA给出一个上升沿),接着要等待一个擦写时间。

·页写模式:给出地址以后连续给出64个数据。如果多于64个数据,则地址计数器自动翻转。(如果少于64昵,估计是没有问题的,但是需要实验验证。)

(5)判断擦写操作是否完毕的一个方法(应答查询),如果器件还处于擦写状态,则不会应答器件寻址;如果有应答,则说明擦写完毕。

2.读过程

(1)上电以后等待一个延时(lms)。

(2)器件寻址。

(3)应答。

(4)开始读有三种模式:立即当前地址读、选择/随机读、连续读。

·立即当前地址读:如果上次读/写的操作地址为N,则现在是N+1。不需要ACK,但是需要Stop信号。

·选择/随机读:先伪写(用于给出一个地址),然后再次启动,读取数据。

·连续读:读取一个以后给一个应答,这样器件会再给出下一个地址的数据内容。

(5)开始数据传输Start后、停止数据传输Stop前,SCL高电平期间,SDA上为有效数据。

/*******************************************************************
一、程序说明:
1, 24LC02器件地址是1010000R/W.
2, 数组写入24LC02采取页写方式.
3, 数组code从24LC02读出时采取自由读方式.
4, 采用4.00M晶体。
5,采用软件I2C。

二、硬件连接:
1, SDA------->23 pin.(RC4当然你可以任意选择脚位)
2, SCL------->18 Pin.(RC3当然你可以任意选择脚位)
3, PORTC----->外接8个LED,显示读出的数据,在这里,读出的刚好是一个闪动的流水灯状态。

//I2C的应用
//★★★★★★★★★I2C★★★★★★★★★★★\
//单片机型号:PIC16F877A,EEPROM 24LC02B
//实验目的:了解I2C(SPI串行通信)通信的一般步骤方法及协议。
//功能描述:I2C通信,当按下RD0时,把用户定义的数组写到24LC04B中,写完后RB1口灯亮。
// 当按下RD1时,从24LC04B中读出数据,送PORTB口显示。

*******************************************************************/


#include
#define scl TRISC3 //定义时钟线
#define sda TRISC4//定义数据线
#define nop() asm("nop")
//#define nop() asm("asm")
#define uchar unsigned char
__CONFIG(0xf73a);

uchar no,ack,c,data;
uchar code[]={0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff}; //送往24LC04的数据,也是PD口要显示的数据
//void start_i2c();
//void send_byte(uchar c);
//uchar receive_byte(void);
//void i_send_str(uchar sal,uchar suba,uchar *s,uchar no);
//void i_receive_str()


//========================================================================
//功能描述:初始化子程序
//函数名称:init();
void init()
{
TRISC=0xff; //C口设为输入,RC3为SCL线,RC4为SDA线
PORTC=0x00;
TRISB=0x00; //B口设为输出,用来显示IC24LC02中读出的内容
PORTB=0x00;
TRISD=0xff; //D口设为输入,当RD0口为低电平时,开始写,当RD1口为低电来时,开始读。
PORTD=0xff;
}

//========================================================================
//功能描述:延时子程序
//函数名称:delay_250ms();
void delay_250ms()
{
unsigned int d=24999;
while(--d);
}


//========================================================================
//功能描述:I2C启动程序
//函数名称:start_i2c();
void start_i2c()
{
sda=1; //发送启动条件的数据信号
nop();
scl=1;
nop();nop();nop();nop();nop(); //24LC02要求的建立时间
sda=0; //发送起始信号
nop();nop();nop();nop();
scl=0; //钳住I2C总线,准备发送数据或接收数据
nop();nop();
}


//========================================================================
//功能描述:I2C停止程序
//函数名称:stop_i2c();
void stop_i2c()
{
sda=0; //发送结束条件的数据信号
nop();
scl=1;
nop();nop();nop();nop();
sda=1;
nop();nop();nop();nop();
}


//========================================================================
//功能描述:字节传送程序
// Function: 将数据C发送出去,可以是地址,也可以是数据,发完后等待回应,并对此状态
//位进行操作(不应答或非应答都使ack=0 ),发送数据正常,ack=1;ack=0
//表示被控器无应答或损坏
//函数名称:send_byte(uchar c);
void send_byte(uchar c)
{
uchar bit_count;
for(bit_count=0;bit_count<8;bit_count++)
{
if((c<

{sda=1;}
else {sda=0;}
nop();
scl=1;
nop();nop();nop();nop();
scl=0;
}
nop();nop();
sda=1;
nop();nop();
scl=1;
nop();nop();
if(RC4==1) ack=0; //用ACK=1作为有应答信号
else ack=1;
scl=0;
nop();nop();
}


//========================================================================
//功能描述:字节数据接收程序
//FUNCTION: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
//发完后请用应答函数。
//函数名称:receive_byte(void);
uchar receive_byte()
{
uchar retc,bit_count;
retc=0;
sda=1;
for(bit_count=0;bit_count<8;bit_count++)
{
nop();
scl=0;
nop();nop();nop();nop();
scl=1;
nop();nop();
retc=retc<<1;
if(RC4==1) retc=retc+1;
nop();nop();
}
scl=0;
nop();nop();
return(retc);
}


//========================================================================
//功能描述:报错程序
//函数名称:i2c_error();
void i2c_error()
{
uchar i;
for(i=0;i<8;i++)
{
PORTB=0x00;
delay_250ms();
PORTB=0x20;
delay_250ms();
}
}


//========================================================================
//功能描述:向有子地址器件发送多字节程序
//Function: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla。如果
//返回1表示操作成功,否则操作有误
//函数名称:i_send_str(uchar sla,uchar shba,uchar *s,uchar no);
void i_send_str(uchar sla,uchar shba,uchar *s,uchar no)
{
uchar i;
start_i2c();
send_byte(sla); //发送器件地址
if(ack==0) i2c_error();
send_byte(shba); //发送子地址
if(ack==0) i2c_error();
for(i=0;i{
send_byte(*s);
if(ack==0) i2c_error();
s++;
}
stop_i2c();
//return(1);
}


//========================================================================
//功能描述:从器件接收多字节程序
//Function:1.发送器件地址。2。发送字地址。3。发送读命令和器件地址。
//函数名称:i_reveive_str();
void i_receive_str()
{
uchar i;
for(i=0;i<9;i++)
{
start_i2c();
send_byte(0xa0); //发送器件地址
if(ack==0) i2c_error(); //如果无应答,则进入I2C_error错误模式
send_byte(i); //发送字地址
if(ack==0) i2c_error();
start_i2c(); //重新启动总线
send_byte(0xa1); //发送读命令和器件地址
if(ack==0) i2c_error();
data=receive_byte();
stop_i2c();
PORTB=data;
delay_250ms();
}
}


//========================================================================
//功能描述:主程序
//函数名称:main();
#include

#define scl TRISC3 //定义时钟线

#define sda TRISC4 //定义数据线

#define nop() asm("nop")

//#define nop() asm("asm")

#define uchar unsigned char

#define uint unsigned int

__CONFIG(0xf73a);

uchar no,ack,c,data;

uchar code[]={0xff,0x7f,0x5f,0x3f,0x1f}; //送往24LC04的数据,也是PD口要显示的数据

//========================================================================

//功能描述:初始化子程序

//函数名称:init();

void init()

{

TRISC=0xff; //C口设为输入,RC3为SCL线,RC4为SDA线

PORTC=0x00;

TRISB=0x00; //B口设为输出,用来显示IC24LC02中读出的内容

PORTB=0x00;

TRISD=0xff; //D口设为输入,当RD0口为低电平时,开始写,当RD1口为低电来时,开始读。

PORTD=0xff;

}

//========================================================================

//功能描述:延时子程序

//函数名称:delay_250ms();

void delay()

{

unsigned int d=24999;

while(--d);

}

//========================================================================

//功能描述:I2C启动程序

//函数名称:start_i2c();

void start_i2c()

{

sda=1; //发送启动条件的数据信号

nop();

scl=1;

nop();nop();nop();nop();nop(); //24LC02要求的建立时间

sda=0; //发送起始信号

nop();nop();nop();nop();

scl=0; //钳住I2C总线,准备发送数据或接收数据

nop();nop();

}

//========================================================================

//功能描述:I2C停止程序

//函数名称:stop_i2c();

void stop_i2c()

{

sda=0; //发送结束条件的数据信号

nop();

scl=1;

nop();nop();nop();nop();

sda=1;

nop();nop();nop();nop();

}

//========================================================================

//功能描述:字节传送程序

// Function: 将数据C发送出去,可以是地址,也可以是数据,发完后等待回应,并对此状态

//位进行操作(不应答或非应答都使ack=0 ),发送数据正常,ack=1;ack=0

//表示被控器无应答或损坏

//函数名称:send_byte(uchar c);

void send_byte(uchar c)

{

uchar bit_count;

for(bit_count=0;bit_count<8;bit_count++)

{

if((c<

else {sda=0;}

nop();

scl=1;

nop();nop();nop();nop();

scl=0;

}

nop();nop();

sda=1;

nop();nop();

scl=1;

nop();nop();

if(RC4==1) ack=0; //用ACK=1作为有应答信号

else ack=1;

scl=0;

nop();nop();

}

//========================================================================

//功能描述:字节数据接收程序

//FUNCTION: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),

//发完后请用应答函数。

//函数名称:receive_byte(void);

uchar receive_byte()

{

uchar retc,bit_count;

retc=0;

sda=1;

for(bit_count=0;bit_count<8;bit_count++)

{

nop();

scl=0;

nop();nop();nop();nop();

scl=1;

nop();nop();

retc=retc<<1;

if(RC4==1) retc=retc+1;

nop();nop();

}

scl=0;

nop();nop();

return(retc);

}

//========================================================================

//功能描述:报错程序

//函数名称:i2c_error();

void i2c_error()

{

uchar i;

for(i=0;i<8;i++)

{

PORTB=0x00;

delay();

PORTB=0x20;

delay();

}

}

//========================================================================

//功能描述:向有子地址器件发送多字节程序

//Function: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla。如果

//返回1表示操作成功,否则操作有误

//函数名称:i_send_str(uchar sla,uchar shba,uchar *s,uchar no);

void i_send_str(uchar sla,uchar shba,uchar *s,uchar no)

{

uchar i;

start_i2c();

send_byte(sla); //发送器件地址

if(ack==0) i2c_error();

send_byte(shba); //发送子地址

if(ack==0) i2c_error();

for(i=0;i

{

send_byte(*s);

if(ack==0) i2c_error();

s++;

}

stop_i2c();

//return(1);

}

//========================================================================

//功能描述:从器件接收多字节程序

//Function:1.发送器件地址。2。发送字地址。3。发送读命令和器件地址。

//函数名称:i_reveive_str();

void i_receive_str()

{

uchar i;

for(i=0;i<5;i++)

{

start_i2c();

send_byte(0xa0); //发送器件地址

if(ack==0) i2c_error(); //如果无应答,则进入I2C_error错误模式

send_byte(i); //发送字地址

if(ack==0) i2c_error();

start_i2c(); //重新启动总线

send_byte(0xa1); //发送读命令和器件地址

if(ack==0) i2c_error();

data=receive_byte();

stop_i2c();

PORTB=data;

delay();

}

}

//========================================================================

//功能描述:主程序

//函数名称:main();

main()

{

init();

while(1)

{

if(RD0&&RD1)

{

i_send_str(0xa0,0x00,code,5); //发送多个字节

PORTB=0x01;

}

delay();

if(!RD0&&!RD1)

{ i_receive_str();}

}

}

//*****************************************************************************先发送数据,后接收数据。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

本文中,主要在于讲解如何利用pic单片机实现红外夜视仪设计。如果你对本文内容具有兴趣,不妨继续往下阅读哦。

关键字: pic单片机 指数 红外夜视仪

为帮助大家解决pic单片机应用难点,本文将对pic单片机硬件死锁问题予以讲解。

关键字: pic单片机 指数 死锁

电子相关专业的朋友对于pic单片机自然十分熟悉,为增进大家对pic单片机的认识,本文将继续为大家介绍pic单片机。本文中,小编将对pic单片机的PAGE和BANK予以阐述。

关键字: pic单片机 指数 单片机

    本文主要介绍的就是基于DM642的视频采集处理系统中I2C模块的正确初始化,以及通过I2C总线正确地对视频解码芯片SAA7115的寄存器读/写程序。   1 I

关键字: dm642 i2c 视频采集

    串行总线和并行总线相比具有结构简单、占用引脚少、成本低的优点。常见的串行总线有USB、IEEE1394、I2C等,其中I2C总线具有使用简单的特点,在单片机、串行E2P

关键字: vhdl i2c 串行总线

对于pic单片机,大家都很熟悉,pic单片机是诸多类型单片机中最为受用的一款。本文是《pic单片机实际应用,基于pic单片机实现IC卡读写器(上)》的余下内容。如果你对pic单片机具有兴趣,抑或对pic单片机的应用充满好...

关键字: ic卡读写器 pic单片机 指数

为帮助大家增进对pic单片机的认识,本文将介绍如何基于pic单片机实现IC卡读写器。本文仅为上篇,剩余内容请翻阅下篇。

关键字: pic单片机 指数 ic卡读写器

为增进大家对pic单片机的了解,本文将对pic单片机开发环境以及pic单片机的引脚3状态予以讲解。如果你对pic单片机具有兴趣,不妨继续往下阅读哦。

关键字: pic单片机 开发环境 指数

  I2C简介   I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。主器件用于启动总线传送数据,并产生时钟以开

关键字: Arduino i2c
关闭
关闭