📄 i2c协议.txt
字号:
虚拟I2C接口通信协议
I2C协议规定在数据传送过程中必须确认数据传送的开始和结束。I2C协议技术规范中规定SCL为高电平,SDA由高电平向低电平跳变定为数据传送的开始;当时钟线SCL为高电平,数据线SDA由低电平向高电平跳变为结束信号。开始信号和结束信号都由主器件产生。在开始信号产生以后,总线即被认为忙状态。在信号结束一段时间内,总线被认为是空闲的。
I2C总线的数据传输格式是在I2C总线开始后,送出来的第一个字节数据用来选择从器件地址的。其中前7位为地址码,第8位为方向位(R/W),方向位为0表示发送,即主器件把数据写到所选择的从器件中去;方向位为1表示读取,即主器件读取从器件中指定的地址的信息。开始后系统中各器件把自己的地址和主器件送到总线上的地址进行比较,如果和主器件发送到总线上的地址一致,则该器件即为被主器件寻址的器件,其接收信息还是发送信息由第8位(R/W)。I2C总线每次传送的字节数据不限,但每一字节必须是8位,而且每个传送的字节后面必须跟一个认可位(第9位),也叫应答位。每次传送都是先传最高位,通常器件在接收每字节后都会做响应,即释放SCL线,返回高电平,准备接收下一个字节数据,主器件可以继续发送。如果从器件正在处理一个实时事件而不能接收数据,可以使SCL线保持低电平。此时主器件产生一个结束信号,使发送异常结束,迫使主器件处于等待状态。当从器件处理完毕时,释放SCL总线,主器件继续传送。
当主器件发送完一字节数据后,接着发送对应于SCL线上的一个时钟(ACK)认可位,此时钟内主器件释放SDA线,一字节传送结束,而从器件的响应信号将SDA线,一个字节传送结束,而从器件响应信号使SDA线拉成低电平,使SDA在该时钟的高电平期间为稳定的低电平。从器件响应信号结束后,SDA线返回高电平进入下一个传送周期。
模拟I2C总线的C51程序
#i nclude<reg51.h>
#i nclude<intrins.h>
#define uchar unsigned char;
#define uint unsigned int ;
#define _Nop() _nop_();
/* 端口定义*/
sbit SDA=P1^3; /*模拟I2C数据位8*/
sbit SCL=P1^2; /*模拟I2C时钟位8*/
/*状态标志位*/
bit ACK;
/********************void Start_I2C()****************
该函数为总线启动函数
****************************************************/
viod Start_I2C(void)
{
SDA=1; /*发送起始条件数据信号*/
_Nop();
SCL=1;
_Nop(); /*起始条件建立时间大于4.7us*/
_Nop();
_Nop();
_Nop();
_Nop();
SDA=0; /*发送起始信号*/
_Nop(); /*起始条件信号锁定时间大于4us*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0; /*钳住I2C总线准备发送数据*/
_Nop();
_Nop();
}
/********************void Stop_I2C()****************
该函数为总线结束函数
****************************************************/
viod Stop_I2C()
{ SDA=0; /*发送结束条件数据信号*/
_Nop(); /*发送结束条件数据信号*/
SCL=1;
_Nop(); /*起始条件建立时间大于4.7us*/
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1; /*发送结束信号*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
}
/********************void SendB(uchar c )****************
该函数为字节数据传送函数,功能是将数据C发送出去,
C可以是地址,也可以是数据,发完后等待应答,并对此状态
位进行操作。
****************************************************/
void SendB(uchar c )
{
unchar BitCnt;
for(BitCnt=0;BitCnt<8;Bit++) /*要传送的数据长度为8位*/
{
if((c<<BitCnt)&0x80) SDA=1; /*判断发送位*/
else SDA=0;
_Nop();
SCL=1 /*置时钟线为高电平通知被控制器开始接收数据*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0;
}
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1; /*8位数据发送完毕,释放数据总线准备接收应答*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
if(SDA==1) ack=0; /*判断是否收到应答*/
else ack=1;
SCL=0;
_Nop();
_Nop();
}
/********************void RcvB( )***********************
该函数为字节数据接收函数,功能是接收从器件传来
的数据,并判断总线是否正确,发完后调用应答函数。
*********************************************************/
uchar RcvB()
{
uchar rctc;
uchar BitCnt;
retc=0;
SDA=1; /*置数据线为输入方式*/
for(BitCnt=0;BitCnt<8;BitCnt++)
{
_Nop();
SCL=0; /*置时钟线为低电平准备接收数据*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SCL=1; /*时钟线为高使数据线上的数据有效*/
_Nop();
_Nop();
retc=retc<<1;
if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放到retc中*/
_Nop();
_Nop();
}
SCL=0;
_Nop();
_Nop();
return(retc);
}
/*************************************void Ack_I2c( )**********************************
该函数为应答子函数,功能是主控制器进行应答信号(可以是应答或非应答信号)
****************************************************************************************/
void Ack_I2c(bit a)
{
if(a==0)SDA=0; /*在此发出应答或非应答信号*/
else SDA=1;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0;
_Nop();
_Nop();
_Nop();
}
/*************bit ISentB(uchar sla,uchar c)******************
该函数为向无子地址器件发送字节数据函数,功能是启动总线到发送地址,
数据,结束总线的全过程,从器件地址sla如果返回1,表示操作成功,否则
操作有误。
*************************************************************/
bit ISentB(uchar sla,uchar c)
{
Star_I2c();
SendB(sla);
if(ack==0) return(0);
SendB(c);
if(ack==0) return(0);
Stop_I2c();
return(1);
}
/************bit ISendStr(uchar sla,uchar suba,uchar s,uchar no)**************************
该函数为向有子地址器件发送多字节数据函数,功能是从启动总线到发送地址,子地址,
数据结束总线全过程,从器件地址sla,子地址suba,发送内容是s指向的内容,发送no字节
如果返回1表示操作成功,否则失败。
***********************************************************************************************/
bit ISendStr(uchar sla,uchar suba,uchar s,uchar no)
{
unchar i;
Star_I2c();
SendB(sla);
if(ack==0) return(0);
SendB(suba);
if(ack==0) return(0);
for(i=0;i<no;i++)
{
SendB(*s);
if(ack==0) return(0);
s++
}
Stop_I2c();
return(1);
}
/************bit IRcvStr(uchar sla,uchar suba,uchar s,uchar no)**************************
该函数为向有子地址器件读取多字节数据函数,功能是从启动总线到发送地址,子地址,
数据结束总线全过程,从器件地址sla,子地址suba,读取内容放入s所指向的存取区,读取no字节
如果返回1表示操作成功,否则失败。
***********************************************************************************************/
bit IRcvStr(uchar sla,uchar suba,uchar s,uchar no)
{
unchar i;
Star_I2c();
SendB(sla);
if(ack==0) return(0);
SendB(suba);
if(ack==0) return(0);
Star_I2c();
SendB(sla+1);
if(ack==0) return(0);
for(i=0;i<no;i++)
{
*s=RcvB();
Ack_I2c(0);
s++
}
*s=RcvB();
Ack_I2c(1);
Stop_I2c();
return(1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -