前言
基于RT-thread操作系统,获取BMI088这款IMU的陀螺仪与加速度数据,本文驱动BMI088使用SPI通讯,主控MCU使用的是STM32F04ZGT6,在工程配置过程中会使用到RT-Thread中的软件包,并且还需对软件包里的文件进行一些修改,如果懒得修改的也可以 直接使用我上传的完整工程
一、BMI088的一些介绍
1、BMI088引脚定义图
2、BMI088官方手册推荐电路连接图
3、我这边实际设计的电路图
4、我们只需要关注几个引脚,需要MCU端操作的(精简起见)
SCK----------PB13 (SPI通讯的时钟引脚,连接MCU的PB13)
SDI-----------PB15 (SPI通讯的MOSI, 连接MCU的PB15)
SDO1、SDO2-----------PB14 (SPI通讯的MISO, 连接到MCU的PB14)
CSB1---------PD8 (BMI088的加速度计片选引脚,想要获取加速度计值,就要把这个引脚拉高)
CSB2--------PD10 (BMI088的角速度计片选引脚,想要获取角速度计值,就要把这个引脚拉高)
二、新建工程
1、创建
2、编译一波,出现如下报错
3、修改芯片支持包版本
4、改为0.2.2
5、再编译,无报错了
三、CubeMX配置
1、打开CubeMX Settings
2、时钟源选择外部高速晶振
3、配置程序下载口
4、打开串口一调试用
5、配置SPI的通讯引脚
6、打开SPI2,引脚变绿就是配置成功了
7、配置时钟树,时钟频率拉满
8、工具链选择MDK-ARM
9、生成代码
四、工程配置
1、添加软件包
2、搜索BMI088,添加软件包
3、进入board.h,打开SPI2
4、打开SPI设备驱动程序
5、使能SPI模块
6、编译一下,有如下报错,说drv_gpio.h这个文件找不到
7、我们直接把这一行删掉
8、再编译,成功通过
五、代码编写(因为我主要是写给自己以后看的,可能会有点啰嗦哦~ 大家可以挑重点看)
1、主函数中这么写
#include "system_deal.h"
int main(void)
{
SystemStartInit();
return RT_EOK;
}
2、新建一个文件夹system_deal,在该文件夹下新建一个.c和.h文件
3、包含这个system_deal文件的路径
4、在system_deal.h文件里写下如下代码,这里面的SYS_LED,就是我板子上的一个灯,用这个灯来闪烁,可以直观的观察我的程序是否跑起来了
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-12-30 Administrator the first version
*/
#ifndef APPLICATIONS_SYSTEM_DEAL_SYSTEM_DEAL_H_
#define APPLICATIONS_SYSTEM_DEAL_SYSTEM_DEAL_H_
#include <rtdevice.h>
#include <rtthread.h>
#include "board.h"
#include "stdio.h"
#include "bmi088_deal.h"
/* bmi088 imu config */
#define BMI088_IMU_ENABLE 1
/* system io */
#define SYS_LED GET_PIN(G, 13)
/* thread information */
#define SYS_THREAD_STACK 1024
#define SYS_THREAD_PRO 15
#define SYS_THREAD_TICK 10
extern void SystemStartInit(void);
#endif /* APPLICATIONS_SYSTEM_DEAL_SYSTEM_DEAL_H_ */
5、在system_deal.c文件里写下如下代码
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-12-30 Administrator the first version
*/
#include "system_deal.h"
/*********************************************************************************************************
** Function name: SystemLedRun
** Descriptions: System Led Run
** input parameters: NONE
** output parameters: NONE
** Returned value: NONE
*********************************************************************************************************/
static void SystemLedRun(void)
{
static uint8_t l_ucmode = 0;
if (l_ucmode == 0)
{
rt_pin_write(SYS_LED, PIN_HIGH);
l_ucmode = 1;
}
else if (l_ucmode == 1)
{
rt_pin_write(SYS_LED, PIN_LOW);
l_ucmode = 0;
}
}
/*********************************************************************************************************
** Function name: SysDeal_thread
** Descriptions: SysDeal thread
** input parameters: parameter
** output parameters: NONE
** Returned value: NONE
*********************************************************************************************************/
static void SysDeal_thread(void* parameter)
{
rt_pin_mode(SYS_LED, PIN_MODE_OUTPUT);
while (1)
{
SystemLedRun();
rt_thread_mdelay(200);
}
}
/*********************************************************************************************************
** Function name: SystemDealTaskInit
** Descriptions: System Task Init
** input parameters: NONE
** output parameters: NONE
** Returned value: NONE
*********************************************************************************************************/
void SystemDealTaskInit(void)
{
rt_thread_t SysDeal_tid;
SysDeal_tid = rt_thread_create("sys_ctl", SysDeal_thread, RT_NULL, SYS_THREAD_STACK, SYS_THREAD_PRO, SYS_THREAD_TICK);
if (SysDeal_tid != RT_NULL)
{
rt_thread_startup(SysDeal_tid);
}
else
{
#if DEBUG_LOG_ENABLE
rt_kprintf("/--> SysDeal create failed!\n");
#endif
}
}
/*********************************************************************************************************
** Function name: SystemTaskInit
** Descriptions: System Task Init
** input parameters: NONE
** output parameters: NONE
** Returned value: NONE
*********************************************************************************************************/
static void SystemTaskInit(void)
{
rt_thread_mdelay(100);
SystemDealTaskInit(); // 15
#if BMI088_IMU_ENABLE
Bmi088ImuDealTaskInit(); // 13
#endif
}
/*********************************************************************************************************
** Function name: SystemStartInit
** Descriptions: System Start Init
** input parameters: NONE
** output parameters: NONE
** Returned value: NONE
*********************************************************************************************************/
void SystemStartInit(void)
{
SystemTaskInit();
}
6、再新建一个文件夹叫bmi088_deal,在这个文件夹下分别新建.c和.h文件
7、添加bmi088_deal文件的路径
8、在bmi088_deal.c文件中写入如下代码
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-12-31 Administrator the first version
*/
#include "bmi088_deal.h"
rt_thread_t Bmi088_Handler;
ImuDev_t s_tImuDev;
pImuDev_t pImuDev = (pImuDev_t)&s_tImuDev;
/*********************************************************************************************************
** Function name: Bmi088DealInit
** Descriptions: Bmi088 Deal Init
** input parameters: NONE
** output parameters: NONE
*********************************************************************************************************/
static void Bmi088DealInit(void)
{
rt_err_t res;
// init imu
rt_pin_mode(BMI088_CSB1_ACCEL_PIN, PIN_MODE_OUTPUT);
rt_pin_write(BMI088_CSB1_ACCEL_PIN, PIN_HIGH);
rt_pin_mode(BMI088_CSB2_AGYRO_PIN, PIN_MODE_OUTPUT);
rt_pin_write(BMI088_CSB2_AGYRO_PIN, PIN_HIGH);
rt_hw_spi_device_attach(BMI088_BUS_NAME, BMI088_ACCEL_NAME, GPIOD, GPIO_PIN_8);
rt_hw_spi_device_attach(BMI088_BUS_NAME, BMI088_GYRO_NAME, GPIOD, GPIO_PIN_10);
pImuDev->AccelCfg.intf.dev_name = BMI088_ACCEL_NAME;
pImuDev->GyrolCfg.intf.dev_name = BMI088_GYRO_NAME;
rt_hw_bmi088_init("bmi", &pImuDev->AccelCfg, &pImuDev->GyrolCfg);
// init accel
pImuDev->AccelDev = rt_device_find(BMI088_ACCEL_DEV_NAME);
if (!pImuDev->AccelDev)
{
#if DEBUG_LOG_ENABLE
rt_kprintf("/--> %s find failed! \n", BMI088_ACCEL_DEV_NAME);
#endif
}
res = rt_device_open(pImuDev->AccelDev, RT_DEVICE_OFLAG_RDWR);
if (RT_EOK != res)
{
#if DEBUG_LOG_ENABLE
rt_kprintf("/--> %s open err ...\n", BMI088_ACCEL_DEV_NAME);
#endif
}
// init gyro
pImuDev->GyroDev = rt_device_find(BMI088_GYRO_DEV_NAME);
if (!pImuDev->GyroDev)
{
#if DEBUG_LOG_ENABLE
rt_kprintf("/--> %s find failed! \n", BMI088_GYRO_DEV_NAME);
#endif
}
res = rt_device_open(pImuDev->GyroDev, RT_DEVICE_OFLAG_RDWR);
if (RT_EOK != res)
{
#if DEBUG_LOG_ENABLE
rt_kprintf("/--> %s open err ...\n", BMI088_GYRO_DEV_NAME);
#endif
}
}
void Bmi088GetData(void)
{
rt_device_read(pImuDev->AccelDev, 0, &pImuDev->tBmi088Msg.AccelData, 1);
rt_device_read(pImuDev->GyroDev, 0, &pImuDev->tBmi088Msg.GyroData, 1);
}
/*********************************************************************************************************
** Function name: Bmi088Task_1ms
** Descriptions: Bmi088 Deal thread
** input parameters: NONE
** output parameters: NONE
** Returned value: NONE
** Author: XYQ
*********************************************************************************************************/
void Bmi088_Task(void* parameter)
{
Bmi088DealInit();
while (1)
{
Bmi088GetData();
rt_kprintf("x:%f y:%f z:%f \r\n",pImuDev->tBmi088Msg.GyroData.data.gyro.x,pImuDev->tBmi088Msg.GyroData.data.gyro.y,pImuDev->tBmi088Msg.GyroData.data.gyro.z);
rt_thread_mdelay(100);
}
}
/*********************************************************************************************************
** Function name: Bmi088ImuDealTaskInit
** Descriptions: Bmi088 Deal Task Init
** input parameters: NONE
** output parameters: NONE
** Returned value: NONE
** Author: XYQ
*********************************************************************************************************/
void Bmi088ImuDealTaskInit(void)
{
Bmi088_Handler = rt_thread_create("bmi088_entry", Bmi088_Task, RT_NULL, BMI088_THREAD_STACK , BMI088_THREAD_PRO, BMI088_THREAD_TICK);
if (Bmi088_Handler != RT_NULL)
{
rt_thread_startup(Bmi088_Handler);
}
else
{
#if DEBUG_LOG_ENABLE
rt_kprintf("/--> Bmi088_Handler create failed!\n");
#endif
}
}
9、在bmi088_deal.h文件中写入如下代码
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-12-31 Administrator the first version
*/
#ifndef APPLICATIONS_BMI088_DEAL_BMI088_DEAL_H_
#define APPLICATIONS_BMI088_DEAL_BMI088_DEAL_H_
#include <rtdevice.h>
#include <rtthread.h>
#include "board.h"
#include "drv_spi.h"
#include "sensor.h"
#include "sensor_intf_bmi088.h"
#define BMI088_THREAD_STACK 2048
#define BMI088_THREAD_PRO 12
#define BMI088_THREAD_TICK 10
/* imu param */
#define BMI088_BUS_NAME "spi2"
#define BMI088_ACCEL_NAME "spi20"
#define BMI088_GYRO_NAME "spi21"
#define BMI088_ACCEL_DEV_NAME "acce_bmi"
#define BMI088_GYRO_DEV_NAME "gyro_bmi"
#define BMI088_CSB1_ACCEL_PIN GET_PIN(D, 8)
#define BMI088_CSB2_AGYRO_PIN GET_PIN(D, 10)
/* Bmi088Msg_t */
typedef struct
{
uint8_t DataGetFlg;
uint32_t DataGetCyc;
struct rt_sensor_data AccelData;
struct rt_sensor_data GyroData;
} Bmi088Msg_t;
/* ImuDev_t */
typedef struct
{
rt_device_t AccelDev;
rt_device_t GyroDev;
struct rt_sensor_config AccelCfg;
struct rt_sensor_config GyrolCfg;
Bmi088Msg_t tBmi088Msg;
} ImuDev_t,*pImuDev_t;
void Bmi088ImuDealTaskInit(void);
#endif /* APPLICATIONS_BMI088_DEAL_BMI088_DEAL_H_ */
10、接下来需要对bmi088这个软件包里的东西进行一些修改,将bmi088.h文件里代码用以下代码进行替换
#ifndef __BMI088_H__
#define __BMI088_H__
#include <rtthread.h>
#include "sensor.h"
/*************************** Common Macros for both Accel and Gyro *****************************/
// Bit #0 : Read/Write bit
// Bit #1-7: Address AD
#define BMI08X_SPI_RD_MASK UINT8_C(0x80)
#define BMI08X_SPI_WR_MASK UINT8_C(0x7F)
/* CMD: soft reset */
#define BMI08X_SOFT_RESET_CMD UINT8_C(0xB6)
/* CMD: accel power save */
#define BMI08X_ACCEL_PWR_ACTIVE_CMD UINT8_C(0x00)
#define BMI08X_ACCEL_PWR_SUSPEND_CMD UINT8_C(0x03)
/* CMD: accel power control */
#define BMI08X_ACCEL_POWER_DISABLE_CMD UINT8_C(0x00)
#define BMI08X_ACCEL_POWER_ENABLE_CMD UINT8_C(0x04)
/* Accel Power Mode */
#define BMI08X_ACCEL_PM_ACTIVE UINT8_C(0x00)
#define BMI08X_ACCEL_PM_SUSPEND UINT8_C(0x03)
/* Gyro Power mode */
#define BMI08X_GYRO_PM_NORMAL UINT8_C(0x00)
#define BMI08X_GYRO_PM_DEEP_SUSPEND UINT8_C(0x20)
#define BMI08X_GYRO_PM_SUSPEND UINT8_C(0x80)
/* Accel Bandwidth */
#define BMI08X_ACCEL_BW_OSR4 UINT8_C(0x00)
#define BMI08X_ACCEL_BW_OSR2 UINT8_C(0x01)
#define BMI08X_ACCEL_BW_NORMAL UINT8_C(0x02)
/* Accel Output Data Rate */
#define BMI08X_ACCEL_ODR_12_5_HZ UINT8_C(0x05)
#define BMI08X_ACCEL_ODR_25_HZ UINT8_C(0x06)
#define BMI08X_ACCEL_ODR_50_HZ UINT8_C(0x07)
#define BMI08X_ACCEL_ODR_100_HZ UINT8_C(0x08)
#define BMI08X_ACCEL_ODR_200_HZ UINT8_C(0x09)
#define BMI08X_ACCEL_ODR_400_HZ UINT8_C(0x0A)
#define BMI08X_ACCEL_ODR_800_HZ UINT8_C(0x0B)
#define BMI08X_ACCEL_ODR_1600_HZ UINT8_C(0x0C)
/* Accel Range */
#define BMI088_ACCEL_RANGE_3G UINT8_C(0x00)
#define BMI088_ACCEL_RANGE_6G UINT8_C(0x01)
#define BMI088_ACCEL_RANGE_12G UINT8_C(0x02)
#define BMI088_ACCEL_RANGE_24G UINT8_C(0x03)
/* Gyro Range */
#define BMI08X_GYRO_RANGE_2000_DPS UINT8_C(0x00)
#define BMI08X_GYRO_RANGE_1000_DPS UINT8_C(0x01)
#define BMI08X_GYRO_RANGE_500_DPS UINT8_C(0x02)
#define BMI08X_GYRO_RANGE_250_DPS UINT8_C(0x03)
#define BMI08X_GYRO_RANGE_125_DPS UINT8_C(0x04)
/* Gyro Output data rate and bandwidth */
#define BMI08X_GYRO_BW_532_ODR_2000_HZ UINT8_C(0x00)
#define BMI08X_GYRO_BW_230_ODR_2000_HZ UINT8_C(0x01)
#define BMI08X_GYRO_BW_116_ODR_1000_HZ UINT8_C(0x02)
#define BMI08X_GYRO_BW_47_ODR_400_HZ UINT8_C(0x03)
#define BMI08X_GYRO_BW_23_ODR_200_HZ UINT8_C(0x04)
#define BMI08X_GYRO_BW_12_ODR_100_HZ UINT8_C(0x05)
#define BMI08X_GYRO_BW_64_ODR_200_HZ UINT8_C(0x06)
#define BMI08X_GYRO_BW_32_ODR_100_HZ UINT8_C(0x07)
#define BMI08X_GYRO_ODR_RESET_VAL UINT8_C(0x80)
#define BMI08X_ACCEL_DATA_SYNC_MODE_OFF 0x00
#define BMI08X_ACCEL_DATA_SYNC_MODE_400HZ 0x01
#define BMI08X_ACCEL_DATA_SYNC_MODE_1000HZ 0x02
#define BMI08X_ACCEL_DATA_SYNC_MODE_2000HZ 0x03
/* Wait Time */
#define BMI08X_ACCEL_SOFTRESET_DELAY_MS UINT8_C(1)
#define BMI08X_GYRO_SOFTRESET_DELAY_MS UINT8_C(30)
#define BMI08X_GYRO_POWER_MODE_CONFIG_DELAY UINT8_C(30)
#define BMI08X_POWER_CONFIG_DELAY UINT8_C(50)
#define BMI08X_G (9.80f)
#define deg2rad (3.1415926 / 180.0f)
#define rad2deg (180.0f / 3.1415926)
#define BMI088_GYRO_2000_SEN 0.00106526443603169529841533860381f
typedef enum
{
ACC_CHIP_ID_REG = 0x00,
ACC_ERR_REG = 0x02,
ACC_STATUS_REG = 0x03,
ACC_X_LSB_REG = 0x12,
ACC_X_MSB_REG = 0x13,
ACC_Y_LSB_REG = 0x14,
ACC_Y_MSB_REG = 0x15,
ACC_Z_LSB_REG = 0x16,
ACC_Z_MSB_REG = 0x17,
TEMP_MSB_REG = 0x22,
TEMP_LSB_REG = 0x23,
ACC_CONF_REG = 0x40,
ACC_RANGE_REG = 0x41,
INT1_IO_CTRL_REG = 0x53,
INT2_IO_CTRL_REG = 0x54,
ACC_SELF_TEST_REG = 0x6D,
ACC_PWR_CONF_REG = 0x7C,
ACC_PWR_CTRL_REG = 0x7D,
ACC_SOFTRESET_REG = 0x7E
} bmi088a_reg_list_t;
typedef enum
{
GYRO_CHIP_ID_REG = 0x00,
RATE_X_LSB_REG = 0x02,
RATE_X_MSB_REG = 0x03,
RATE_Y_LSB_REG = 0x04,
RATE_Y_MSB_REG = 0x05,
RATE_Z_LSB_REG = 0x06,
RATE_Z_MSB_REG = 0x07,
GYRO_INT_STAT_1_REG = 0x0A,
GYRO_RANGE_REG = 0x0F,
GYRO_BANDWIDTH_REG = 0x10,
GYRO_LPM1_REG = 0x11,
GYRO_SOFTRESET_REG = 0x14,
GYRO_INT_CTRL_REG = 0x15
} bmi088g_reg_list_t;
enum bmi08x_intf {
/*! I2C interface */
BMI08X_I2C_INTF,
/*! SPI interface */
BMI08X_SPI_INTF
};
struct bmi08x_cfg
{
/*! power mode */
uint8_t power;
/*! range */
uint8_t range;
/*! bandwidth */
uint8_t bw;
/*! output data rate */
uint8_t odr;
};
/* bmi088 device structure */
struct bmi08x_dev
{
/*! Accel chip Id */
uint8_t accel_chip_id;
/*! Gyro chip Id */
uint8_t gyro_chip_id;
/*! Accel device Id in I2C mode, can be used for chip select pin in SPI mode */
rt_base_t accel_id;
/*! Gyro device Id in I2C mode, can be used for chip select pin in SPI mode */
rt_base_t gyro_id;
/*! Device of accel bus*/
rt_device_t accel_bus;
/*! Device of gyro bus*/
rt_device_t gyro_bus;
/*! 0 - I2C , 1 - SPI Interface */
enum bmi08x_intf intf;
/*! Structure to configure accel sensor */
struct bmi08x_cfg accel_cfg;
/*! Structure to configure gyro sensor */
struct bmi08x_cfg gyro_cfg;
/*! Config stream data buffer address will be assigned*/
const uint8_t *config_file_ptr;
/*! Max read/write length (maximum supported length is 32).
To be set by the user */
uint8_t read_write_len;
};
struct bmi088_3axes
{
rt_int16_t x;
rt_int16_t y;
rt_int16_t z;
};
struct bmi088_data
{
float x;
float y;
float z;
};
struct bmi08x_dev *bmi088_init(const char *acc_name, const char *gyro_name);
void bmi088_deinit(struct bmi08x_dev *dev);
rt_err_t bmi088a_set_power_mode(struct bmi08x_dev *dev);
rt_err_t bmi088g_set_power_mode(struct bmi08x_dev *dev);
rt_err_t bmi088a_set_meas_conf(struct bmi08x_dev *dev);
rt_err_t bmi088g_set_meas_conf(struct bmi08x_dev *dev);
rt_size_t bmi088_get_accel(struct bmi08x_dev *dev, struct bmi088_data *buf);
rt_size_t bmi088_get_gyro(struct bmi08x_dev *dev, struct bmi088_data *buf);
#endif // BMI088_H
11、将bmi088.c文件里的代码,用以下代码进行替换,注意这个文件里的片选引脚,要根据自己的MCU连接情况自己去改,我这里用的是PD8和PD10在前文已经提到过
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-02-28 MyGuo the first version
*/
#include "bmi088.h"
#include <rtdbg.h>
#include <rtdevice.h>
#include <board.h>
#include "drv_spi.h"
#define BMI088_SPI_MAX_SPEED (10 * 1000 * 1000) // M
//#define CSB1_Pin GET_PIN(B, 14)
//#define CSB2_Pin GET_PIN(B, 15)
//#define CSB1_Pin GET_PIN(F, 3)
//#define CSB2_Pin GET_PIN(F, 4)
#define CSB1_Pin GET_PIN(D, 8)
#define CSB2_Pin GET_PIN(D, 10)
static rt_err_t _bmi088_spi_read(struct rt_spi_device *dev, rt_uint8_t reg_addr, const rt_uint8_t len, rt_uint8_t *buf)
{
reg_addr |= 0x80;
dev->bus->owner = dev;
rt_spi_send_then_recv(dev, ®_addr, 1, buf, len);
return RT_EOK;
}
static rt_err_t _bmi088_spi_write(struct rt_spi_device *dev, rt_uint8_t reg_addr, const rt_uint8_t len, rt_uint8_t *buf)
{
reg_addr &= 0x7f;
dev->bus->owner = dev;
rt_spi_send_then_send(dev, ®_addr, 1, buf, len);
return RT_EOK;
}
static rt_err_t _bmi088_get_accel_raw(struct bmi08x_dev *dev, struct bmi088_3axes *accel)
{
rt_uint8_t buffer[10];
uint8_t lsb, msb;
rt_err_t res;
struct rt_spi_device *spi_dev = (struct rt_spi_device *)(dev->accel_bus);
res = _bmi088_spi_read(spi_dev, ACC_X_LSB_REG, 10, buffer);
if (res != RT_EOK)
{
return res;
}
lsb = buffer[1];
msb = buffer[2];
accel->x = (rt_int16_t)((msb << 8) | lsb); /* X */
lsb = buffer[3];
msb = buffer[4];
accel->y = (rt_int16_t)((msb << 8) | lsb);/* Y */
lsb = buffe