ICM20602六轴传感器-IIC通信模式

ICM20602六轴传感器

  • ICM20602 通过IIC协议与MCU通信
  • ICM20602 初始化配置
  • ICM20602 相关配置函数
  • ICM20602 内部寄存器
  • 注意事项
    • (一)ICM20602 从地址
    • (二)ICM20602 器件id(0x12)

ICM20602 通过IIC协议与MCU通信

ICM-20602 是 日本TDKTDK公司生产的六轴传感器。
ICM-20602的DataSheet可在其官网下载: ICM20602 或者参考链接: 芯片翻译之ICM20602.

IIC软件模拟时序,请参考链接: IIC软件模拟时序-stm32F系列平台通用
下面为MCU通过IIC与ICM20602通信的读写函数

/*-------------- 读写从机的内部寄存器reg,读写1个字节数据 ----------------*/
/**
  * @brief  IIC写一个字节
  * @param  reg  要写的寄存器地址
  *         buf  写入到的数据存储区
  * @retval 1:失败
  *         0:成功
  */
u8 ICM_Write_Byte(u8 reg, u8 data)
{
    IIC_Start();
    IIC_Send_Byte((ICM20602_ADDR << 1) | 0); //发送器件地址+写命令
    if (IIC_Wait_Ack()) //等待应答
    {
        IIC_Stop();
        return 1;
    }
    IIC_Send_Byte(reg); //写寄存器地址
    IIC_Wait_Ack(); //等待应答
    IIC_Send_Byte(data); //发送数据
    if (IIC_Wait_Ack()) //等待ACK
    {
        IIC_Stop();
        return 1;
    }
    IIC_Stop();

    return 0;
}

/**
  * @brief  IIC读一个字节
  * @param  reg  要写的寄存器地址
  * @retval 读到的数据
  */
u8 ICM_Read_Byte(u8 reg)
{
    u8 res;
    IIC_Start();
    IIC_Send_Byte((ICM20602_ADDR << 1) | 0); //发送器件地址+写命令
    IIC_Wait_Ack(); //等待应答
    IIC_Send_Byte(reg); //写寄存器地址
    IIC_Wait_Ack(); //等待应答
    IIC_Start();
    IIC_Send_Byte((ICM20602_ADDR << 1) | 1); //发送器件地址+读命令
    IIC_Wait_Ack(); //等待应答
    res = IIC_Read_Byte(0); //读取数据,发送nACK
    IIC_Stop(); //产生一个停止条件

    return res;
}


/*----------------------- ICM20602 连续读写数据 ----------------------*/
/**
  * @brief  IIC发送数据
  * @param  
  * @retval 返回从机有无应答
  *         1:有应答
  *         0:无应答
  */
u8 ICM_Write_Len(u8 addr, u8 reg, u8* buf, u8 len)
{
    u8 i;
    IIC_Start();
    IIC_Send_Byte((addr << 1) | 0); //发送器件地址+写命令
    if (IIC_Wait_Ack()) //等待应答
    {
        IIC_Stop();
        return 1;
    }
    IIC_Send_Byte(reg); //写寄存器地址
    IIC_Wait_Ack(); //等待应答
    for (i = 0; i < len; i++) {
        IIC_Send_Byte(buf[i]); //发送数据
        if (IIC_Wait_Ack()) //等待ACK
        {
            IIC_Stop();
            return 1;
        }
    }
    IIC_Stop();

    return 0;
}

/**
  * @brief  IIC读取数据
  * @param  addr 器件地址
  *         reg  要读取的寄存器地址
  *         len  要读取的长度
  *         buf  读取到的数据存储区
  * @retval 1:失败
  *         0:成功
  */
u8 ICM_Read_Len(u8 addr, u8 reg, u8* buf, u8 len)
{
    IIC_Start();
    IIC_Send_Byte((addr << 1) | 0); //发送器件地址+写命令
    if (IIC_Wait_Ack()) //等待应答
    {
        IIC_Stop();
        return 1;
    }
    IIC_Send_Byte(reg); //写寄存器地址
    IIC_Wait_Ack(); //等待应答
    IIC_Start();
    IIC_Send_Byte((addr << 1) | 1); //发送器件地址+读命令
    IIC_Wait_Ack(); //等待应答
    
    while (len) {
        if (len == 1)
            *buf = IIC_Read_Byte(0); //读数据,发送nACK
        else
            *buf = IIC_Read_Byte(1); //读数据,发送ACK
        len--;
        buf++;
    }
    IIC_Stop(); //产生一个停止条件

    return 0;
}

ICM20602 初始化配置

在初始化配置IMU传感器时,一定要先配置成功能正常读取IMU传感器的内部标识 id

/* ------------- ICM20602 六轴传感器初始化 ---------------- */
u8 ICM20602_sensor_init(void)
{
    u8 ICM_id;

    /* (1)IIC初始化 */
    IIC_Dev_Init();

#if 1  // 此部分为ICM20602的INT引脚产生中断的相关配置
/*- ICM20602引脚INT产生中断时,MCU引脚PE0配置外部中断和NVIC优先级 -*/
    GPIO_InitTypeDef GPIO_InitStructure;
    
    /* 使能GPIOE、AFIO 端口时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE);

    /* 配置ICM20602-PE0中断线 */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(GPIOE, &GPIO_InitStructure);

    /* 配置中断线和 GPIO-PE0 映射关系 */
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource0);
    
    /* 配置外部中断EXTI */
    myEXTI_Config(EXTI_Line0, EXTI_Mode_Interrupt, EXTI_Trigger_Falling);

    /* 配置NVIC中断优先级并使能中断 */
    myNVIC_Config(EXTI0_IRQn, 0, 0); // 外部中断线0

#endif

    /* (2)复位ICM20602 */
    ICM_Write_Byte(ICM20602_PWR_MGMT1_REG, 0x80);
    timer_delay(100); // 利用定时器配置延迟100ms
    ICM_Write_Byte(ICM20602_PWR_MGMT1_REG, 0x00); //唤醒ICM20602
    
    /* 复位重置传感器各个通道的寄存器 */
    ICM_Write_Byte(ICM20602_USER_CTRL, 0x01); 
    timer_delay(100);
    ICM_Write_Byte(ICM20602_USER_CTRL, 0x00);

    /* (3)配置陀螺仪满量程范围:-2g ~ +2g;加速度计满量程范围:-2000dps ~ +2000dps */
    ICM_Set_Gyro_Fsr(0x3);
    ICM_Set_Accel_Fsr(0);

    /* (4)设置采样频率50HZ */
    ICM_Set_Rate(50);

    /* (5)禁止中断,关闭硬件 */
    ICM_Write_Byte(ICM20602_INT_ENABLE_REG, 0x00);  // 关闭所有中断
    ICM_Write_Byte(ICM20602_FIFO_EN, 0x00);         // 关闭陀螺仪和加速度计的FIFO数据缓冲区
    ICM_Write_Byte(ICM20602_INT_PIN_CFG, 0x80);     // 设置INT引脚为低电平有效,开漏输出

    /* (6)判断器件ID = 0x12 */
    ICM_id = ICM_Read_Byte(ICM20602_WHO_AM_I);
    printf("ICM20602_ID = 0x%x .......\r\n", ICM_id);
    if (ICM_id == 0x12) {
        /* 设置时钟源 */
        ICM_Write_Byte(ICM20602_PWR_MGMT1_REG, 0x01);

        /* 设置accelerate阈值 */
        ICM_Write_Byte(ICM20602_LACCEL_WOM_X_THR, 0x7F);
        ICM_Write_Byte(ICM20602_LACCEL_WOM_Y_THR, 0x7F);
        ICM_Write_Byte(ICM20602_LACCEL_WOM_Z_THR, 0x7F);

        /* 开启加速度计的阈值中断 */
        ICM_Write_Byte(ICM20602_ACCEL_INTEL_CTRL, 0x80);
        timer_delay(1);

        /* 使能中断 */
        ICM_Write_Byte(ICM20602_INT_ENABLE_REG, 0xE0);
        timer_delay(1);

        /* 开启加速度与陀螺仪都工作 */
        ICM_Write_Byte(ICM20602_PWR_MGMT2_REG, 0x00);
        timer_delay(1);

        printf("ICM20602 IMU initalize success ............\r\n");

    } else {
        printf("ICM20602 initalize fail ...........\r\n");
        return 1;
    }

    return 0;
}

/*---------- 设置运动检测(WAKE-ON MOTION) accelerate阈值 ----------*/
int Set_Accl_Thresh(u8 threshold)
{
    u8 accl_val;
    /* Threshold按十六进制传参不能超过值:(十进制0D)100 = 0x64 */
    if(threshold > 100){
        return 1;
    }
    u16 val_1= threshold * 0xFF;
    u16 val_2 = (u8)(val_1 / 100);
    accl_val = (u8)val_2;
    _debug(SYS_INFO, "threshold = %d%%, val_1 = 0x%x, val_2 = 0x%x, set accl_val = 0x%x ...\n", \
                        threshold, val_1, val_2, accl_val);
    ICM_Write_Byte(ICM20602_LACCEL_WOM_X_THR, accl_val);
    ICM_Write_Byte(ICM20602_LACCEL_WOM_Y_THR, accl_val);
    ICM_Write_Byte(ICM20602_LACCEL_WOM_Z_THR, accl_val);  
    return 0; 
}

/* 外部中断配置EXTI寄存器 */
void myEXTI_Config(u32 myEXTI_Line, EXTIMode_TypeDef myEXTI_Mode, EXTITrigger_TypeDef myEXTI_Trigger)
{
    EXTI_InitTypeDef EXTI_InitStructure;

    EXTI_InitStructure.EXTI_Line = myEXTI_Line;
    EXTI_InitStructure.EXTI_Mode = myEXTI_Mode;
    EXTI_InitStructure.EXTI_Trigger = myEXTI_Trigger;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
}


/* NVIC中断配置函数 */
void myNVIC_Config(u8 myNVIC_IRQChannel, u8 PreEmptionPriority, u8 SubPriority)
{
    NVIC_InitTypeDef NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel = myNVIC_IRQChannel;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PreEmptionPriority;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = SubPriority;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}


/* EXTI0 中断处理函数 */
void EXTI0_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line0)) {
        
        /* ICM20602六轴传感器INT引脚 接MCU的PE0引脚 */
        if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_0) == Bit_RESET) {
            ICM20602_Get_Data();
        }

        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}

ICM20602 相关配置函数

此部分参考ICM20602的数据手册,

/*-------------------------- 设置满量程范围 ---------------------*/
/* 设置GYRO陀螺仪的满量程范围 */
u8 ICM_Set_Gyro_Fsr(u8 fsr)
{
    return ICM_Write_Byte(ICM20602_GYRO_CONFIG_REG, fsr << 3);
}


/* 设置ACCEL加速度计的满量程范围 */
u8 ICM_Set_Accel_Fsr(u8 fsr)
{
    return ICM_Write_Byte(ICM20602_ACCEL_CONFIG1_REG, fsr << 3);
}


/*------------------------- 设置采样频率 -------------------------*/
/**
  * 设置ICM20602的采样频率(假定Fs=1KHz)
  * INTERNAL_SAMPLE_RATE = 1 kHz
  * SAMPLE_RATE = INTERNAL_SAMPLE_RATE / (1 + SMPLRT_DIV);
  * rate:4 ~ 1000(Hz)
  * 返回值:0,设置成功;其他,设置失败
  */
u8 ICM_Set_Rate(u16 rate)
{
    u8 div;

    if (rate > 1000) {
        rate = 1000;
    } else if (rate < 4) {
        rate = 4;
    }

    /* 设置预分频值DIV */
    div = 1000 / rate - 1;
    ICM_Write_Byte(ICM20602_SMPLRT_DIV, div);

    /* 配置低通滤波器为采样率的1/2 */
    return ICM_Set_DLPF(rate / 2);
}


/**
  * 设置ICM20602的数字低通滤波器(假定Fs=1KHz)
  * 返回值:0,设置成功;其他,设置失败
  */
u8 ICM_Set_DLPF(u16 dlpf)
{
    u8 data;

    if (dlpf >= 250) {
        data = 0;
    } else if (dlpf >= 176) {
        data = 1;
    } else if (dlpf >= 92) {
        data = 2;
    } else if (dlpf >= 41) {
        data = 3;
    } else if (dlpf >= 20) {
        data = 4;
    } else if (dlpf >= 10) {
        data = 5;
    } else {
        data = 6;
    }

    return ICM_Write_Byte(ICM20602_CONFIG_REG, data);
}


/* ---------------------- 读取传感器采集到的数据 -------------------------- */
/**
  * 读取陀螺仪值(原始值)
  * gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
  * 返回值:0,成功; 其他,错误代码
  */
u8 ICM_Get_Gyroscope(short* gx, short* gy, short* gz)
{
    u8 buf[6], res;
    res = ICM_Read_Len(ICM20602_ADDR, ICM20602_GYRO_XOUT_H, buf, 6);
    if (res == 0) {
        *gx = ((u16)buf[0] << 8) | buf[1];
        *gy = ((u16)buf[2] << 8) | buf[3];
        *gz = ((u16)buf[4] << 8) | buf[5];
    }
    return res;
}

/**
  * 读取加速度计值(原始值)
  * ax,ay,az:加速度计x,y,z轴的原始读数(带符号)
  * 返回值:0,成功; 其他,错误代码
  */
u8 ICM_Get_Accelerometer(short* ax, short* ay, short* az)
{
    u8 buf[6], res;
    res = ICM_Read_Len(ICM20602_ADDR, ICM20602_ACCEL_XOUT_H, buf, 6);
    if (res == 0) {
        *ax = ((u16)buf[0] << 8) | buf[1];
        *ay = ((u16)buf[2] << 8) | buf[3];
        *az = ((u16)buf[4] << 8) | buf[5];
    }
    return res;
}

/**
  * 读取温度值(原始值)
  * 返回值:温度值(扩大了100倍)
  */
short ICM_Get_Temperature(void)
{
    u8 buf[2];
    short raw;
    float temp;

    ICM_Read_Len(ICM20602_ADDR, ICM20602_TEMP_OUT_H, buf, 2);
    raw = ((u16)buf[0] << 8) | buf[1];
    temp = 36.53 + ((double)raw) / 340;
    return temp * 100;
}

ICM20602 内部寄存器

icm20602_iic.h 头文件

/* ------------------ Register map for ICM20602 ---------------------- */

#define ICM20602_SELF_TEST_X_ACCEL 0x0D     // X轴加速度计自检寄存器
#define ICM20602_SELF_TEST_Y_ACCEL 0x0E     // Y轴加速度计自检寄存器
#define ICM20602_SELF_TEST_Z_ACCEL 0x0F     // Z轴加速度计自检寄存器
#define ICM20602_SMPLRT_DIV 0x19            // 采样频率分频器
#define ICM20602_CONFIG_REG 0x1A            // 配置:fifo MODE, Enables the FSYNC and DLPF低通滤波器
#define ICM20602_GYRO_CONFIG_REG 0x1B       // (4:3 bit)gyroscope configuration
#define ICM20602_ACCEL_CONFIG1_REG 0x1C     // accelerometer configuration
#define ICM20602_ACCEL_CONFIG2_REG 0x1D     // accelerometer configuration
#define ICM20602_LP_MODE_CFG 0x1E           // gyroscope low-power mode or 6-axis low-power mode
#define ICM20602_LACCEL_WOM_X_THR 0x20      // 加速度计X轴阈值
#define ICM20602_LACCEL_WOM_Y_THR 0x21      // 加速度计Y轴阈值
#define ICM20602_LACCEL_WOM_Z_THR 0x22      // 加速度计Z轴阈值
#define ICM20602_FIFO_EN 0x23               // GYRO/ACCEL _FIFO_EN
#define ICM20602_FSYNC_INT 0x36
#define ICM20602_INT_PIN_CFG 0x37           // 中断引脚配置
#define ICM20602_INT_ENABLE_REG 0x38        // interrupt enable
#define ICM20602_INT_STATUS 0x3A            // INTERRUPT STATUS
#define ICM20602_ACCEL_XOUT_H 0x3B          // accelerometer measurements
#define ICM20602_ACCEL_XOUT_L 0x3C
#define ICM20602_ACCEL_YOUT_H 0x3D
#define ICM20602_ACCEL_YOUT_L 0x3E
#define ICM20602_ACCEL_ZOUT_H 0x3F
#define ICM20602_ACCEL_ZOUT_L 0x40
#define ICM20602_TEMP_OUT_H 0x41            // TEMPERATURE MEASUREMENT,Temperature = 36.53 + regval/340
#define ICM20602_TEMP_OUT_L 0x42
#define ICM20602_GYRO_XOUT_H 0x43           // gyroscope measurements
#define ICM20602_GYRO_XOUT_L 0x44
#define ICM20602_GYRO_YOUT_H 0x45
#define ICM20602_GYRO_YOUT_L 0x46
#define ICM20602_GYRO_ZOUT_H 0x47
#define ICM20602_GYRO_ZOUT_L 0x48
#define ICM20602_SELF_TEST_X_GYRO 0x50
#define ICM20602_SELF_TEST_Y_GYRO 0x51
#define ICM20602_SELF_TEST_Z_GYRO 0x52
#define ICM20602_SIGNAL_PATH_RESET 0x68     // ACCEL_RST,TEMP_RST
#define ICM20602_ACCEL_INTEL_CTRL 0x69
#define ICM20602_USER_CTRL 0x6A             // FIFO_EN,FIFO_RST,SIG_COND_RST
#define ICM20602_PWR_MGMT1_REG 0x6B         // DEVICE_RESET,SLEEP,CYCLE,GYRO_STANDBY,TEMP_DIS,CLKSEL
#define ICM20602_PWR_MGMT2_REG 0x6C         // STBY_XA - STBY_ZG
#define ICM20602_I2C_IF 0x70                //1 – Disable I2C Slave module and put the serial interface in SPI mode only.
#define ICM20602_FIFO_COUNTH 0x72
#define ICM20602_FIFO_R_W 0x74              //FIFO READ WRITE
#define ICM20602_WHO_AM_I 0x75              //RO, default value ID = 0x12;
#define ICM20602_CONFIG 0x80
#define ICM20602_ADDR 0x69                  // Slave address, ad0 set 0

/*------------------------- 初始化ICM20602 -----------------------------*/
u8 ICM20602_sensor_init(void);
int Set_Accl_Thresh(u8 threshold);

/*------------------------ 设置加速度计和陀螺仪 -------------------------*/
u8 ICM_Set_Gyro_Fsr(u8 fsr);
u8 ICM_Set_Accel_Fsr(u8 fsr);
u8 ICM_Set_DLPF(u16 lpf);
u8 ICM_Set_Rate(u16 rate);

/*---------------------- 获取 加速度计、陀螺仪和温度 数据 ----------------*/
short ICM_Get_Temperature(void);
u8 ICM_Get_Gyroscope(short* gx, short* gy, short* gz);
u8 ICM_Get_Accelerometer(short* ax, short* ay, short* az);

注意事项

(一)ICM20602 从地址

从下面的数据手册节选可以看出:SA0引脚决定了从机地址的值,从下面的我的ICM20602原理图可以看出,我的SA0引脚接VCC,故始终为高电平,因此:ICM20602_ADDR = 0x69;又CS片选始终也为高电平,即为IIC通信模式。具体的使用要看原理图,硬件工程师将SA0和CS引脚是怎么接的,是接地还是接的VCC。
ICM20602六轴传感器-IIC通信模式_第1张图片
ICM20602六轴传感器-IIC通信模式_第2张图片

(二)ICM20602 器件id(0x12)

内部寄存器:WHO_AM_I ,不同的芯片的地址有可能不同,具体的还详细请看传感器的数据手册。
ICM20602六轴传感器-IIC通信模式_第3张图片

你可能感兴趣的:(ICM20602六轴传感器-IIC通信模式)