IIC协议

本文详细介绍了IIC(二线式串行总线)的工作原理,包括时钟线SCL和数据线SDA的作用,通信协议的细节,如开始、结束信号的发送,以及发送和接受过程中的操作步骤。同时,文章强调了两个上拉电阻的重要性以及IIC的仲裁机制,确保多主机环境下的数据通信顺利进行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

IIC:两线式串行总线,它是由数据线SDA和时钟线SCL构成的串行总线,可以发送和接收数据。

时钟线SCL:在通信过程起到控制作用。

数据线SDA:用来一位一位的传送数据。

但是IIC是半双工通信方式。同一时间段,SDA的输入端和输出端只有一端有效。

通信协议

1、(在发送、接收数据的时候)当SCL为高电平的时候,SDA不允许变化,此时是某端在读取数据;当SCL为低电平的时候,SDA允许变化,此时是某端在放置数据

2、(在任意时刻)只有在SCL为高电平时,IIC电路才对SDA线上的电平(0/1)进行记录;当SCL为低电平时候,无论SDA是什么状态,IIC都不对SDA进行记录

空闲状态

又称初始状态,就是没有开始通信的状态,此时SCL和SDA两根线都处于高电平。此时各个器件的输出级场效管处于截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

开始信号与停止信号

开始信号:当SCL处于高电平状态的时候,SDA由高到低的跳变。

void I2C_Start(void)
    {
        //起始数据端和时钟端都是高电平
        I2C_W_SCL(1);
        I2C_W_SDA(1);
        //
        delay_us(5);
        //在时钟端是高电平的时候拉低数据端 此时表明开始
        I2C_W_SDA(0);
        delay_us(5);
        //然后时钟端拉低等待数据变化
        I2C_W_SCL(0);
        delay_us(5);
        printf("I2C_Start Ok\n");
    }

结束信号:当SCL为高电平状态时候,SDA由低到高的跳变。

void I2C_Stop()
{
    //拉低数据位表明结束
    I2C_W_SDA(0);
    delay_us(5);
    //然后通讯结束后两端又拉到高电平
    I2C_W_SCL(1);
    I2C_W_SDA(1);
    printf("I2C_Stop\n");
}

发送过程

(一)先找相应寄存器

(二)再找寄存器当中存数据的地址

(三)发送数据

由上述通信协议可知:SCL处于低电平状态时,SDL是某端在放数据;SCL处于高电平状态时,SDL是IIC电路在读数据

SDA该现处于输出状态,将所需要发送的数据一位一位从最高位发给从端。

void I2C_Send_Byte(uint8_t data)
    {
        uint8_t i;
        for(int i=0;i<8;i++)
        {
            I2C_W_SDA(data&(0x80>>i));//SDA每次发送1位数据,且从最高位开始
            delay_us(5);
            I2C_W_SCL(1);//时钟拉高,这样从机就能接收到
            delay_us(5);
            I2C_W_SCL(0);//时钟拉低,表明主机这会需要放置下一位数据,
            delay_us(5);
        }
        printf("I2C_Send_Byte Ok\n");
    }

(四)应答信号

当主端给从端每发一个字节,由接收器反馈一个应答信号,如果应答信号为1表明接收器并未作出接收动作,为0表示准备好接收。

SCL处于低电平状态时,将SDA线拉低,确保在SCL处于高电平时能给读到稳定的低电平。

综上一个完整的发送过程格式如下图所示:

void I2C_RA()
    {
        I2C_W_SDA(1);//主机放弃掌握权,从机准备拿取掌握权
        delay_us(5);
        I2C_W_SCL(1);//数据拉高,表明从机已经将回复的数据交到SDA线,准备读取
        if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==1)
        {//如果从机给主机回的是高电平,那么就是从机拒绝与主机连接,处于忙碌
            return;
        }
    //否则接收主机连接
        delay_us(5);
        I2C_W_SCL(0);//为下一次放置数据做准备
        delay_us(5);
        printf("I2C_RA Ok\n");
    }

如果结束即回复1

void I2C_SA()
    {
        I2C_W_SDA(1);
        delay_us(5);
        I2C_W_SCL(1);
        I2C_W_SCL(0);
        printf("I2C_SA Ok\n");
    }

接受过程

(一)随机接受

与发送过程相同,先找到对应寄存器,从中读取数据,注意这个数据是从机随机给主机发的,值不一定是想要的。

(二)指定位置接受

根据发送过程,我们不难发现发送的前两步是为了找到一个固定位置,此时这里有一个指针去指向该空间。那么如果我们想要读取指定位置的值,就可以先将想要的数据对应地址的指针找到,要这个指针先指向该空间,当我们二次发送寄存器位置的时候,从机直接从该指针位置处读取数据,这样就能得到我们想要的值。

uint8_t I2C_Read_Byte()
    {
        uint8_t data=0x00;
        uint8_t i;
        I2C_W_SDA(1);
        for(int i=0;i<8;i++)
        {
            I2C_W_SCL(1);
            if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==1)
            {
                data |=(0x80>>i);
            }
            I2C_W_SCL(0);
        }
        printf("I2C_Read_Byte Ok\n");
        return data;
    }
    void I2C_Read()
    {
     uint8_t data;
    I2C_Start();
    I2C_Send_Byte(0xA0);
    
    //接收应答
    I2C_RA();
    //发送写地址
    I2C_Send_Byte(0x11);
    //接收应答
     I2C_RA();
    
    I2C_Start();
    I2C_Send_Byte(0xA1);
    
    //接收应答
    I2C_RA();
    data = I2C_Read_Byte();
    printf("read data:%x\n",data);
    
    I2C_SA();
    I2C_Stop();
    }

注意点

1、为什么要有两个上拉电阻

如果有两个从机同时给主机发送1和0,这样就会形成短路,其中一个器件会受到损失。因此为了让从机不受到伤害,将从机的P-Mos管取掉,这样从机只能输出低电平,为了能够输出高电平,就在外面加两个上拉电阻。(也就形成了开漏模式+上拉模式)

就形成这样一个图,要想输出高电平,只需要让从机不输出低电平即可,上拉电阻提供高电平。

注意这里的电阻不能太小,如果过大输出的电流对从机有伤害。

此外:如果电阻过大,流向下端电流变小,从低电平变成高电平变化的这个爬坡阶段就会变得缓慢(有点像功能不足)

如果电阻过小,流向下端电流变大,则供能过大,这样就会出现爬坡巨快

以上两种情况都会让我们的数据失真。

2、I2C的仲裁机制

1.“线与”机制: 多主机时,总线具有“线与”的逻辑功能,即只要有一个节点发送低电平时,总线上就表现为低电平。 2.SDA回读机制: 总线被启动后,多个主机在每发送一个数据位时都要对自己的输出电平进行检测,只要检测的电平与自己发出的电平一致,就会继续占用总线。 3.低电平优先机制:由于线与的存在,当多主机发送时,谁先发送低电平谁就会掌握对总线的控制权。

3.仲裁结果: 仲裁结束后,获胜的主设备将继续发送其数据,而其他设备则将停止发送并等待下一个通信机会。 4.重试机制: 如果多个主设备的仲裁结果是平局,即它们的地址相同或优先级相同,通常会启用重试机制。在重试机制中,设备会等待一段随机时间后重新尝试发送数据,以避免再次发生冲突。

 

第一位大家都是1,那么都是高电平,这时候仲裁不发生,在第二位的时候,主机3为低电平,而其余为高电平,根据低电平优先,则主机三掌握主动权,主机2和主机1放弃掌握转而接受,此时1和2停止转发数据,主机3将剩余数据发送完后,主机1和主机2 继续,而在第四位时主机1和2 不一样,主机2 掌握主动权,主机2将剩余数据发完后主机1从第一位重新开始发送。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值