嵌入式——时序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)
    {
        //设计超时机制
    } 
}
相关推荐
LS_learner5 小时前
针对VMware Workstation虚拟机无法联网问题排查
嵌入式硬件
项目題供诗5 小时前
51单片机入门(七)
单片机·嵌入式硬件·51单片机
来自晴朗的明天5 小时前
1、光耦隔离电路
单片机·嵌入式硬件·硬件工程
国科安芯7 小时前
面向星载芯片原子钟的RISC-V架构MCU抗辐照特性研究及可靠性分析
单片机·嵌入式硬件·架构·制造·risc-v·pcb工艺·安全性测试
三伏5228 小时前
Cortex-M3权威指南Cn第十章——笔记
笔记·单片机·嵌入式硬件·cortex-m3
独处东汉8 小时前
freertos开发空气检测仪之按键输入事件管理系统设计与实现
人工智能·stm32·单片机·嵌入式硬件·unity
小灰灰搞电子8 小时前
STM32/GD32 字节对齐详解
stm32·单片机·嵌入式硬件
我送炭你添花9 小时前
工业触摸屏:PCAP(投影电容式)触摸屏控制器选型推荐(工业级,2025-2026主流)
嵌入式硬件·自动化
来自晴朗的明天11 小时前
2、NMOS 电源防反接电路
单片机·嵌入式硬件·硬件工程