【通信协议】IIC通信协议详解

2023-05-16

IIC的基本介绍

IIC总线的发展:

       芯片间总线(Inter Interface Circuit,IIC),是应用广泛的芯片间串行扩展总线。目前世界上采用的IIC总线一共有两个规范,分别由荷兰飞利浦公司和日本索尼公司提出的,现在基本采用荷兰飞利浦的IIC总线的技术规范。

IIC总线的优点:

        1、IIC总线优点中最主要的优点是其简单性(IIC只有两条信号线)和有效性(根据SCL线上的时钟线来判断)。带有IIC总线的接口的单片机都可直接与具有IIC总线接口的各种扩展器件(如存储器、I/O芯片、A/D、D/A、键盘、显示器、时钟、日历等)连接。由于IIC总线采用纯软件的寻址方法,无须片选线的连接,这样就大大的简化了总线的数量。

        2、IIC总线的另一个优点是允许多主器件任何能够进行发送和接收的设备都可以成为主总线一个主控能够控制信号的传输和时钟频率,在任何时间点上只能有一个主控。在实际应用中,经常遇到的是以单一单片机为主器件,其他外围接口期间为从器件的情况。

IIC总线的缺点:

        在标准的IIC普通模式下,数据的传输速率为100kbit/s,高速模式下可以达到400kbit/s。

        IIC所接的外围器件的数量并不是无穷多的,总线上的扩展的期间数量是由限制的。总线上的扩展的期间数量并不是由电流负载决定的,而是由电容负载决定的。IIC总线上的每个器件的接口都有一定的等效电容,器件越多(扩展外围器件可以看作是并联在主器件的总线上的),电容值就越大,就会造成信号传输的延迟。

        总线上允许接的器件数量以器件的电容量不能超过400pF(可以通过其他的方法增加总线的电容量),据此可以算出总线的长度扩展外围器件的数量

IIC的总线系统的基本结构:

        IIC总线总共只有两条信号线,一条是双向的串行数据线SDA,另一条是串行时钟线SCL。SDA和SCL都是双向的,IIC总线上的各器件的数据线都接到SDA线上,IIC总线上的各器件的时钟线都接到SCL线上。

        每个连接到IIC总线上的器件都有一个唯一的地址,扩展期间时要受到器件地址数量的限制。IIC的总线系统的基本结构如图所示。

 

IIC的总线物理拓扑结构:

        当IIC总线空闲时,SDA和SCL两条线均为高电平。由于连接到总线上的器件输出级必须是漏极开路或者集电极开路的,因此只要有一个器件任意时刻输出低电平,都将总线上的信号变低,即各器件的SDA和SCL都是“线与“的关系。

        由于各器件输出端为漏极开路,则SCL和SDA线必须通过上拉电阻接正电源,以保证SDA和SCL在空闲状态被上拉到高电平。IIC总线的拓扑结构如图所示。

 

IIC协议介绍

IIC总线的起始信号与终止信号:

        IIC 总线在传送数据过程中一共有三种类型的信号,它们分别是:开始信号(S)、结束信号(P)和应答信号。

        开始信号:在SCL 串行时钟线为高电平期间,SDA 线由高电平向低电平的变化表示起始信号,只有在起始信号以后,其他命令才有效。

        结束信号:在SCL 串行时钟线为高电平期间,SDA 线由低电平向高电平的变化表示终止信号,随着终止信号的出现,所有外部操作就结束。

 

IIC总线上数据传送的应答信号:

        应答信号:IIC总线进行数据传送时,传送的字节数并没有限制,但是每个字节长必须为8位长。数据传送过程中,先传送最高位(MSB),每一个被传送的字节后面都必须跟随着1位应答位(即一帧共有9位长)。

        1、应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;

        2、应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。

        对于反馈有效应答位ACK的要求是:接收器在第9个时钟脉冲之前的低电平期间将数据线SDA拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放数据线SDA,以便主控接收器发送一个停止信号P。

 

IIC总线上数据有效性:

        IIC总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定;只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。 

        即:SDA线上的数据在SCL时钟“高”期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的“高”或“低”状态才可以改变。

 

 IIC总线上数据帧格式:

 

IIC总线上传送的数据信号不仅包括真正的数据信号,并且包括地址信号。

       IIC总线规定,在起始信号后面必须传送一个从器件的地址(7位),第8位是数据传送的方向位(R/`W),用“0”来表示主器件发送(`W),“1”表示主器件接受数据(R)。每次数据传送总是由主器件产生终止信号而结束。但是,如果主器件希望继续占用总线进行新的数据传送,则可以不产生终止信号,而马上再次发出起始信号对另一从器件进行寻址操作。因此,在总线一次数据传送过程中,可以由以下几种组合方式。

       (1)、主器件向从器件发送N个字节的数据。

        数据传送方向在整个传送的方向过程并没有变化,数据传送的格式如图所示。

 

       其中N个字节是由主机写入从器件的N个字节的数据。淡蓝色部分表示数据由主机向从机传送,粉红色部分则表示数据由从机向主机传送。

        上述的从设备地址为7位,紧接其后的读/写标志位决定了主器件的读写方向写用“0” (低电平)来表示,读用“1” (高电平)来表示。

 

        1、主机首先产生START信号;

        2、然后紧跟着发送一个从机地址,这个地址共有7位,紧接着的第8位是数据方向位(R/`W),“0”表示主机发送数据(写),“1”表示主机接收数据(读);

        3、主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,若相同,则认为自己正在被主机寻址,根据R/T位将自己确定为发送器和接收器;

        4、这时候主机等待从机的应答信号(A);

        5、当主机收到应答信号时,发送要访问从机的那个地址, 继续等待从机的应答信号;

        6、当主机收到应答信号时,发送N个字节的数据,继续等待从机的N次应答信号;

        7、主机产生停止信号,结束传送过程。

       (2)、主器件读来自从机的N字节。

        除第一个寻址字节由主机发送,N个字节都是由从器件发送,主器件接收,数据传送的格式如图所示。

 

        在从机产生响应时,主机从发送变成接收,从机从接收变成发送。之后,数据由从机发送,主机接收,每个应答由主机产生,时钟信号仍由主机产生。若主机要终止本次传输,则发送一个非应答信号,紧接着主机产生停止条件。

 

        1、主机首先产生START信号;

        2、然后紧跟着发送一个从机地址,注意此时该地址的第8位为0,表明是向从机写命令;

        3、这时候主机等待从机的应答信号(ACK);

        4、当主机收到应答信号时,发送要访问的地址,继续等待从机的应答信号;

        5、当主机收到应答信号后,主机要改变通信模式(主机将由发送变为接收,从机将由接收变为发送)所以主机重新发送一个开始start信号,然后紧跟着发送一个从机地址,注意此时该地址的第8位为1,表明将主机设置成接收模式开始读取数据;

        6、这时候主机等待从机的应答信号,当主机收到应答信号时,就可以接收1个字节的数据,当接收完成后,主机发送非应答信号,表示不再接收数据;

        7、主机进而产生停止信号,结束传送过程。

(3)、主器件的读、写操作。

        在一次数据传送过程中,主器件先发送一个字节的数据,然后再接收一个字节的数据,此时起始信号和从器件地址都要被重新产生一次,但两次读写的方向位刚好相反,数据传送的格式如图所示。

 

        图中的“RS”表示重新产生的起始信号,后面一个从设备地址表示重新产生的从器件地址

        由上可知,无论哪种形式,起始信号、终止信号和从器件地址均由主器件发送,数据字节的传送方向则由主器件发出的寻址字节中的方向位决定,每个字节的传送都必须有应答位(A或者`A)相随。

      

IIC总线上的寻址字节:

        在上面介绍的数据帧格式中,均有7位从器件地址和紧随其后的1位读/写方向位,即寻址字节。IIC总线的寻址采用软件寻址,主器件在发送完起始信号后,立即发送寻址字节来寻址被控的从器件,寻址字节格式如图所示。

 

       7位从器件地址为“1010”(AT24C02芯片的固定地址)和“A2A1A0”,其中前四位为器件地址,即器件固有的地址编码,器件出厂时就已经给定。“A2A1A0”为引脚地址,由器件引脚“A2A1A0”在电路中接高电平或接地决定,

       数据方向位(R/`W)规定了总线上的单片机(主器件)与从器件的数据传送方向位。R/`W=1,表示主器件接收(读),R/`W=0,表示主器件发送(写)。

IIC总线上数据传送格式:

        IIC总线上每传送一位数据都与一个时钟脉冲相对应,传送的每一帧数据均为一个字节。但启动IIC总线后传送的字节数并没有限制,只要求每传送一个字节后,对方回应一个应答位即可。

       IIC总线数据传送必须遵循规定的数据传送格式。根据总线协议规范,起始信号表明一次数据传送的开始,其后为寻址字节。在寻址字节后是按指定读写的数据字节与应答位。在数据传送完成后主器件都必须发送终止信号。在起始信号与终止信号之间的传输的数据字节数由主器件(单片机)决定,理论上讲没有字节数量的限制。

       由上述的数据传送格式可知:

       (1)、无论何种数据传送格式,寻址字节都有主器件发出,数据字节的传送方向则由寻址字节中的方向位来决定。

       (2)、寻址字节只表明了从器件的地址和数据传送方向。从器件内部的N个数据地址,由器件设计者在该器件的IIC总线数据操作格式中,指定第一个数据字节作为器件内部的单元地址指针,并且设置地址自动加减功能,以减少从器件地址的寻址操作。

       (3)、每个字节传送必须有应答信号(A或者`A)相随.

       (4)、从器件在接收到起始信号后都必须释放数据总线,使其处于高电平,以便主器件发送从机地址。

    IIC总线底层程序

IIC总线引脚与函数定义:

        采用PB6PB7来模拟IIC时序, PB6为时钟线(SCL),PB7为数据线(SDA)。

        关于宏定义与函数定义的代码。

//IO方向设置
 
#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}

//IO操作函数	 
#define IIC_SCL    PBout(6) 			//SCL
#define IIC_SDA    PBout(7) 			//SDA	 
#define READ_SDA   PBin(7)  		    //输入SDA 

//IIC所有操作函数
void IIC_Init(void);                	//初始化IIC的IO口				 
void IIC_Start(void);					//发送IIC开始信号
void IIC_Stop(void);	  				//发送IIC停止信号
void IIC_Send_Byte(u8 txd);			    //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);	//IIC读取一个字节
u8 IIC_Wait_Ack(void); 				    //IIC等待ACK信号
void IIC_Ack(void);					    //IIC发送ACK信号
void IIC_NAck(void);					//IIC不发送ACK信号

        由于IIC是半双工通信方式:

        (1)、数据线SDA可能会数据输入,也可能是数据输出,需要定义IIC_SDA来进行输出、READ_SDA来进行输入,与此同时就要对IO口进行模式配置:SDA_IN()SDA_OUT()

        (2)、时钟线SCL一直是输出的,所以不用区分时钟线的输入和输出。

IIC总线典型信号以及字节收发的模拟子程序:

(1)总线初始化函数

        初始化函数的功能是将SCL和SDA总线拉高以释放总线。

子程序代码如下:

void IIC_Init(void)								        //初始化IIC
{					     
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );  //使能GPIOB时钟
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;  		//推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); 				//PB6,PB7 输出高
}

(2)起始信号S函数

        起始信号S,要求一个新的起始信号前总线的空闲时间必须大于4.7us,而对于一个重复的起始信号,要求建立事件也必须大于4.7us,如下图所示,起始信号的时序波形在SCL高电平器件SDA发生负跳变。起始信号S到第一个时钟脉冲负跳变沿的时间间隔应大于4us.

 子程序代码如下:

void IIC_Start(void)	 //产生IIC起始信号
{
	SDA_OUT();           //sda线输出
	IIC_SDA=1;	  	  
	IIC_SCL=1;
	delay_us(4);
 	IIC_SDA=0;		    //START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL=0;		    //钳住I2C总线,准备发送或接收数据 
}

3)终止信号P函数

        终止信号:在SCL高电平期间SDA的一个上升沿产生终止信号。如下图所示。

 

子程序代码如下: 

void IIC_Stop(void)		//产生IIC停止信号
{
	SDA_OUT();			//sda线输出
	IIC_SCL=0;
	IIC_SDA=0;			//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL=1; 
	IIC_SDA=1;			//发送I2C总线结束信号
	delay_us(4);							   	
}

(4)应答位/数据“0”函数

        发送接收应答位与发送数据“0”相同,即在SDA低电平期间SCL发生一个高电平,如下图所示。

子程序代码如下:

//产生ACK应答
void IIC_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}

 

        SCL在高电平期间,SDA被从器件被拉为低电平表示应答。

(5)非应答位/数据“1”函数

        发送非应答位与发送数据“1”相同,即在SDA高电平期间SCL发生一个正脉冲,如下图所示。

子程序代码如下:

//不产生ACK应答		    
void IIC_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}

 

(6)字节收发子程序函数

        除了上述的典型信号的模拟外,在IIC总线的数据传送过程中,经常使用单字节数据的发送和接收。

       1、发送1字节数据子程序。下面是模拟IIC的数据线由SDA发送1字节的数据(可以是地址,也可以是数据),发送完后等待应答,并对状态位ACK进行操作,即应答或非应答都使ACK=0,发送数据正常ACK=1,从器件无应答或损坏,则ACK=0。发送一字节数据参考程序如下。

子程序代码如下:

//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	SDA_OUT(); 	    
    IIC_SCL=0;					//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1; 	  
		delay_us(2);   			//对TEA5767这三个延时都是必须的
		IIC_SCL=1;
		delay_us(2); 
		IIC_SCL=0;	
		delay_us(2);
    }	 
} 	
//IIC_SDA=txd&0x80;   
//获取最高位
//获取数据的最高位,然后右移7位,假设为 1000 0000 右移7位为 0000 0001 
// 假设为 0000 0000 右移7位为 0000 0000 
//如果某位为1,则SDA为1,否则相反

 

        发送串行1字节时,” IIC_SDA=(txd&0x80)>>7;”中,txd和0x80进行与运算后再右移七位,则把运算出来的结果赋给数据线(IIC_SDA),并发送出去,紧接着txd左移一位,把次高位移到最高位,再进行下一次循环即可。这样进行8次,就能把1字节的数据都发送出去就可以达到发送一个字节的目的。

1、接收1字节数据子程序。

        下面是模拟从IIC的数据线SDA接收从器件传来的1字节数据的子程序。

子程序代码如下:

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
    unsigned char i,receive=0;
    SDA_IN();						    //SDA设置为输入
    for(i=0;i<8;i++ )
    {
        IIC_SCL=0; 
        delay_us(2);
	    IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)
            receive++;   
	    delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();				    //发送nACK
    else
        IIC_Ack(); 				    //发送ACK   
    return receive;
}

         同理,串行接收1字节的数据时,需将八位的数据一位一位地接收,然后在组合成1字节。“receive<<=1;     if(READ_SDA)       receive++;”这三行代码可以理解为在SCL为高电平时,接收READ_SDA的高低电平状态,如果READ_SDA的电平为高时,receive加1,相当于低位赋1;如果READ_SDA的电平为低时,receive不进行,相当于低位赋0。这样循环八次,receive就相当于存储了一字节的数据,在判断这亿字节数据后面的应答信号是应答位还是非应答位,进行判断,最终把接收到一个字节数据的变量传出去即可。

利用IIC总线扩展EEPROM AT24C02的IC卡设计:

        通用存储器的IC卡是由通用存储器芯片封装而成,由于其结构与功能简单、成本低、使用方便,所以在各个领域都得到了广泛的应用。目前用于IC卡的通用存储器芯片多为EEPROM,且应用于IIC总线接口,典型器件为ATMEL公司的IIC接口的AT24Cxx系列。该系列具有AT24C01/02/04/08/16等型号,它们的封装形式,引脚功能以及内部结构类似,只是容量不同,分别为128B/256B/512B/1KB/2KB。下面以AT24C02为例,介绍单片机如何通过IIC总线对AT24C02进行读写。

(1)封装与引脚。

        AT24C02的封装形式由双列直插(DIP)8只引脚和贴片(SOP)8只引脚两种,无论哪种封装,其引脚功能都是一样的。AT24C02的引脚如图所示。

 

1、A0,A1,A2:硬件地址引脚。

2、WP:写保护引脚,接高电平只读,接地允许读和写。

3SCL和SDA:IIC总线。

4、GND,VCC为电源引脚。

 AT24C02引脚功能如表所示。

 

(2)存储单元的寻址。

AT24C02的存储容量为256B,分为32页,每页8B.对片内单元访问操作,需要先对芯片寻址然后在进行片内子地址寻址。

       1、芯片寻址。

AT24C02芯片地址固定为1010,它是IIC总线器件的特征编码,其地址控制字节的格式为1010 A2 A1 A0 R/非W。A2,A1,A0引脚接高、低电平后得到确定的3为编码,与1010形成7位编码,即为该器件的地址码。由于A2\A1\A0共有八种组合,故系统最多可外接8片AT24C02,R/非W是对芯片的读/写控制位。

       2、片内子地址寻址。

在确定了AT24C02芯片的7位地址码后,片内的存储空间可用1字节的地址码进行寻址,寻址字节位00H~FFH,即可对片内的256个单元进行读/写操作。

(3) 初始化AT24CXX。

子程序代码如下:

//初始化IIC接口
void AT24CXX_Init(void)
{
    IIC_Init();
}

 (4) 检查检查AT24CXX是否正常。

(4) 检查检查AT24CXX是否正常。

子程序代码如下:
//检查AT24CXX是否正常
//这里用了24XX的最后一个地址(255)来存储标志字.
//如果用其他24C系列,这个地址要修改
//返回1:检测失败
//返回0:检测成功
u8 AT24CXX_Check(void)
{
	u8 temp;
	temp=AT24CXX_ReadOneByte(255);		        //避免每次开机都写AT24CXX			   
	if(temp==0X55)
return 0;		   
	else										//排除第一次初始化的情况
	{
		AT24CXX_WriteOneByte(255,0X55);
	    temp=AT24CXX_ReadOneByte(255);	  
		if(temp==0X55)
return 0;
	}
	return 1;											  
}

 

(5) 向AT24C02中写数据。

AT24C02有两种写入方式,即字节写入方式页写入方式

       1、字节写入方式

单片机(主器件)先发送启动信号和1字节的控制字,从器件发出应答信号后,单片机再发送1字节的存储单元子地址(AT24C02芯片内部单元的地址码),单片机收到AT24C02的应答后,再发送八位数据和一位终止信号。

       2、页写入方式

单片机先发送启动信号和1字节的控制字,再发送1字节的存储器起始单元地址,上述几个字节都将得到AT24C02的应答后,就可以发送最多一页的数据,并顺序存放在已指定的起始地址开始的相继的单元中,最终以终止信号结束。

       1、MCU先发送一个开始信号(START)启动总线;

        2、接着跟上首字节,发送器件写操作地址(DEVICE ADDRESS)+写数据(0xA0);

        3、等待应答信号(ACK);

        4、发送数据的存储地址。24C02一共有256个字节的存储空间,地址从0x00~0xFF,想把数据存储>在哪个位置,此刻写的就是哪个地址;

        5、发送要存储的数据第一字节、第二字节、…注意在写数据的过程中,E2PROM每个字节都会>回应一个“应答位0”,老告诉我们写E2PROM数据成功,如果没有回应答位,说明写入不成功;

        6、发送结束信号(STOP)停止总线。

子程序代码如下:

//在AT24CXX指定地址写入一个数据
//WriteAddr  :写入数据的目的地址    
//DataToWrite:要写入的数据
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{				   	  	    																 
    IIC_Start();  
    if(EE_TYPE>AT24C16)
    {
	    IIC_Send_Byte(0XA0);	    					 //发送写命令
	    IIC_Wait_Ack();
	    IIC_Send_Byte(WriteAddr>>8);					 //发送高地址
     }
    else
    {
	    IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));	     //发送器件地址0XA0,写数据 
    }	 
    IIC_Wait_Ack();	   
    IIC_Send_Byte(WriteAddr%256);   					 //发送低地址
    IIC_Wait_Ack(); 	 										  		   
    IIC_Send_Byte(DataToWrite);     					 //发送字节				   
    IIC_Wait_Ack();  		    	   
    IIC_Stop();										     //产生一个停止条件 
    delay_ms(10);	 
}



//在AT24CXX里面的指定地址开始写入长度为Len的数据
//该函数用于写入16bit或者32bit的数据.
//WriteAddr  :开始写入的地址  
//DataToWrite:数据数组首地址
//Len        :要写入数据的长度2,4
void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
{  	
    u8 t;
    for(t=0;t<Len;t++)
    {
	    AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
    }												    
}
    

//在AT24CXX里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer   :数据数组首地址
//NumToWrite:要写入数据的个数
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
    while(NumToWrite--)
    {
	    AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
	    WriteAddr++;
	    pBuffer++;
    }
}

 

        温馨提示:在写数据的过程中,每成功写入一个字节,E2PROM存储空间的地址就会自动加1,当加到0xFF后,再写一个字节,地址就会溢出又变成0x00

       (6) 向AT24C02中读数据。

       AT24C02的读操作页由两种方式,即指定地址读方式指定地址连续读方式

       1、指定地址读方式

单片机发送启动信号后,先发送含有芯片地址的写操作控制字,AT24C02应答后,单片机再发送1字节的指定单元的地址,AT24C02应答后再发送1个含有芯片地址的读操作控制字,此时如果AT24C02做出应答,被访问单元的数据就会按照SCL信号同步出现在SDA线上,以供单片机读取。

       2、指定地址连续读方式。

指定地址连续读方式是单片机收到每个字节数据都要做出应答,只要AT24C02检测到应答信号,其内部的地址寄存器就自动加一指向下一个单元,并顺序将指向单元的数据送到SDA线上。当需要结束读操作时,单片机接收到数据后,在需要应答的时刻发送一个非应答信号,紧接着再发送一个终止信号即可。

        1、MCU先发送一个开始信号(START)启动总线;

        2、接着跟上首字节,发送器件写操作地址(DEVICE ADDRESS)+写数据(0xA0);

(注意:这里写操作是为了要把所要读的数据的存储地址先写进去,告诉E2PROM要读取哪个地址的数据)

        3、发送要读取内存的地址(WORD ADDRESS),通知E2PROM读取要哪个地址的信息;

        4、重新发送开始信号(START);

        5、发送设备读操作地址(DEVICE ADDRESS)对E2PROM进行读操作 (0xA1);

        6、E2PROM会自动向主机发送数据,主机读取从器件发回的数据,在读一个字节后,MCU会回应一个应答信号(ACK)后,E2PROM会继续传输下一个地址的数据,MCU不断回应应答信号可以不断读取内存的数据;

        7、如果不想读了,告诉E2PROM不想要数据了,就发送一个“非应答位NAK(1)”。发送结束信号(STOP)停止总线。

子程序代码如下:

//在AT24CXX指定地址读出一个数据
//ReadAddr:开始读数的地址  
//返回值  :读到的数据
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{				  
    u8 temp=0;		  	    												 
    IIC_Start();  
    if(EE_TYPE>AT24C16)
    {
	    IIC_Send_Byte(0XA0);	   						 //发送写命令
	    IIC_Wait_Ack();
	    IIC_Send_Byte(ReadAddr>>8);					 //发送高地址
	    IIC_Wait_Ack();		 
    }
    else 
        IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));	 //发送器件地址0XA0,写数据 
    IIC_Wait_Ack(); 
    IIC_Send_Byte(ReadAddr%256);   				 //发送低地址
    IIC_Wait_Ack();	    
    IIC_Start();  	 	   
    IIC_Send_Byte(0XA1);           				 //进入接收模式			   
    IIC_Wait_Ack();	 
    temp=IIC_Read_Byte(0);		   
    IIC_Stop();									 //产生一个停止条件	    
    return temp;
}


//在AT24CXX里面的指定地址开始读出长度为Len的数据
//该函数用于读出16bit或者32bit的数据.
//ReadAddr   :开始读出的地址 
//返回值     :数据
//Len        :要读出数据的长度2,4
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
{  	
    u8 t;
    u32 temp=0;
    for(t=0;t<Len;t++)
    {
	    temp<<=8;
	    temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1); 	 				   
    }
    return temp;												    
}

//在AT24CXX里面的指定地址开始读出指定个数的数据
//ReadAddr :开始读出的地址 对24c02为0~255
//pBuffer  :数据数组首地址
//NumToRead:要读出数据的个数
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
    while(NumToRead)
    {
	    *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);	
	    NumToRead--;
    }
}

 

IIC总线通信方式总结:

        1、进行数据传送时,在SCL为高电平期间,SDA线上电平必须保持稳定,只有SCL为低时,才允许SDA线上电平改变状态。并且每个字节传送时都是高位在前;

        2、对于应答信号,ACK=0时为有效应答位,说明从机已经成功接收到该字节,若为1则说明接受不成功;

        3、如果从机需要延迟下一个数据字节开始传送的时间,可以通过把SCL电平拉低并保持来强制主机进入等待状态;

        4、主机完成一次通信后还想继续占用总线在进行一次通信,而又不释放总线,就要利用重启动信号。它既作为前一次数据传输的结束,又作为后一次传输的开始;

        5、总线冲突时,按“低电平优先”的仲裁原则,把总线判给在数据线上先发送低电平的主器件;

        6、在特殊情况下,若需禁止所有发生在I2C总线上的通信,可采用封锁或关闭总线,具体操作为在总线上的任一器件将SCL锁定在低电平即可;

        7、SDA仲裁和SCL时钟同步处理过程没有先后关系,而是同时进行的。

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【通信协议】IIC通信协议详解 的相关文章

  • SPI通信协议

    spi通信协议概念 xff1a SPI是一种有线通信协议 xff0c 用于两个设备之间的全双工数据传输 xff08 所谓的全双工 xff0c 就是该协议可以同时进行收发数据 xff09 SPI 规定了两个 SPI 设备之间通信必须由主设备
  • OLED显示屏驱动:8080并口,IIC,SPI三种驱动方式

    本文介绍了对OLED的几种驱动方式 xff0c 8080并口 xff0c IIC xff0c SPI三种驱动方式 xff0c 采用的单片机是STM32F407 文章目录 一 OLED驱动原理介绍二 8080并口驱动方式三 IIC驱动方式四
  • PX4-5-SPI-IIC设备驱动

    在之前的分享中 xff0c 我们聊了PX4的通信框架和任务调度框架 xff0c 现在我们讲一下PX4的设备驱动 PX4支持很多种设备 xff0c 根据通信方式的不同大致分为 xff1a SPI IIC设备 串口设备 IO设备 CAN设备 这
  • IIC通信协议

    IIC通信协议 一 什么是IIC通信协议 xff1f 二 IIC协议时序分析1 空闲状态2 起始信号和停止信号3 数据传输 xff08 1 xff09 写操作 字节写 xff08 2 xff09 写操作 页写 xff08 3 xff09 读
  • IIC通讯总结

    1 IIC简介 IIC全称Inter Integrated Circuit 是由PHILIPS公司在80年代开发的两线式串行总线 xff0c 用于连接微控制器及其外围设备 IIC属于半双工同步通信方式 2 IIC特点 xff08 1 xff
  • 基于STM32平台的BMP180测试(模拟IIC)

    1 测试描述 xff1a 使用模拟IIC xff0c 从BMP180中获取ID号 温度值 气压值以及计算海拔高度 2 测试准备 xff1a 硬件平台 xff1a 原子战舰V3开发板 测试工具 xff1a 逻辑分析仪 串口调试工具 3 数据手
  • IIC上拉电阻的选择

    上周项目评审的时候 xff0c 评审部门问了我一个问题 xff1a 为什么单片机内部有上拉电阻 xff0c 你们还要用外部的上拉电阻 xff1f 我的答复如下 xff1a 上拉电阻的选取要考虑上限值和下限值这两点 xff1a 上限值的最大限
  • 详解 Modbus 通信协议(清晰易懂)

    文章目录 已剪辑自 https mp weixin qq com s dvo1l1GgJ2DtIHnPK5E1tA 本文总结关于 Modbus 相关的知识 xff0c 浅显易懂 xff0c 旨在对 Modbus 有一个很直观的了解 如有错误
  • IIC总线基础知识

    IIC总线基础知识 一 简介 IIC xff08 Inter Integrated Circuit xff09 是一个多主从的串行总线 xff0c 又叫I2C xff0c 是由飞利浦公司发明的通讯总线 xff0c 属于半双工同步传输类型总线
  • STM32——硬件IIC从机通信

    前言 xff1a 根据网上的资料 xff0c 大部分网友表示STM32自带的硬件IIC存在bug xff0c 读写时很容易卡死 自己在调试的时候也出现卡死的情况 xff0c 最后一点一点调试 xff0c 也还是调通了 本文将记录自己调试ST
  • spi,iic,uart,pcie区别

    一 spi SPI 是英语Serial Peripheral interface的缩写 xff0c 顾名思义就是串行外围设备接口 xff0c 是同步传输协议 xff0c 特征是 xff1a 设备有主机 xff08 master xff09
  • 总线协议一(UART/RS232/RS485/IIC/SPI)

    目录 基础概述 xff1a 一 UART xff08 为串口通信方式 xff09 二 RS232协议 三 RS485协议 四 I2C总线协议 五 SPI总线 六 I2C和SPI的区别 基础概述 xff1a 总线的本质就是一根导线 xff0c
  • STM32软件模拟iic驱动oled(显示汉字,图片)(二)

    在上一篇介绍的软件模拟iic及iic源码后 xff0c 今天来实现显示汉字与图片以及各个函数的介绍 一 函数介绍及使用 1 显示字符 OLED ShowStr unsigned char x unsigned char y unsigned
  • UART、IIC、SPI、CAN通信的区别与应用

    文章目录 1 通信的基本知识1 1 数据通信的种类1 1 1 串行通信1 1 2 并行通信1 1 3 总结 1 2 数据通信的传输方向1 2 1 单工1 2 2 半双工1 2 3 全双工1 2 4 总结 1 3 数据通信的方式1 3 1 同
  • Modbus通信协议

    一 Modbus 协议简介 Modbus 协议是应用于电子控制器上的一种通用语言 通过此协议 xff0c 控制器相互之间 控制器经由网络 xff08 例如以太网 xff09 和其它设备之间可以通信 它已经成为一通用工业标准 有了它 xff0
  • IIC通信总线寻址

    IIC的使用 IIC总线简介IIC通信时序IIC总线寻址 IIC总线简介 1 IIC总线是一种由PHILIPS公司开发的两线式串行总线 2 IIC在硬件上是时钟总线SCL和数据总线SDA两条线构成 3 器件连接到总线都是SCL连到一起 xf
  • UART,SPI,IIC,RS232通信时序和规则

    一 UART 1 串口通信方式 2 串口通信步骤 注意 xff1a 串口协议规定 xff0c 闲置时必须是高电平 校验位 xff1a 是使用奇偶校验 停止位必须高电平 一个0和多个0区分是靠掐时间 异步通信 xff1a 时钟各不一样 二 I
  • 【Unity3D】在Unity中使用Protobuf(proto3)

    有研究表明 一条消息数据 用protobuf序列化后的大小是json的10分之一 xml格式的20分之一 是二进制序列化的10分之一 ProtoBuf的优势还是很明显的 这里简单介绍哈使用 一 下载protobuf https github
  • Tcp建立连接为什么需要三次握手

    前言 众所周知tcp传输层协议在建立连接的时候需要三次才能建立起一个真正的可靠连接 可是为什么是三次呢 不可以是两次 四次等等呢 可以自己思考一番 带着疑问可以看下文 三次握手 在 计算机网络 一书中其中有提到 三次握手的目的是 为了防止已
  • 计算机网络中的通信子网:架构、协议与技术简介

    在计算机网络中 通信子网是负责实现主机之间以及主机与终端之间数据传输的核心部分 它由一系列硬件设备和通信协议组成 为上层应用提供可靠 高效和透明的数据传输服务 本文将详细介绍通信子网的架构 协议与技术 一 通信子网的架构 星型拓扑 星型拓扑

随机推荐

  • FreeRTOS内核——任务与任务切换

    2 任务 相关函数 1 xTaskCreateStatic 2 prvInitialiseNewTask 3 prvInitialiseTaskLists 4 vTaskStartScheduler 5 xPortStartSchedule
  • FreeRTOS应用——任务

    12 任务 12 1 相关函数 12 1 1 任务创建函数与启动调度 12 1 1 1 xTaskCreateStatic 静态创建任务 if configSUPPORT STATIC ALLOCATION 61 61 1 TaskHand
  • FreeRTOS应用——消息队列

    13 消息队列 消息队列是一种常用于任务键通信的数据结构 xff0c 队列可以在任务与任务间 中断与任务间传递信息 xff0c 实现了任务接收来自其他任务或者中断的不定长数据 任务能从队列中读取信息 xff0c 当队列中的消息为空时 xff
  • RoboMaster电机驱动

    1 硬件 1 1 电机 RM有很多不同型号的电机 xff0c 不同型号的电机有它不同的用途 xff0c 但是以用途分类的话主要是分成两种电机 xff1a 用来精准控制位置的电机 xff0c 在RM中的主要是云台电机 RM官网上的云台电机只有
  • 数据结构——校园导游系统

    校园导游系统 1 要求 大二下学期修了数据结构这门课 xff0c 课设的要求是做一个校园导航系统 详细的要求如下 问题描述 xff1a 当我们参观校园时 xff0c 会遇到如下问题 xff1a 从当前所处位置去校园另外一个位置 xff0c
  • 平衡小车实现

    平衡小车 1 前期准备 1 1 I2C通讯协议 在与MPU6050进行数据的读取时需要用到I2C通讯协议来进行通信 物理层 IIC一共有只有两个总线 xff1a 一条是双向的串行数据线SDA xff0c 一条是串行时钟线SCL SDA Se
  • 关于STM32CubeMX生成不了Keil代码的解决办法

    关于STM32CubeMX生成Keil代码时弹出but MDK ARM project generation have a problem的问题 有两种可能 xff1a 1 输出路径或文件名包含中文 2 Java环境版本不匹配 下载 xff
  • 2020电赛D题绕组飞行器

    在准备电赛的过程中 xff0c 做了一下去年的题 xff0c 本文将介绍我的方案及部分代码 xff0c 希望可以帮助到大家 一 我的装备 由于初学飞控所以主控用的是匿名的拓空者 xff0c 还有匿名的光流传感器 xff0c 北醒的激光雷达
  • nuxtjs常见问题

    1 在服务器端部署 xff0c 需要再服务器端安装node modules 2 本地忽略 nuxt文件夹 xff0c 这个需要在服务器端上执行npm run build生成 xff0c 然后执行 pm2 start npm name 34
  • Ubuntu学习笔记:sudo:vim:command not found

    Ubuntu学习笔记 xff1a sudo xff1a vim xff1a command not found 完成 xff01
  • Ubuntu学习笔记:查看所有用户

    Ubuntu学习笔记 xff1a 查看所有用户 输入 cat etc passwd cut f 1 d 注意 xff01 结尾有一个 xff1a 效果如下 xff1a
  • Ubuntu学习笔记:cd命令

    Ubuntu学习笔记 xff1a cd命令 命令顺序 xff1a 创建一个名为aaa的文件夹 进入指定文件夹 返回上一级文件夹 进入指定文件夹 返回上一级文件夹 退回上一次操作的文件夹 显示上一次操作的文件夹所在的路径 退回多级文件夹 退回
  • Ubuntu学习笔记:swapon 失败:设备或资源忙

    swapon 失败 xff1a 设备或资源忙 用命令swapoff xff0f 交换分区 将交换分区停止 然后再用swapon命令重新加载即可
  • Ubuntu学习笔记:使用命令查看当前登录系统的用户信息

    Ubuntu学习笔记 xff1a 使用命令查看当前登录系统的用户信息 1 查看当前登录的用户名 2 查看当前登录的用户名 终端类型 时间 IP地址 3 服务器连接的所有用户及正在使用的进程 4 显示系统中有哪些使用者正在上面 xff0c 显
  • Ubuntu学习笔记:使用命令查看系统资源,内存使用情况

    Ubuntu学习笔记 xff1a 使用命令查看系统资源 xff0c 内存使用情况 方法1 打开资源管理器 资源 gnome system monitor 方法2 top命令 方法3 下载htop apt get install htop h
  • Ubuntu学习笔记:使用命令修改 root 用户的密码

    Ubuntu学习笔记 xff1a 使用命令修改 root 用户的密码 Ubuntu 每次开机都有一个随机的新的 root 密码 在不知道密码的情况下 xff0c 要重新修改root密码 方法 xff1a sudo passwd 输入用户登录
  • C语言的特点

    1 语言简洁 紧凑 xff0c 使用方便 灵活 xff1b 2 运算符丰富 xff1b 3 数据类型丰富 xff1b 4 具有结构化的控制语句 xff08 例如if else语句 while语句 do while语句 switch语句和fo
  • Win11 更新绕过TPM2.0 方法 最新最简单 亲测有效 Win11系统更新 DEV方式

    最新的win11内测把不符合硬件规定的人都排除出去了 xff0c 虽然有注册表导入可以挤到DEV通道 xff0c 不过在更新到8 会弹出显示设备不支持提示 xff0c 关闭窗口后升级被取消 因此特在实践后教大家如何绕过TPM2 0 更新的方
  • iview常见问题

    1 radio组 label如果为字符串可以默认选中 xff0c 如果为数字 xff0c 却没有反应 答 xff1a label为数字时 xff0c 需要在label前加 xff1a 来绑定 xff0c 这样就可以实现默认选中了
  • 【通信协议】IIC通信协议详解

    IIC的基本介绍 IIC总线的发展 xff1a 芯片间总线 xff08 Inter Interface Circuit xff0c IIC xff09 xff0c 是应用广泛的芯片间串行扩展总线 目前世界上采用的IIC总线一共有两个规范 x