1. IIC协议

可挂多个设备,每个IIC从设备里都有个固化的地址,只有两条线上传输的值对应IIC从设备的地址时,从设备才作出响应。

1.1 开始信号 

SCL时钟保持高电平,然后SDA数据信号“由高变低”表示一个开始信号;同时从设备检测到这个开始信号就知道主控设备要发送数据了。

1.2 停止信号

SCL时钟保持高电平,然后SDA数据信号“由低变高”表示一个停止信号;同时从设备检测到这个停止信号就知道主控设备已经结束数据传输。

1.3 数据传输

SDA上传输的数据必须在SCL为高电平期间保持稳定,因为外接IIC设备在SCL为高电平期间采集数据;也因此,SDA上的数据只能在SCL为低电平期间翻转变化。

1.4 响应信号(ACK)

主设备把数据发给IIC从设备,需要IIC从设备回应一个信号给主设备,以来判断IIC从设备数据是否已经收到数据。具体过程如下:

(1)主设备发完8bit数据后就不再驱动总线了(SDA引脚设置为输入),由于SDA和SCL硬件设计时都有上拉电阻,所以此时SDA变成高电平。

(2)如果IIC从设备能接收到信号的话,接着需要在第9个时钟周期主动把SDA拉低,此时主设备检测到SDA变低,就知道从设备已经收到数据。

2. IIC通讯流程

IIC总线用7bit表示从地址,因此最多挂载的从设备数量为2^7即:128个。

(1)先发送起始位;

(2)发一个8bit数据,前7bit表示从设备地址,第8bit表示“读”或“写”标识。其中,“0”对应write,即:主控设备往IIC从设备发;“1”对应read,即:从设备往主控设备发。

(3)第9个时钟周期检测从设备回复的响应信号。

3. 以 AT24Cxx 为例

3.1 读取数据时序

(1)首先发出一个start信号,和从设备地址,R/W(1,0),回应ACK表示有这个从设备存在。

(2)主控把需要访问的IIC从设备的待读取的8bit存储地址写入,ACK回应。

(3)另一个start信号+从设备地址,最低位是高电平表示读数据,回应ACK表示有这个从设备存在。

(4)在读数据的时候,每发出一个时钟,主设备会读取SDA上的数据并存起来,那么发出8个时钟后主设备就能得到8位的数据。若想连续读就不断回应ACK信号否则就发出停止信号。

3.2 写入数据时序

(1)start信号,某个设备地址,R/W 为“写”标识;对方收到8bit地址后回应ACK;

(2)接着主设备发送需要写入的地址,从设备收到8bit地址后回应ACK;

(3)接着主控将8bit数据发给从设备,对方收到8bit数据后回应ACK;

(4)通讯完成后,主设备发送停止信号。

4. 逻辑分析仪抓到数据

5. GPIO模拟IIC协议

#define SDA 254                         //定义SDA所对应的GPIO接口编号
#define SCL 255                         //定义SCL所对应的GPIO接口编号
#define OUTP 1                          //表示GPIO接口方向为输出
#define INP 0                           //表示GPIO接口方向为输入
/* I2C起始条件 */
int i2c_start()
{
    set_gpio_direction(SDA, OUTP);          //设置SDA方向为输出
    set_gpio_direction (SCL, OUTP);         //设置SCL方向为输出
    set_gpio_value(SDA, 1);                //设置SDA为高电平
    set_gpio_value(SCL, 1);                 //设置SCL为高电平
    delay();                            //延时
    set_gpio_value(SDA, 0);                 //SCL为高电平时,SDA由高变低
    delay();
}
/* I2C终止条件 */
void i2c_stop()
{
    set_gpio_value(SCL, 1);
    set_gpio_direction(SDA, OUTP);
    set_gpio_value(SDA, 0);
    delay();
    set_gpio_value(SDA, 1);             //SCL高电平时,SDA由低变高
}
/*
I2C读取ACK信号(写数据时使用)
返回值 :0表示ACK信号有效;非0表示ACK信号无效
*/
unsigned char i2c_read_ack()
{
    unsigned char r;
    set_gpio_direction(SDA, INP);           //设置SDA方向为输入
    set_gpio_value(SCL,0);              // SCL变低
    r = get_gpio_value(SDA);                //读取ACK信号
    delay();
    set_gpio_value(SCL,1);              // SCL变高
    delay();
    return r;
}
/* I2C发出ACK信号(读数据时使用) */
int i2c_send_ack()
{
    set_gpio_direction(SDA, OUTP);          //设置SDA方向为输出
    set_gpio_value(SCL,0);              // SCL变低
    set_gpio_value(SDA, 0);             //发出ACK信号
    delay();
    set_gpio_value(SCL,1);              // SCL变高
    delay();
}
/* I2C字节写 */
void i2c_write_byte(unsigned char b)
{
    int i;
    set_gpio_direction(SDA, OUTP);          //设置SDA方向为输出
    for (i=7; i>=0; i--)
    {
        set_gpio_value(SCL, 0);             // SCL变低
        delay();
        set_gpio_value(SDA, b & (1<<i));        //从高位到低位依次准备数据进行发送
        set_gpio_value(SCL, 1);             // SCL变高
        delay();
    }
    2c_read_ack();                 //检查目标设备的ACK信号
}
/* I2C字节读 */
unsigned char i2c_read_byte()
{
    int i;
    unsigned char r = 0;
    set_gpio_direction(SDA, INP);           //设置SDA方向为输入
    for (i=7; i>=0; i--)
    {
        set_gpio_value(SCL, 0);         // SCL变低
        delay();
        r = (r <<1) | get_gpio_value(SDA);      //从高位到低位依次准备数据进行读取
        set_gpio_value(SCL, 1);         // SCL变高
        delay();
    }
    i2c_send_ack();                 //向目标设备发送ACK信号
    return r;
}
/*
I2C读操作
addr:目标设备地址
buf:读缓冲区
len:读入字节的长度
*/
void i2c_read(unsigned char addr, unsigned char* buf, int len)
{
    int i;
    unsigned char t;
    i2c_start();                        //起始条件,开始数据通信
    t = (addr << 1) | 1;                    //低位为1,表示读数据
    i2c_write_byte(t);
    for (i=0; i<len; i++)
        buf[i] = i2c_read_byte();
    i2c_stop();                     //终止条件,结束数据通信
}
/*
I2C写操作
addr:目标设备地址
buf:写缓冲区
len:写入字节的长度
*/
void i2c_write (unsigned char addr, unsigned char* buf, int len)
{
    int i;
    unsigned char t;
    i2c_start();                        //起始条件,开始数据通信
    t = (addr << 1) | 0;                    //低位为0,表示写数据
    i2c_write_byte(t);
    for (i=0; i<len; i++)
        i2c_write_byte(buf[i]);
    i2c_stop();                     //终止条件,结束数据通信
}
注意:本站所有文章除特别说明外,均为原创,转载请务必以超链接方式并注明作者出处。 标签:MCU探讨,接口协议