独家揭秘!2024年IIC原理深度解析与物联网嵌入式开发秘籍——火爆IT圈阿里内部笔记

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

主机就是负责整个系统的任务协调与分配,从机一般是通过接收主机的指令从而完成某些特定的任务,主机和从机之间通过总线连接,进行数据通讯。

  • 发布主要命令的称为主机
  • 接受命令的称为从机
  • 半双工和全双工:

    IIC的协议层

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

  • 开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。
  • 结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。
  • 应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
  • 这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。

    IIC 总线时序图

    img

    下面我们来详细的介绍下IIC的通信协议流程:

    初始(空闲)状态

    因为IIC的 SCL 和SDA 都需要接上拉电阻,保证空闲状态的稳定性

    所以IIC总线在空闲状态下SCL 和SDA都保持高电平

    代码:

    void IIC\_init()       //IIC初始化
    
    {
    
           SCL=1; //首先把时钟线拉高
    
           delay\_us(4);//延时函数
    
           SDA=1; //在SCL为高的情况下把SDA拉高
    
           delay\_us(4); //延时函数
    
    }
    
    
    开始信号:

    SCL保持高电平,SDA由高电平变为低电平后,延时(>4.7us),SCL变为低电平。

    代码表示:

    //产生IIC起始信号
    //1.先拉高SDA,再拉高SCL,空闲状态
    //2.拉低SDA
    void IIC\_Start()         //启动信号
    
    {
           SDA=1; //确保SDA线为高电平
           delay\_us(5);
           SCL=1;  //确保SCL高电平
           delay\_us(5);
           SDA=0; //在SCL为高时拉低SDA线,即为起始信号
           delay\_us(5);
           SCL=0;   //钳住I2C总线,准备发送或接收数据 
        
    }
    
    
    停止信号

    停止信号:SCL保持高电平。SDA由低电平变为高电平。

    //产生IIC停止信号
    //1.先拉低SDA,再拉低SCL
    //2.拉高SCL
    //3.拉高SDA
    //4.停止接收数据
    void IIC\_Stop(void)
    {
    
    	IIC_SCL=0;
    	IIC_SDA=0;    //STOP:当SCL高时,数据由低变高
     	delay\_us(4);
    	IIC_SCL=1; 
    	IIC_SDA=1;    //发送I2C总线结束信号
    	delay\_us(4);							   	
    }
    
    

    在起始条件产生后,总线处于忙状态,由本次数据传输的主从设备独占,其他I2C器件无法访问总线;而在停止条件产生后,本次数据传输的主从设备将释放总线,总线再次处于空闲状态。

    数据有效性

    IIC信号在数据传输过程中,当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。

    SCL=1时 数据线SDA的任何电平变换会看做是总线的起始信号或者停止信号。

    也就是在IIC传输数据的过程中,SCL时钟线会频繁的转换电平,以保证数据的传输

    img

    应答信号

    每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据,

    应答信号:主机SCL拉高,读取从机SDA的电平,为低电平表示产生应答

  • 应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
  • 应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
  • **每发送一个字节(8个bit)**在一个字节传输的8个时钟后的第九个时钟期间,接收器接收数据后必须回一个ACK应答信号给发送器,这样才能进行数据传输。

    应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答,

    //主机产生应答信号ACK
    //1.先拉低SCL,再拉低SDA
    //2.拉高SCL
    //3.拉低SCL## 标题
    void I2C\_Ack(void)
    {
       IIC_SCL=0;   //先拉低SCL,使得SDA数据可以发生改变
       IIC_SDA=0;   
       delay\_us(2);
       IIC_SCL=1;
       delay\_us(5);
       IIC_SCL=0;
    }
    
    
    //主机不产生应答信号NACK
    //1.先拉低SCL,再拉高SDA
    //2.拉高SCL
    //3.拉低SCL
    void I2C\_NAck(void)
    {
       IIC_SCL=0;   //先拉低SCL,使得SDA数据可以发生改变
       IIC_SDA=1;   //拉高SDA,不产生应答信号
       delay\_us(2);
       IIC_SCL=1;
       delay\_us(5);
       IIC_SCL=0;
    }
    
    
    

    等待应答信号:

    //等待应答信号到来
    //返回值:1,接收应答失败
    // 0,接收应答成功
    char IIC\_Wait\_Ack(void)
    {
    	u8 ucErrTime=0;
    	 
    	IIC_SDA=1;delay\_us(1);	   
    	IIC_SCL=1;delay\_us(1);	 
    	while(IIC_SDA)
    	{
    		ucErrTime++;
    		if(ucErrTime>250)
    		{
    			IIC\_Stop();
    			return 1;
    		}
    	}
    	IIC_SCL=0;//时钟输出0 
    	return 0;  
    } 
    
    
    IIC数据传送
    数据传送格式

    SDA线上的数据在SCL时钟“高”期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的“高”或“低”状态才可以改变。输出到SDA线上的每个字节必须是8位,数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。

    当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位ACK, 此时才认为一个字节真正的被传输完成 ,如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。

    img

    IIC写数据:

    img

    多数从设备的地址为7位或者10位,一般都用七位。
    八位设备地址=7位从机地址+读/写地址,

    再给地址添加一个方向位位用来表示接下来数据传输的方向,

  • 0表示主设备向从设备(write)写数据,
  • 1表示主设备向从设备(read)读数据
  • IIC的每一帧数据由9bit组成,

    如果是发送数据,则包含 8bit数据+1bit ACK,

    如果是设备地址数据,则8bit包含7bit设备地址 1bit方向

    在起始信号后必须传送一个从机的地址(7位) 1~7位为7位接收器件地址,第8位为读写位,用“0”表示主机发送数据(W),“1”表示主机接收数据 (R), 第9位为ACK应答位,紧接着的为第一个数据字节,然后是一位应答位,后面继续第2个数据字节。

    IIC发送一个字节数据:

    //IIC发送一个字节
    //返回从机有无应答
    //1,有应答
    //0,无应答 
    
    //IIC\_SCL=0;
    //在SCL上升沿时准备好数据,进行传送数据时,拉高拉低SDA,因为传输一个字节,一个SCL脉冲里传输一个位。
    //数据传输过程中,数据传输保持稳定(在SCL高电平期间,SDA一直保持稳定,没有跳变)
    //只有当SCL被拉低后,SDA才能被改变
    //总结:在SCL为高电平期间,发送数据,发送8次数据,数据为1,SDA被拉高,数据为0,SDA被拉低。
    //传输期间保持传输稳定,所以数据线仅可以在时钟SCL为低电平时改变。
    void IIC\_Send\_Byte(u8 txd)
    {                        
        u8 t;   
        SDA\_OUT();         
        IIC_SCL=0;//拉低时钟开始数据传输
        for(t=0;t<8;t++)
        {              
            //IIC\_SDA=txd&0x80; //获取最高位
            //获取数据的最高位,然后数据左移一位
            //如果某位为1,则SDA为1,否则相反
            if(txd&0x80)
                IIC_SDA=1;
            else
                IIC_SDA=0;
            txd<<=1;       
            delay\_us(2);   
            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,否则相反
            IIC_SDA=((txd&0x80)>>7);
            txd<<=1;
    
    
    
    

    IIC读取一个字节数据:

    
    //读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;
    }
    
    
    
    IIC发送数据


    Start: IIC开始信号,表示开始传输。
    DEVICE_ADDRESS:: 从设备地址,就是7位从机地址
    R/W: W(write)为写,R(read)为读
    ACK: 应答信号
    WORD_ADDRESS : 从机中对应的寄存器地址 比方说访问 OLED中的 某个寄存器
    DATA: 发送的数据
    STOP: 停止信号。结束IIC

    主机要向从机写数据时:

    1. 主机首先产生START信号
    2. 然后紧跟着发送一个从机地址,这个地址共有7位,紧接着的第8位是数据方 向位(R/W),0表示主机发送数据(写),1表示主机接收数据(读)
    3. 主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,若相同,则认为自己正在被主机寻址,根据R/T位将自己确定为发送器和接收器
    4. 这时候主机等待从机的应答信号(A)
    5. 当主机收到应答信号时,发送要访问从机的那个地址, 继续等待从机的应答信号
    6. 当主机收到应答信号时,发送N个字节的数据,继续等待从机的N次应答信号,
    7. 主机产生停止信号,结束传送过程。
    IIC读数据:


    主机要从从机读数据时

    img
    img

    既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

    由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

    如果你需要这些资料,可以戳这里获取

    poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
    主机要从从机读数据时

    [外链图片转存中…(img-pOERcjBs-1715624903966)]
    [外链图片转存中…(img-XQe3QJ5A-1715624903967)]

    既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

    由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

    如果你需要这些资料,可以戳这里获取

    作者:普通网友

    物联沃分享整理
    物联沃-IOTWORD物联网 » 独家揭秘!2024年IIC原理深度解析与物联网嵌入式开发秘籍——火爆IT圈阿里内部笔记

    发表回复