IIC总线

1.简介

  • IIC是串行,半双工总线协议,主要用于近距离,低速芯片之间的通信
  • IIC总线有两根双向信号线,分别为数据线SDA,用于收发数据;时钟线SCL,用于通信双方时钟同步
  • IIC为一种多主机总线,连接在IIC上的器件分为主机和从机,主机有权发起和结束一次通信,而从机只能被主机呼叫.当总线上有多个主机启用总线时,IIC具备冲突检测和仲裁功能防止错误产生
  • 每个连接到IIC总线上的器件都有一个唯一的地址(7bit),且每个器件都可以作为主机也可以作为从机(但同一时刻只能存在一个主机),总线上其他器件的增加和删除不影响其他器件的正常工作

2.IIC通信过程

1.主机发送起始信号启用总线
2.主机发送一个字节数据指明从机地址(7bit)和后续字节的传送方向(1bit,0表示主机发数据给从机,1表示从机发数据给主机)
3.被寻址的从机发送应答信号回应主机
4.发送器发送一个字节数据
5.接收器发送应答信号回应发送器
6.重复4,5发送数据
7.通信完成后主机发送停止信号释放总线

3.IIC总线信号

1.起始与终止信号

  • 起始信号:SCL为高电平时,SDA由高变低
  • 终止信号:SCL为高电平时,SDA由低变高

2.字节传输与应答信号

  • IIC总线通信时每个字节为8bit,数据传输时,先传输高位,再传输低位(串口先低后高),发送器发送完一个字节数据后接收器必须发送1位应答位(0表示应答)来回应,即一帧数据有9位

3.时钟同步信号

  • IIC在进行数据传输时,时钟线SCL为低电平期间发送器向数据线上发送一位数据,在此期间数据线上的信号允许发送变化,时钟线为高电平期间接收器从数据线上读取一位数据,在此期间数据线上的信号不允许发送改变,必须保持稳定
    IIC流程.png

4.典型IIC时序

  • S:起始信号,P:终止信号,A:应答信号,-A:非应答信号,斜线:主机发送的数据,非斜线:从机发送的数据
  • 主机向从机发送数据
S 从机地址 0 A 数据 A 数据 A/-A P
  • 从机向主机发送数据
S 从机地址 1 A 数据 A 数据 -A P
  • 主机先向从机发送数据,然后从机再向主机发送数据(在交换数据流中间主机并没有发送停止信号就直接发送开始信号,此举是为了不释放数据线,防止总线被占用,进而阻断此次通信)
S 从机地址 0 A 数据 A/-A S 从机地址 1 A 数据 -A P

5.MPU6050传感器控制

1.向MPU6050的一个寄存器写入一个字节数据

  • 主机发送起始信号
  • 主机发送从机地址及读写方向(0:写)
  • 从机发送应答信号
  • 主机发送要操作的从机的寄存器地址(1字节)
  • 从机响应
  • 主机发送写入的数据(1字节)
  • 从机响应
  • 主机发送停止信号

2.从MPU6050中读取一字节数据

  • 主机发送起始信号
  • 主机发送从机地址及读写方向(0:写)
  • 从机响应
  • 主机发送要写的寄存器地址(1字节)
  • 从机响应
  • 主机发送起始信号
  • 主机发送从机地址及读写方向(1:读)
  • 从机响应
  • 从机发送数据(主机想要读取的寄存器数据)
  • 从机发送非应答信号(停止通信)
  • 主机发送停止信号

3.总结

  • 每次主机更改读写方向时候都会发送一次起始信号

6.4412的MPU6050驱动代码

#include "exynos_4412.h"

#define SMPLRT_DIV      0x19    //陀螺仪采样率,一般取:0x07(125Hz)
#define CONFIG          0x1A    //低通滤波器频率,一般取:0x06(5Hz)
#define GYRO_CONFIG     0x1B    //陀螺仪自检及测量范围,一般取:0x18(不自检,2000deg/s)
#define ACCEL_CONFIG    0x1C    //加速度计自检,测量范围及高通滤波,一般取:0x00(不自检,2G,5Hz)    
#define ACCEL_XOUT_H    0x3B
#define ACCEL_XOUT_L    0x3C
#define ACCEL_YOUT_H    0x3D
#define ACCEL_YOUT_L    0x3E
#define ACCEL_ZOUT_H    0x3F
#define ACCEL_ZOUT_L    0x40
#define TEMP_OUT_H      0x41
#define TEMP_OUT_L      0x42
#define GYRO_XOUT_H     0x43
#define GYRO_XOUT_L     0x44
#define GYRO_YOUT_H     0x45
#define GYRO_YOUT_L     0x46
#define GYRO_ZOUT_H     0x47
#define GYRO_ZOUT_L     0x48
#define PWR_MGMT_1      0x00    //电源管理,一般取:0x00(正常启动)
#define SlaveAddress    0x68    //寄存器地址:WHO_AM_I

void my_delay_ms(int time)
{
    int i, j;
    while(time--)
    {
        for(i=0;i<5;i++)
        {
            for(j=0;j<514;j++);
        }
    }
}

void iic_write(unsigned char slave_addr, unsigned char addr, unsigned char data)
{
    I2C5.I2CCON = I2C5.I2CCON | (1<<6) | (1<<5);    //时钟源512倍分频,打开IIC中断
    I2C5.I2CSTAT = 0xD0;                            //设置IIC模式为主机发送模式,使能发送与接收
    I2C5.I2CDS = (slave_addr << 1);                 //写入从机地址及读写位,此处为0,表示主机向从机写数据
    I2C5.I2CSTAT = 0xF0;                            //设置IIC模式为主机发送模式,发送起始信号启动总线,使能IIC发送与接收
    while(!(I2C5.I2CCON & (1 << 4)));               //等待从机应答
    I2C5.I2CDS = addr;                              //发送要操作的从机内部的某寄存器地址
    I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));          //清除中断标志位
    while(!(I2C5.I2CCON & (1 << 4)));               //等待从机应答
    I2C5.I2CDS = data;                              //向从机寄存器中写入数据
    I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));          //清除中断标志位
    while(!(I2C5.I2CCON & (1 << 4)));               //等待从机应答
    I2C5.I2CSTAT = 0xD0;                            //发送停止信号
    I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));          //清除中断标志位
    my_delay_ms(10);
}

unsigned char iic_read(unsigned char slave_addr, unsigned char addr)
{
    unsigned char data = 0;
    I2C5.I2CCON = I2C5.I2CCON | (1<<6) | (1<<5);    //时钟源512倍分频,打开IIC中断
    I2C5.I2CSTAT = 0xD0;                            //设置IIC模式为主机发送模式,使能发送与接收
    I2C5.I2CDS = (slave_addr << 1);                 //写入从机地址及读写位,此处为0,表示主机向从机写数据
    I2C5.I2CSTAT = 0xF0;                            //设置IIC模式为主机发送模式,发送起始信号启动总线,使能IIC发送与接收
    while(!(I2C5.I2CCON & (1 << 4)));               //等待从机应答
    I2C5.I2CDS = addr;                              //发送要操作的从机内部的某寄存器地址
    I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));          //清除中断标志位
    while(!(I2C5.I2CCON & (1 << 4)));               //等待从机应答
    I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));          //清除中断标志位

    I2C5.I2CDS = (addr << 1) | (0x01);              //写入要读取的从机寄存器地址,设置主机为读模式
    I2C5.I2CSTAT = 0xB0;                            //设置IIC模式为主机接收模式,使能发送与接收
    while(!(I2C5.I2CCON & (1 << 4)));               //等待从机应答
    I2C5.I2CCON = I2C5.I2CCON & ((~(1<<7))&(~(1<<4)))//禁止主机应答,清空中断标志位,这样只接收一字节
    while(!(I2C5.I2CCON & (1 << 4)));               //等待从机应答
    data = I2C5.I2CDS;                              //获取数据
    I2C5.I2CSTAT = 0x90;                            //发送停止信号
    I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));          //清除中断标志位
    my_delay_ms(10);
    return data;
}

void MPU6050_init()
{
    iic_write(SlaveAddress, PWR_MGMT_1, 0x00);      //设置电源
    iic_write(SlaveAddress, SMPLRT_DIV, 0x07);      //设置采样率
    iic_write(SlaveAddress, CONFIG, 0x06);          //设置低通滤波器频率     
    iic_write(SlaveAddress, GYRO_CONFIG, 0x18);     //设置陀螺仪量程
    iic_write(SlaveAddress, ACCEL_CONFIG, 0x00);    //设置加速度计量程
}

int main()
{
    unsigned char zvalue_h, zvalue_l;
    short int zvalue;
    GPB.CON = (GPB.CON & ~(0xF << 12)) | (0x3 << 12);//设置GPB_3为I2C_5_SCL
    GPB.CON = (GPB.CON & ~(0xF << 8)) | (0x3 << 8);  //设置GPB_2为I2C_5_SDA
    MPU6050_init();
    while (1)
    {
        zvalue_h = iic_read(SlaveAddress, GYRO_ZOUT_H);
        zvalue_l = iic_read(SlaveAddress, GYRO_ZOUT_L);
        zvalue = (zvalue_h << 8) | zvalue_l;
        printf("GYRO-Z :%d\r\n", zvalue);
        my_delay_ms(100);
    }
    return 0;
}

你可能感兴趣的:(IIC总线)