关闭

协议理解之I2C协议

标签: 协议
469人阅读 评论(0) 收藏 举报
分类:

I2C总线的特征

协议我们参考|EEPROM 24C64的DataSheet

  • 硬件特征:
    SDA:串行数据线
    SCL:串行时钟线
    每个连接到总线上的设备都有唯一的地址

  • 速度
    标准模式下可以达到100kbit/s
    快速模式下可以达到400kbit/s
    高速模式下可以达到3.4Mbit/s

  • I2C总线术语
    发送器: 发送数据到总线的器件
    接收器: 从总线接收数据的器件
    主机: 初始化发送 产生时钟信号和终止发送的器件
    从机: 被主机寻址的器件
    多主机: 同时有多于一个主机尝试控制总线 但不破坏报文
    仲裁: 是一个在有多个主机同时尝试控制总线 但只允许其中一个控制总线并使报文不被破坏
    的过程
    同步: 两个或多个器件同步时钟信号的过程

协议格式

  • 开始位
    在 SCL 线是高电平时 SDA 线从高电平向低电平切换
    这里写图片描述

  • 停止位
    当 SCL 是高电平时 SDA 线由低电平向高电平切换
    这里写图片描述

  • 数据位
    发送到 SDA 线上的每个字节必须为 8 位,数据的高位在前(先发数据高位);
    这里写图片描述

代码范例

void i2c_delay(void)
{
    unsigned char i;
    for(i=0;i<10;i++);
}

void i2c_start(void)
{
    I2C_SDA = 1;
    I2C_CLK = 1;
    i2c_delay();
    I2C_SDA = 0;
    i2c_delay();
    I2C_CLK = 0;
}

void i2c_stop(void)
{
    I2C_SDA = 0;
    I2C_CLK = 0;
    i2c_delay();
    I2C_CLK = 1;
    i2c_delay();
    I2C_SDA = 1;
}

unsigned char read_i2c_onebyte(bit ack_or_nak)
{
    unsigned char read_data, i;
    SET_SDA_INPUTMODE;
    read_data = 0x00;
    for(i=0;i<7;i++)
    {
        I2C_CLK = 1;
        if(I2C_SDA)
            read_data |= 0x01;
        i2c_delay();
        I2C_CLK = 0;
        read_data <<= 1;
        i2c_delay();
    }
    I2C_CLK = 1;
    if(I2C_SDA)
        read_data |= 0x01;
    i2c_delay();
    I2C_CLK = 0;

    SET_SDA_OUTPUTMODE;     //SDA output

    i2c_delay();
    if(ack_or_nak)
        I2C_SDA = 1;
    else
        I2C_SDA = 0;
    I2C_CLK = 1;
    i2c_delay();
    I2C_CLK = 0;

    i2c_delay();
    I2C_SDA = 0;
    return read_data;
}

bit write_i2c_onebyte(char w_buf)
{
    unsigned char i;
    bit ack_or_nak;
    for(i=0;i<8;i++)
    {
        if(w_buf&0x80)
            I2C_SDA = 1;
        else
            I2C_SDA = 0;
        i2c_delay();
        I2C_CLK = 1;
        i2c_delay();
        I2C_CLK = 0;
        w_buf <<= 1;
    }
    SET_SDA_INPUTMODE;
    i2c_delay();
    I2C_CLK = 1;
    i2c_delay();
    ack_or_nak = 0;
    if(I2C_SDA)
        ack_or_nak = 1;
    I2C_CLK = 0;
    I2C_SDA = 0;
    SET_SDA_OUTPUTMODE;     //SDA output

    return ack_or_nak;
}

写操作

  • 设备地址
    这里写图片描述

  • 字节写操作
    这里写图片描述

时序分析:
1、开始信号;
2、写从设备地址,地址最低位R/W=0,表示为写操作,从设备收到数据后会自动返回ACK,判断设备存不存在可以根据ACK信号;
3、写存储地址高八位(写完地址后从设备会返回ACK),(有的设备是10bit的地址,24C64是8bit地址)
4、写存储地址低八位(写完地址后从设备会返回ACK)
5、写8bit数据(1Byte)
6、写停止位

void 24cxx_write(unsigned short addr, unsigned char dat)
{
    i2c_start();
    write_i2c_onebyte((EEPROM_ADDR<<1)+WRITE_CMD);
    write_i2c_onebyte(addr>>8);
    write_i2c_onebyte(addr);    
    write_i2c_onebyte(dat);
    i2c_stop();
    delay_ms(12);
}
  • 页写操作
    这里写图片描述
    时序分析:
    1、开始信号;
    2、写从设备地址,地址最低位R/W=0,表示为写操作,从设备收到数据后会自动返回ACK,判断设备存不存在可以根据ACK信号;
    3、写存储地址高八位(写完地址后从设备会返回ACK),(有的设备是10bit的地址,24C64是8bit地址)
    4、写存储地址低八位(写完地址后从设备会返回ACK)
    5、写停止位
    7、写开始位
    8、写从设备地址
    6、写停止位
int 24cxx_write_page(unsigned short addr, unsigned short len, unsigned char* idata buf)
{
    i2c_start();
    write_i2c_onebyte((EEPROM_ADDR<<1)+WRITE_CMD);
    write_i2c_onebyte(addr>>8);
    write_i2c_onebyte(addr);

    while(len--) {
        write_i2c_onebyte(*buf++);
    }
    i2c_stop();
    delay_ms(12);
    return 0;
}

//用于拷贝芯片的数据
int 24cxx_write_buf(unsigned short addr, unsigned short num, unsigned char* idata buf)
{
    int stat;
    unsigned char NumOfPage = 0, NumOfSingle = 0;

    if (addr % _24CXX_PageSize) //位一页空间的大小
        NumOfSingle = _24CXX_PageSize - addr%_24CXX_PageSize;
    else 
        NumOfSingle = 0;
    if (num <= NumOfSingle)     
        NumOfSingle = num;  
    else 
        NumOfPage =  (num - NumOfSingle + (_24CXX_PageSize - 1)) / _24CXX_PageSize;

    if (NumOfSingle) {
        if (0!=(stat=_24cxx_write_page(addr, NumOfSingle, buf)))
            return stat;
        addr += NumOfSingle;
        buf += NumOfSingle;
        num  -= NumOfSingle;
    }
    while (NumOfPage--) {
        if (0!=(stat=_24cxx_write_page(addr, (num>=_24CXX_PageSize)?_24CXX_PageSize:num, buf)))
            return stat;
        addr += _24CXX_PageSize;
        buf += _24CXX_PageSize;
        num  -= _24CXX_PageSize;    
    }
    return 0;
}

读操作

这里写图片描述
- 随机读操作
时序分析:
1、开始信号;
2、写从设备地址,地址最低位R/W=1,表示为读操作,从设备收到数据后会自动返回ACK,判断设备存不存在可以根据ACK信号;
3、读存储地址高八位(写完地址后从设备会返回ACK),(有的设备是10bit的地址,24C64是8bit地址)
4、读存储地址低八位(写完地址后从设备会返回ACK)
5、写停止位
6、写开始信号
7、写从设备地址
8、读取数据,并告诉从设备这次不用回ACK
9、写停止位

unsigned char 24cxx_read(unsigned short addr)
{
    unsigned char tmp;
    i2c_start2();
    write_i2c_onebyte((EEPROM_ADDR<<1)+WRITE_CMD);
    write_i2c_onebyte(addr>>8);
    write_i2c_onebyte(addr);
    i2c_stop();

    i2c_start();
    write_i2c_onebyte((EEPROM_ADDR<<1)+READ_CMD);
    i2c_delay();
    tmp = read_i2c_onebyte(NAK_FLAG);
    i2c_stop();
    return tmp;
}   
  • 顺序读
    这里写图片描述
    时序分析:
    1、开始信号;
    2、写从设备地址,地址最低位R/W=1,表示为读操作,从设备收到数据后会自动返回ACK,判断设备存不存在可以根据ACK信号;
    3、读存储地址高八位(写完地址后从设备会返回ACK),(有的设备是10bit的地址,24C64是8bit地址)
    4、读存储地址低八位(写完地址后从设备会返回ACK)
    5、写停止位
    6、写开始信号
    7、写从设备地址
    8、读取数据,并告诉从设备这次不用回ACK
    9、写停止位
void _24cxx_read_buf(unsigned short addr, unsigned short len, unsigned char* idata buf)
{
    i2c_start();
    write_i2c_onebyte((EEPROM_ADDR<<1)+WRITE_CMD);
    write_i2c_onebyte(addr>>8);
    write_i2c_onebyte(addr);
    i2c_stop2();
    i2c_start2();
    write_i2c_onebyte((EEPROM_ADDR<<1)+READ_CMD);
    while(--len) {
        i2c_delay();
        *buf++ = read_i2c_onebyte(ACK_FLAG);
    }
    i2c_delay();
    *buf = read_i2c_onebyte(NAK_FLAG);
    i2c_stop();
}

附图:

I2C协议图片逻辑分析
临时保存I2C逻辑采样图片,MSB在前

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:3162次
    • 积分:307
    • 等级:
    • 排名:千里之外
    • 原创:29篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档