嵌入式——时序IIC

概念

IIC,或者I2C,年"I方C",集成电路总线,是同步串行半双工通信总线方式。该总线允许同时连接多个设备(芯片),每个芯片在总线上有特定的地址

SDA:数据线

SCL:时钟线

两个信号线都是双向的,在硬件电路设计上,是必须要接上拉电阻,因为这是一种双开漏的通信模式,引脚只能主动拉低电平,无法主动输出高电平,需要上拉电阻来提供稳定的高电平,同时实现多设备 "线与" 通信逻辑

开漏和推挽

GPIO通过两个MOS管来控制引脚的高低电平

开漏模式:当GPIO处于该模式下,只允许出现2,3情景,高阻态下,相当于断路

推挽模式:当GPIO处于该模式下,只允许出现1,2情景

时序

总线处于空闲时,不管是SCL,还是SDA线,均处于高电平状态,所以总线上的设备都处于开漏模式中的高阻态。当某个设备想要通信时,就先在总线上发送start起始信号,把SDA拉低,此时会在SCL上产生时钟信号,是高低电平交错的脉冲信号

1,start信号:在总线空闲时(高电平),主机在时钟线SCL为高电平时,在数据线SDA上产生一个下降沿,称之为起始信号

2,发送数据时

1)遵循高位优先原则MSB

2)在SCL为低电平时,只允许发送方改变SDA数据线(高1低0),接收方不得采样SDA

3)在SCL为高电平时,只允许接收方采样SDA数据线,此时发送方需保证数据线稳定

3,应答位(9clock第九个bit)

1)ACK:应答,类似真人回复

2)NACK:非应答,类似自动回复

4,stop型号:在主机不需要再通信时,主机在SCL为高电平时,在数据线SDA上产生一个上升沿,称之为停止信号

从机地址

为了确定接收的从机,规定发送的第一个字节必须具有特定含义,前七个bit位为从机地址,第八个为数据流向位,指的是通信的过程的收发方,0为主机发送从机接收,1则相反

线与特性

|-------|-------|------|
| chipA | chipB | 实际电平 |
| 1 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 1 | 1 |
| 0 | 0 | 0 |

当一个芯片输出高电平,真实的引脚电平由外接的芯片、上下拉电路决定

PSR引脚状态寄存器

所需寄存器

写函数

cs 复制代码
void i2c_write(I2C_Type *base, unsigned char dev_addr, unsigned short reg_addr, int reg_len, unsigned char *data, unsigned int len)
{
    int stat = 0;
    //0. 清除IAL、IIF, 
    base->I2SR &= ~(I2SR_IAL | I2SR_IIF);
    //1. 设置为发送模式
    base->I2CR |= I2CR_MTX;
    //2.start信号
    base->I2CR |= I2CR_MSTA;

    //3.发送从机地址及数据流向位
    base->I2DR = ((dev_addr << 1) | 0);
    stat = wait_i2c_iif(base);
    if (stat != 0) goto stop;

    //4.发送从机寄存器地址
    int i = reg_len - 1;
    for (; i >=0; i--)
    {
        base->I2DR = (reg_addr >> (i * 8)) & 0xFF;
        stat = wait_i2c_iif(base);
        if (stat != 0) goto stop;  
    }

    for (i = 0; i < len; i++)
    {
        base->I2DR = data[i];
        stat = wait_i2c_iif(base);
#if AT24C02
        if (((reg_addr + (i + 1)) % 8 == 0) && ((i + 1) < len))
        {
            //发送stop信号
            base->I2CR &= ~I2CR_MSTA; 
            delay_ms(5);

            //2.start信号
            base->I2CR |= I2CR_MSTA;

            //3.发送从机地址及数据流向位
            base->I2DR = ((dev_addr << 1) | 0);
            stat = wait_i2c_iif(base);
            if (stat != 0) goto stop;

            //4.发送从机寄存器地址
            int j = reg_len - 1;
            for (; j >= 0; j--)
            {
                base->I2DR = ((reg_addr + (i + 1)) >> (j * 8)) & 0xFF;
                stat = wait_i2c_iif(base);
                if (stat != 0) goto stop;  
            }
        }
#endif
        if (stat != 0) goto stop;
    }

stop:
    //发送stop信号
    base->I2CR &= ~I2CR_MSTA;
    while ((base->I2SR & I2SR_IBB) != 0)
    {
        //设计超时机制
    } 
#if AT24C02
    delay_ms(5);
#endif
}

读函数

cs 复制代码
void i2c_read(I2C_Type *base, unsigned char dev_addr,unsigned short reg_addr, int reg_len, unsigned char *data, unsigned int len)
{
    int stat = 0;
    //0. 清除IAL、IIF, 
    base->I2SR &= ~(I2SR_IAL | I2SR_IIF);
    //1. 设置为发送模式
    base->I2CR |= I2CR_MTX;
    //2.start信号
    base->I2CR |= I2CR_MSTA;

    //3.发送从机地址及数据流向位
    base->I2DR = ((dev_addr << 1) | 0);
    stat = wait_i2c_iif(base);
    if (stat != 0) goto stop;

    //4.发送从机寄存器地址
    int i = reg_len - 1;
    for (; i >= 0; i--)
    {
        base->I2DR = (reg_addr >> (i * 8)) & 0xFF;
        stat = wait_i2c_iif(base);
        if (stat != 0) goto stop;  
    }

    //5.重发start
    base->I2CR |= I2CR_RSTA;

    //6.发送从机地址及数据流向位
    base->I2DR = ((dev_addr << 1) | 1);
    stat = wait_i2c_iif(base);
    if (stat != 0) goto stop;

    //7. 设置为接收模式
    base->I2CR &= ~I2CR_MTX;
    //8. 设置应答类型
    if (len > 1)
    {
        base->I2CR &= ~I2CR_TXAK;       //ACK
    } else {
        base->I2CR |= I2CR_TXAK;       //NACK
    }
    // 9.触发一次伪读;
    data[0] = base->I2DR;

    for (i = 0; i < len; i++)
    {
        stat = wait_i2c_iif(base);
        if (i == len - 2){
            base->I2CR |= I2CR_TXAK;       //倒数第二个字节读数据前,设置应答类型为NACK,开始触发接收 倒数第一个字节。
        }
        if (i == len - 1){
           base->I2CR |= I2CR_MTX;          //倒数第一个字节读数据前 修改为发送模式(避免触发新的读取操作)
        }
        data[i] = base->I2DR;
        if (stat != 0) goto stop;
    }

stop:
    //发送stop信号
    base->I2CR &= ~I2CR_MSTA;
    while ((base->I2SR & I2SR_IBB) != 0)
    {
        //设计超时机制
    } 
}
相关推荐
HQB20266 小时前
EG1198|屹晶微电子 120V 内置 MOS 异步降压 DC‑DC(高性价比)
嵌入式硬件·硬件工程
果壳science7 小时前
张祥前实验如何获取正电荷
笔记·科技·嵌入式硬件·硬件工程·制造
南山电子nscn7 小时前
中科芯CETC汽车电池管理系统BMS进口芯片国产型号替代指南
单片机·汽车·bms
桀人8 小时前
认识AT24C02
stm32·单片机·嵌入式硬件
国科安芯9 小时前
星间激光通信终端CANFD控制网络的时延确定性与辐射可靠性
网络·嵌入式硬件·信息与通信·canfd·低轨卫星·商业航天·抗辐射
一直C10 小时前
嵌入式 Linux 驱动开发学习笔记:内核定时器、platform 总线与 I²C 驱动
linux·驱动开发·嵌入式硬件·学习·imx6ull
传感器与混合集成电路10 小时前
150MHz主频、8路DAC与6路PWM:JLH221360伺服控制SIP解析
嵌入式硬件
comyccccc10 小时前
STM32PID控制板设计全解析学习笔记
单片机·嵌入式硬件
碧海银沙音频科技研究院11 小时前
实现炬芯ATS308X的usb cdc 串口IAP 固件升级功能实现
人工智能·嵌入式硬件·深度学习·算法
恒锐丰科技林技术员11 小时前
EG1160 高压半桥驱动芯片:高压功率变换的实用驱动方案
经验分享·嵌入式硬件·硬件工程