2.58 ICM-20602 六轴加速度陀螺仪模块(来自余葵的贡献)
2.58.1 模块来源
采购链接: https://detail.tmall.com/item.htm?abbucket=10&id=637794742826&rn=c93cc1cd3ad237b8a33e9ab2d22b9b6c&spm=a1z10.3-b.w4011-21785900764.19.6aff21fe5iOQr2 资料下载:(基于该模块的资料,百度云链接等) https://product.tdk.com.cn/system/files/dam/doc/product/sensor/mortion-inertial/imu/data_sheet/ds-000176-icm-20602-v1.1.pdf实物展示图
2.58.2 规格参数
工作电压:3.3-5V(模块自带 LDO)工作电流:3mA通信方式:IIC/SPI
2.58.3 模块资料
ICM-20602 是 InvenSense 公司推出的整合性 6 轴运动处理组件,其内部整合了 3 轴陀螺仪和 3 轴加速度传感器,且支持 IIC/SPI 接口,相较于 MPU6050,ICM-20602 拥有更高的精度与更小的输出噪声。
2.58.4 移植工程
本次移植使用 SPI 通讯协议
2.58.4.1 引脚选择
ICM20602 | 立创·梁山派 | 接线图 |
---|
2.58.4.2 移植步骤
初始化步骤
- 读取自检寄存器,确认 SPI 接口工作正常
- 复位 ICM-20602,让 ICM-20602 内部所有寄存器恢复默认值(向 0x6b 写入 0x80)
- 禁用 IIC 接口,使模块工作于 SPI 模式(向 0x70 写入 0x00)
- 设置模块时钟源(向 0x6b 写入 0x01)
- 配置陀螺仪低通滤波器
- 配置加速度计低通滤波器
- 配置采样率分频器
- 设置陀螺仪满量程
- 设置加速度计满量程
- 使能陀螺仪与加速度计
读取温度传感器
读取陀螺仪原始数据
读取加速度计原始数据
2.58.5 移植至工程
移植步骤中的导入.c 和.h 文件与上一节相同,只是将.c 和.h 文件更改为 icm20602.c 与 icm20602.h。见 2.2.3.3 移植至工程。这里不再过多讲述。移植完成后面修改相关代码。
在文件 icm20602.c 中,编写如下代码。
#include "icm20602.h"
#include "gd32f4xx.h"
#include "systick.h"
/* 此处定义了与ICM20602有关的宏 */
#define ICM_SPI SPI1
#define ICM_SPI_RCU RCU_SPI1
/* ICM20602使用的SPI总线及相关宏 */
#define ICM_SCK_RCU RCU_GPIOB
#define ICM_SCK_GPIO_PORT GPIOB
#define ICM_SCK_GPIO_PIN GPIO_PIN_10
#define ICM_SCK_GPIO_AF GPIO_AF_5
/* SCK对应的引脚及相关宏 */
#define ICM_MISO_RCU RCU_GPIOB
#define ICM_MISO_GPIO_PORT GPIOB
#define ICM_MISO_GPIO_PIN GPIO_PIN_14
#define ICM_MISO_GPIO_AF GPIO_AF_5
/* MISO对应的引脚及相关宏 */
#define ICM_MOSI_RCU RCU_GPIOC
#define ICM_MOSI_GPIO_PORT GPIOC
#define ICM_MOSI_GPIO_PIN GPIO_PIN_3
#define ICM_MOSI_GPIO_AF GPIO_AF_5
/* MOSI对应的引脚及相关宏 */
#define ICM_NSS_RCU RCU_GPIOB
#define ICM_NSS_GPIO_PORT GPIOB
#define ICM_NSS_GPIO_PIN GPIO_PIN_12
/* NSS对应的引脚及相关宏 */
/* 此处使用软件NSS,因此NSS引脚无需复用 */
#define ICM_NSS_SELECT gpio_bit_reset(ICM_NSS_GPIO_PORT, ICM_NSS_GPIO_PIN)
#define ICM_NSS_RELEASE gpio_bit_set(ICM_NSS_GPIO_PORT, ICM_NSS_GPIO_PIN)
/* 片选函数 */
/* ICM20602地址帧格式如下
* MSB LSB
* R/W A6 A5 A4 A3 A2 A1 A0
*
* 数据帧格式如下
* MSB LSB
* D7 D6 D5 D4 D3 D2 D1 D0
*/
#define REGISTER_READ 0x80
#define REGISTER_WRITE 0x00
/* 定义地址帧的首位,1为读,0为写 */
/* 此处定义了ICM20602的寄存器地址 */
#define XG_OFFS_TC_H 0x04
#define XG_OFFS_TC_L 0x05
#define YG_OFFS_TC_H 0x07
#define YG_OFFS_TC_L 0x08
#define ZG_OFFS_TC_H 0x0a
#define ZG_OFFS_TC_L 0x0b
/* 陀螺仪低噪声至低功耗偏移误差和陀螺仪失调温度补偿(TC)寄存器 */
#define SELF_TEST_X_ACCEL 0x0d
#define SELF_TEST_Y_ACCEL 0x0e
#define SELF_TEST_Z_ACCEL 0x0f
/* 自检寄存器,此寄存器中的值表示制造测试期间生成的自检输出。此值用于检查最终用户执行的后续自检输出。 */
#define XG_OFFS_USRH 0x13
#define XG_OFFS_USRL 0x14
#define YG_OFFS_USRH 0x15
#define YG_OFFS_USRL 0x16
#define ZG_OFFS_USRH 0x17
#define ZG_OFFS_USRL 0x18
/* 陀螺仪偏移校正寄存器 */
#define SMPLRT_DIV 0x19
/* 采样率分频器 */
#define CONFIG 0x1a
/* 配置寄存器 */
#define GYRO_CONFIG 0x1b
/* 陀螺仪配置寄存器 */
#define ACCEL_CONFIG_1 0x1c
/* 加速度计配置寄存器1 */
#define ACCEL_CONFIG_2 0x1d
/* 加速度配置寄存器2 */
#define LP_MODE_CFG 0x1e
/* 低功耗模式配置寄存器 */
#define ACCEL_WOM_X_THR 0x20
#define ACCEL_WOM_Y_THR 0x21
#define ACCEL_WOM_Z_THR 0x22
/* 运动中断唤醒阈值寄存器 */
#define FIFO_EN 0x23
/* 队列使能寄存器 */
#define FSYNC_INT 0x36
/* FSYNC中断标志寄存器,生成 FSYNC 中断后,此位会自动设置为 1。读取寄存器后,位清除为 0。 */
#define INT_PIN_CFG 0x37
/* FSYNC中断配置寄存器 */
#define FIFO_WM_INT_STATUS 0x39
/* 先进先出水印中断状态。读取时清除 */
#define INT_STATUS 0x3a
/* 中断状态寄存器 */
#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 SELF_TEST_X_GYRO 0x50
#define SELF_TEST_Y_GYRO 0x51
#define SELF_TEST_Z_GYRO 0x52
/* 陀螺仪自检输出寄存器,此寄存器中的值表示制造测试期间生成的自检输出。此值用于检查最终用户执行的后续自检输出。 */
#define FIFO_WM_TH1 0x60
#define FIFO_WM_TH2 0x61
/* 水印中断阈值寄存器 */
#define SIGNAL_PATH_RESET 0x68
/* 加速度数字信号路径复位寄存器 */
#define ACCEL_INTEL_CTRL 0x69
/* 加速度计控制寄存器 */
#define USER_CTRL 0x6a
/* 用户控制寄存器 */
#define PWR_MGMT_1 0x6b
/* 电源管理寄存器1 */
#define PWR_MGMT_2 0x6c
/* 电源管理寄存器2 */
#define I2C_IF 0x70
/* IIC接口寄存器 */
#define FIFO_COUNTH 0x72
#define FIFO_COUNTL 0x73
/* 队列写入数寄存器 */
#define FIFO_R_W 0x74
/* 队列读/写操作寄存器 */
#define WHO_AM_I 0x75
/* 设备身份验证寄存器 */
#define XA_OFFSET_H 0x77
#define XA_OFFSET_L 0x78
#define YA_OFFSET_H 0x7a
#define YA_OFFSET_L 0x7b
#define ZA_OFFSET_H 0x7d
#define ZA_OFFSET_L 0x7e
/* 加速度计偏移寄存器 */
/* 使能外设时钟 */
static void rcu_config(void)
{
rcu_periph_clock_enable(ICM_SPI_RCU);
rcu_periph_clock_enable(ICM_SCK_RCU);
rcu_periph_clock_enable(ICM_MISO_RCU);
rcu_periph_clock_enable(ICM_MOSI_RCU);
rcu_periph_clock_enable(ICM_NSS_RCU);
}
/* 配置外设引脚 */
static void gpio_config(void)
{
/* 配置SPI SCK引脚 */
gpio_output_options_set(ICM_SCK_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, ICM_SCK_GPIO_PIN);
gpio_mode_set(ICM_SCK_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, ICM_SCK_GPIO_PIN);
gpio_af_set(ICM_SCK_GPIO_PORT, ICM_SCK_GPIO_AF, ICM_SCK_GPIO_PIN);
/* 配置SPI MISO引脚 */
gpio_output_options_set(ICM_MISO_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, ICM_MISO_GPIO_PIN);
gpio_mode_set(ICM_MISO_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, ICM_MISO_GPIO_PIN);
gpio_af_set(ICM_MISO_GPIO_PORT, ICM_MISO_GPIO_AF, ICM_MISO_GPIO_PIN);
/* 配置SPI MOSI引脚 */
gpio_output_options_set(ICM_MOSI_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, ICM_MOSI_GPIO_PIN);
gpio_mode_set(ICM_MOSI_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, ICM_MOSI_GPIO_PIN);
gpio_af_set(ICM_MOSI_GPIO_PORT, ICM_MOSI_GPIO_AF, ICM_MOSI_GPIO_PIN);
/* 配置SPI NSS引脚 */
gpio_mode_set(ICM_NSS_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, ICM_NSS_GPIO_PIN);
gpio_output_options_set(ICM_NSS_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, ICM_NSS_GPIO_PIN);
}
/* 配置SPI总线 */
static void spi_config(void)
{
spi_parameter_struct spi_init_struct;
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; /* 全双工模式 */
spi_init_struct.device_mode = SPI_MASTER; /* 主机模式 */
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT; /* 帧长为8位 */
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE; /* 上升沿采样,下降沿传输 */
spi_init_struct.nss = SPI_NSS_SOFT; /* 软件NSS */
spi_init_struct.prescale = SPI_PSC_32; /* 通讯频率为主频32分频,即3.75Mbit/s */
spi_init_struct.endian = SPI_ENDIAN_MSB; /* MSB优先传输 */
spi_init(ICM_SPI, &spi_init_struct);
}
/*
* 功能 ICM20602写寄存器
* 参数 addr 寄存器地址
* dat 需要写入的数据
* 返回 无
*/
static void icm20602_writeReg(uint8_t addr, uint8_t dat)
{
uint8_t cmd;
ICM_NSS_SELECT;
cmd = addr | REGISTER_WRITE; /* 注:此处的运算实质上起到了NSS引脚拉低后的2ns延时作用,因此不可移除 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_RBNE))
spi_i2s_data_receive(ICM_SPI);/* 读取读SPI_DATA寄存器中的数据以复位RBNE标志位 */
while(RESET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE));/* 等待发送缓冲区清空 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE))
spi_i2s_data_transmit(ICM_SPI, cmd);/* 发送地址与写指令 */
while(RESET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE));/* 等待发送缓冲区清空 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE))
spi_i2s_data_transmit(ICM_SPI, dat);/* 发送需要写入寄存器的值 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TRANS))/* 等待数据传输完毕 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_RBNE))
spi_i2s_data_receive(ICM_SPI);/* 读取读SPI_DATA寄存器中的数据以复位RBNE标志位 */
while(RESET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE));/* 等待发送缓冲区清空 */
ICM_NSS_RELEASE;
}
/*
* 功能 ICM20602读寄存器
* 参数 addr 寄存器地址
* dat 读取得到的数据
* 返回 无
*/
static void icm20602_readReg(uint8_t addr, uint8_t *dat)
{
uint8_t cmd;
uint8_t res;
ICM_NSS_SELECT;
cmd = addr | REGISTER_READ; /* 注:此处的运算实质上起到了NSS引脚拉低后的2ns延时作用,因此不可移除 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_RBNE))
res = spi_i2s_data_receive(ICM_SPI);/* 读取读SPI_DATA寄存器中的数据以复位RBNE标志位 */
while(RESET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE));/* 等待发送缓冲区清空 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE))
spi_i2s_data_transmit(ICM_SPI, cmd);/* 发送地址与读指令 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TRANS));/* 等待数据传输完毕 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_RBNE))
spi_i2s_data_receive(ICM_SPI);/* 本周期(以缓冲区内数据发送完成为结束)内收到的数据不能使用 */
while(RESET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE));/* 等待发送缓冲区清空 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE))
spi_i2s_data_transmit(ICM_SPI, 0x00);/* 传输数据以进行接收 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TRANS));/* 等待数据传输完毕 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_RBNE))
res = spi_i2s_data_receive(ICM_SPI);/* 这个周期收到的才是传感器返回的数据 */
while(RESET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE));/* 等待发送缓冲区清空 */
ICM_NSS_RELEASE;
*dat = res;
}
/*
* 功能 ICM20602读取多字节数据
* 参数 addr 寄存器地址
* dat 读取得到的数据
* len 需要读取的数据长度
* 返回 无
*/
static void icm20602_readBytes(uint8_t addr, uint8_t *dat_array, uint8_t len)
{
uint8_t cmd;
uint8_t *dat_ptr = dat_array;
uint8_t i;
ICM_NSS_SELECT;
cmd = addr | REGISTER_READ; /* 注:此处的运算实质上起到了NSS引脚拉低后的2ns延时作用,因此不可移除 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_RBNE))
spi_i2s_data_receive(ICM_SPI);/* 读取读SPI_DATA寄存器中的数据以复位RBNE标志位 */
while(RESET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE));/* 等待发送缓冲区清空 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE))
spi_i2s_data_transmit(ICM_SPI, cmd);/* 发送地址与读指令 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TRANS));/* 等待数据传输完毕 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_RBNE))
spi_i2s_data_receive(ICM_SPI);/* 本周期(以缓冲区内数据发送完成为结束)内收到的数据不能使用 */
while(RESET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE));/* 等待发送缓冲区清空 */
for(i = 0; i < len; i++)
{
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE))
spi_i2s_data_transmit(ICM_SPI, *dat_ptr);/* 传输数据以进行接收 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TRANS));/* 等待数据传输完毕 */
while(SET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_RBNE))
*dat_ptr = spi_i2s_data_receive(ICM_SPI);/* 这个周期收到的才是传感器返回的数据 */
while(RESET == spi_i2s_flag_get(ICM_SPI, SPI_FLAG_TBE));/* 等待发送缓冲区清空 */
dat_ptr++;
}
ICM_NSS_RELEASE;
}
/*
* 功能 ICM20602自检
* 参数 无
* 返回 无
*/
void icm20602_selfTest(void)
{
uint8_t deviceID = 0x00;
while(deviceID != 0x12)
{
icm20602_readReg(WHO_AM_I, &deviceID);
delay_1ms(10);
//卡在这里原因有以下几点
//1 传感器坏了,如果是新的这样的概率极低
//2 接线错误或者没有接好
//3 可能你需要外接上拉电阻,上拉到3.3V
//(转自逐飞库)
}
}
/*
* 功能 ICM20602初始化
* 参数 icm_struct icm20602_parameter_struct类型指针,指向一个icm20602配置结构体
* 返回 无
*/
void icm20602_init(icm20602_parameter_struct *icm_struct)
{
uint8_t regValue = 0x00;
icm20602_parameter_struct icm_temp_param = *icm_struct;
rcu_config();
gpio_config();
spi_config();
ICM_NSS_RELEASE;
spi_enable(ICM_SPI);
/* 初始化SPI并释放片选引脚 */
delay_1ms(10);
icm20602_selfTest();
/* 上电自检 */
icm20602_writeReg(PWR_MGMT_1, 0x80);
/* 复位全部寄存器 */
delay_1ms(2);
while(0x41 != regValue)
{
icm20602_readReg(PWR_MGMT_1, ®Value);
delay_1ms(5);
}/* 等待复位完成 */
icm20602_writeReg(I2C_IF, 0x00);/* 禁用I2C接口,使模块工作于SPI模式 */
icm20602_writeReg(PWR_MGMT_1, 0x01);/* 设置时钟源 */
switch(icm_temp_param.gyro_tempture_band)/* 配置陀螺仪滤波器与温度计滤波器带宽 */
{
case GYRO_3281HZ_TEMPERATURE_4000HZ_RATE_8KHZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x07);
break;
case GYRO_5HZ_TEMPERATURE_5HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x06);
break;
case GYRO_10HZ_TEMPERATURE_10HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x05);
break;
case GYRO_20HZ_TEMPERATURE_20HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x04);
break;
case GYRO_41HZ_TEMPERATURE_42HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x03);
break;
case GYRO_92HZ_TEMPERATURE_98HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x02);
break;
case GYRO_176HZ_TEMPERATURE_188HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x01);
break;
case GYRO_250HZ_TEMPERATURE_4000HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x00);
break;
case GYRO_3281HZ_TEMPERATURE_4000HZ_RATE_32KHZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
regValue = regValue | 0x02;
icm20602_writeReg(GYRO_CONFIG, regValue);
break;
case GYRO_8173HZ_TEMPERATURE_4000HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
regValue = regValue | 0x01;
icm20602_writeReg(GYRO_CONFIG,regValue);
break;
}
icm20602_writeReg(SMPLRT_DIV, icm_temp_param.div);
/* 配置采样率分频器,注:仅gyro_tempture_band介于
GYRO_5HZ_TEMPERATURE_5HZ与GYRO_176HZ_TEMPERATURE_188HZ之间时该寄存器有效 */
switch(icm_temp_param.gyro_scale)/* 设置陀螺仪满量程 */
{
case GYRO_250DPS_FULLSCALE:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xe7;
icm20602_writeReg(GYRO_CONFIG, regValue);
break;
case GYRO_500DPS_FULLSCALE:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xe7;
regValue = regValue | 0x08;
icm20602_writeReg(GYRO_CONFIG, regValue);
break;
case GYRO_1000DPS_FULLSCALE:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xe7;
regValue = regValue | 0x10;
icm20602_writeReg(GYRO_CONFIG, regValue);
break;
case GYRO_2000DPS_FULLSCALE:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xe7;
regValue = regValue | 0x18;
icm20602_writeReg(GYRO_CONFIG, regValue);
break;
}
switch(icm_temp_param.accel_scale)/* 设置加速度计满量程 */
{
case ACCEL_2G_FULLSCALE:
icm20602_writeReg(ACCEL_CONFIG_1, 0x00);
break;
case ACCEL_4G_FULLSCALE:
icm20602_writeReg(ACCEL_CONFIG_1, 0x08);
break;
case ACCEL_8G_FULLSCALE:
icm20602_writeReg(ACCEL_CONFIG_1, 0x10);
break;
case ACCEL_16G_FULLSCALE:
icm20602_writeReg(ACCEL_CONFIG_1, 0x18);
break;
}
switch(icm_temp_param.accel_band)/* 配置加速度计低通滤波器带宽 */
{
case ACCEL_5HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x06);
break;
case ACCEL_10HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x05);
break;
case ACCEL_21HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x04);
break;
case ACCEL_45HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x03);
break;
case ACCEL_99HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x02);
break;
case ACCEL_218HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x01);
break;
case ACCEL_420HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x07);
break;
case ACCEL_1046HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x10);
break;
}
icm20602_writeReg(PWR_MGMT_2, 0x00);/* 设置加速度计与陀螺仪使能 */
}
/*
* 功能 设置ICM20602陀螺仪-温度计低通滤波器带宽
* 参数 band:gyro_temperature_3dB_bandWidth枚举类型,需要设置的陀螺仪-温度计低通滤波器带宽
* 返回 无
*/
void icm20602_GyroTempBand_config(gyro_temperature_3dB_bandWidth band)
{
uint8_t regValue;
switch(band)
{
case GYRO_3281HZ_TEMPERATURE_4000HZ_RATE_8KHZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x07);
break;
case GYRO_5HZ_TEMPERATURE_5HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x06);
break;
case GYRO_10HZ_TEMPERATURE_10HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x05);
break;
case GYRO_20HZ_TEMPERATURE_20HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x04);
break;
case GYRO_41HZ_TEMPERATURE_42HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x03);
break;
case GYRO_92HZ_TEMPERATURE_98HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x02);
break;
case GYRO_176HZ_TEMPERATURE_188HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x01);
break;
case GYRO_250HZ_TEMPERATURE_4000HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
icm20602_writeReg(GYRO_CONFIG, regValue);
icm20602_writeReg(CONFIG, 0x00);
break;
case GYRO_3281HZ_TEMPERATURE_4000HZ_RATE_32KHZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
regValue = regValue | 0x02;
icm20602_writeReg(GYRO_CONFIG, regValue);
break;
case GYRO_8173HZ_TEMPERATURE_4000HZ:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xf8;
regValue = regValue | 0x01;
icm20602_writeReg(GYRO_CONFIG,regValue);
break;
}
}
/*
* 功能 设置ICM20602加速度计低通滤波器带宽
* 参数 band:accel_3dB_bandWidth枚举类型,需要设置的加速度计低通滤波器带宽
* 返回 无
*/
void icm20602_AccelBand_config(accel_3dB_bandWidth band)
{
switch(band)
{
case ACCEL_5HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x06);
break;
case ACCEL_10HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x05);
break;
case ACCEL_21HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x04);
break;
case ACCEL_45HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x03);
break;
case ACCEL_99HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x02);
break;
case ACCEL_218HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x01);
break;
case ACCEL_420HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x07);
break;
case ACCEL_1046HZ:
icm20602_writeReg(ACCEL_CONFIG_2, 0x10);
break;
}
}
/*
* 功能 设置ICM20602陀螺仪与加速度计满量程
* 参数 gyro_scale:gyro_fullScale枚举类型,需要设置的陀螺仪满量程
* accel_scale:accel_fullScale枚举类型,需要设置的加速度计满量程
* 返回 无
*/
void icm20602_FullScale_config(gyro_fullScale gyro_scale, accel_fullScale accel_scale)
{
uint8_t regValue;
switch(gyro_scale)/* 设置陀螺仪满量程 */
{
case GYRO_250DPS_FULLSCALE:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xe7;
icm20602_writeReg(GYRO_CONFIG, regValue);
break;
case GYRO_500DPS_FULLSCALE:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xe7;
regValue = regValue | 0x08;
icm20602_writeReg(GYRO_CONFIG, regValue);
break;
case GYRO_1000DPS_FULLSCALE:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xe7;
regValue = regValue | 0x10;
icm20602_writeReg(GYRO_CONFIG, regValue);
break;
case GYRO_2000DPS_FULLSCALE:
icm20602_readReg(GYRO_CONFIG, ®Value);
regValue = regValue & 0xe7;
regValue = regValue | 0x18;
icm20602_writeReg(GYRO_CONFIG, regValue);
break;
}
switch(accel_scale)/* 设置加速度计满量程 */
{
case ACCEL_2G_FULLSCALE:
icm20602_writeReg(ACCEL_CONFIG_1, 0x00);
break;
case ACCEL_4G_FULLSCALE:
icm20602_writeReg(ACCEL_CONFIG_1, 0x08);
break;
case ACCEL_8G_FULLSCALE:
icm20602_writeReg(ACCEL_CONFIG_1, 0x10);
break;
case ACCEL_16G_FULLSCALE:
icm20602_writeReg(ACCEL_CONFIG_1, 0x18);
break;
}
}
/*
* 功能 获取ICM20602加速度数据
* 参数 accelList:uint16_t类型的数组指针,用于存储返回的加速度值,按顺序依次存储X、Y、Z轴加速度
* 返回 无
*/
void icm20602_ReadAccel(int16_t *accelList)
{
uint8_t addr = ACCEL_XOUT_H;
uint8_t dat[6];
icm20602_readBytes(addr, dat, 6);
accelList[0] = (int16_t)((uint16_t)dat[0] << 8 | dat[1]);
accelList[1] = (int16_t)((uint16_t)dat[2] << 8 | dat[3]);
accelList[2] = (int16_t)((uint16_t)dat[4] << 8 | dat[5]);
}
/*
* 功能 获取ICM20602角速度数据
* 参数 gyroList:uint16_t类型的数组指针,用于存储返回的角速度值,按顺序依次存储绕X、Y、Z轴角速度
* 返回 无
*/
void icm20602_ReadGyro(int16_t *gyroList)
{
uint8_t addr = GYRO_XOUT_H;
uint8_t dat[6];
icm20602_readBytes(addr, dat, 6);
gyroList[0] = (int16_t)((uint16_t)dat[0] << 8 | dat[1]);
gyroList[1] = (int16_t)((uint16_t)dat[2] << 8 | dat[3]);
gyroList[2] = (int16_t)((uint16_t)dat[4] << 8 | dat[5]);
}
/*
* 功能 获取ICM20602温度传感器数据
* 参数 gyroList:uint16_t类型的数组指针,用于存储返回的角速度值,按顺序依次存储绕X、Y、Z轴角速度
* 返回 无
*/
void icm20602_ReadTempture(float *temp)
{
uint8_t addr = TEMP_OUT_H;
uint8_t dat[2];
icm20602_readBytes(addr, dat, 2);
*temp = (double)((int16_t)((uint16_t)dat[0] << 8 |dat[1])/326.8) + 25.0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
在文件 icm20602.h 中,编写如下代码。
#ifndef __ICM20602_H__
#define __ICM20602_H__
#include "gd32f4xx.h"
/* 用于描述陀螺仪满量程的枚举类型,详见芯片的Datasheet */
typedef enum
{
GYRO_250DPS_FULLSCALE = 0,
GYRO_500DPS_FULLSCALE,
GYRO_1000DPS_FULLSCALE,
GYRO_2000DPS_FULLSCALE
}gyro_fullScale;
/* 用于描述加速度计满量程的枚举类型,详见芯片的Datasheet */
typedef enum
{
ACCEL_2G_FULLSCALE = 0,
ACCEL_4G_FULLSCALE,
ACCEL_8G_FULLSCALE,
ACCEL_16G_FULLSCALE,
}accel_fullScale;
/* 用于描述陀螺仪-温度计低通滤波器3dB带宽的枚举类型,详见芯片的Datasheet */
typedef enum
{
GYRO_3281HZ_TEMPERATURE_4000HZ_RATE_8KHZ = 0,
GYRO_5HZ_TEMPERATURE_5HZ,
GYRO_10HZ_TEMPERATURE_10HZ,
GYRO_20HZ_TEMPERATURE_20HZ,
GYRO_41HZ_TEMPERATURE_42HZ,
GYRO_92HZ_TEMPERATURE_98HZ,
GYRO_176HZ_TEMPERATURE_188HZ,
GYRO_250HZ_TEMPERATURE_4000HZ,
GYRO_3281HZ_TEMPERATURE_4000HZ_RATE_32KHZ,
GYRO_8173HZ_TEMPERATURE_4000HZ,
}gyro_temperature_3dB_bandWidth;
/* 用于描述加速度计低通滤波器3dB带宽的枚举类型,详见芯片的Datasheet */
typedef enum
{
ACCEL_420HZ = 0,
ACCEL_5HZ,
ACCEL_10HZ,
ACCEL_21HZ,
ACCEL_45HZ,
ACCEL_99HZ,
ACCEL_218HZ,
ACCEL_1046HZ,
}accel_3dB_bandWidth;
/* icm20602初始化结构体,用于配置icm20602 */
typedef struct
{
gyro_fullScale gyro_scale; /* 陀螺仪满量程 */
accel_fullScale accel_scale; /* 加速度计满量程 */
gyro_temperature_3dB_bandWidth gyro_tempture_band; /* 陀螺仪-温度计低通滤波器带宽 */
accel_3dB_bandWidth accel_band; /* 加速度计低通滤波器带宽 */
uint8_t div; /* 采样率分频器,仅仅gyro_tempture_band介于
GYRO_5HZ_TEMPERATURE_5HZ与GYRO_176HZ_TEMPERATURE_188HZ之间
时该寄存器有效 */
}icm20602_parameter_struct;
void icm20602_selfTest(void);/* icm20602自检 */
void icm20602_init(icm20602_parameter_struct *icm_struct);/* icm20602初始化 */
void icm20602_GyroTempBand_config(gyro_temperature_3dB_bandWidth band);/* 设置icm20602陀螺仪-温度传感器低通滤波器带宽 */
void icm20602_AccelBand_config(accel_3dB_bandWidth band);/* 设置icm20602加速度计低通滤波器带宽 */
void icm20602_FullScale_config(gyro_fullScale gyro_scale, accel_fullScale accel_scale);/* 设置icm20602陀螺仪与加速度计满量程 */
void icm20602_ReadAccel(int16_t *accelList);/* 读取icm20602三轴加速度 */
void icm20602_ReadGyro(int16_t *gyroList);/* 读取icm20602三轴角速度 */
void icm20602_ReadTempture(float *temp);/* 读取icm20602温度传感器数值 */
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
移植完成以上文件后,即可获取陀螺仪和加速度原始数据,通过角速度积分、三轴加速度分量求解反三角函数等方法即可解出角度数据。
2.58.6 移植验证
在自己工程中的 main 主函数中,编写如下。
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "console.h"/* 该头文件负责初始化串口,并将printf函数重定向至串口输出 */
#include "icm20602.h"
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
float temp;
float real_gyro[3];/* 带单位的角速度数据 */
float real_accel[3];/* 带单位的加速度数据 */
int16_t gyroList[3];/* 从传感器中获取的角速度原始数据 */
int16_t accelList[3];/* 从传感器中获取的加速度原始数据 */
uint8_t i;
icm20602_parameter_struct icm_init_struct;
icm_init_struct.accel_band = ACCEL_45HZ;
icm_init_struct.accel_scale = ACCEL_16G_FULLSCALE;
icm_init_struct.div = 7;
icm_init_struct.gyro_scale = GYRO_500DPS_FULLSCALE;
icm_init_struct.gyro_tempture_band = GYRO_176HZ_TEMPERATURE_188HZ;
systick_config();
/* init function begin here */
console_init();/* 输出串口初始化 */
icm20602_init(&icm_init_struct);/* icm20602初始化 */
while(1)
{
icm20602_ReadAccel(accelList);
icm20602_ReadGyro(gyroList);
icm20602_ReadTempture(&temp);
/* 读取传感器数据 */
for(i=0; i<3; i++)
{
real_accel[i] = (float)accelList[i] / 2048;
real_gyro[i] = (float)gyroList[i] / 65.5f;
}/* 将传感器数据转换为带物理单位的数据 */
printf("tempture is %f\r\n", temp);
printf("accX is %.2f g, accY is %.2f g, accZ is %.2f g\r\n", real_accel[0], real_accel[1], real_accel[2]);
printf("gyroX is %.4f dps, gyroY is %.4f dps, gyroZ is %.4f dps\r\n", real_gyro[0], real_gyro[1], real_gyro[2]);
printf("\r\n");
delay_1ms(20);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
移植现象:串口终端输出三轴角速度、三轴加速度及温度.
移植成功示例如下:
移植成功示例