硬件环境

Robomaster 开发板C型

STLink V2

XT30电源

CubeMX配置

基本的配置请参考《RoboMaster开发板C型嵌入式软件教程文档》中0.4.2和13.4.1。

Development-Board-C-Examples/RoboMaster开发板C型嵌入式软件教程文档.pdf at master · RoboMaster/Development-Board-C-Examples · GitHubicon-default.png?t=N7T8https://github.com/RoboMaster/Development-Board-C-Examples/blob/master/RoboMaster%E5%BC%80%E5%8F%91%E6%9D%BFC%E5%9E%8B%E5%B5%8C%E5%85%A5%E5%BC%8F%E8%BD%AF%E4%BB%B6%E6%95%99%E7%A8%8B%E6%96%87%E6%A1%A3.pdf需要注意的是,配置完成后,SPI_MOSI是这样的,而且没有配置CS1_Accel和CS1_Gyro,

 开发板原理图中SPI_MOSI对应PA7,CS1_ Accel对应PA4,CS1_Gyro对应PB0,

 所以要在Pinout view中修改到正确的位置。

另外,PA4和PB0的GPIO output level要设置为High,意思是设置默认输出电平为高电平。至于为什么,举例来说,PA4对应CS1_Accel,PA4的默认电平为高电平,当需要片选加速度计的时候,将PA4设置为低电平,然后进行一系列的读取操作,读取完成之后,再将PA4设置为高电平来取消片选。可以看到,默认状态下不片选时PA4和PB0是要保持高电平状态的,所以我们才把GPIO output level设置为High。

KEIL配置

这里最好改为Level 0,否则在debug的时候watch到的accelerometer会提示not in scope。

加速度计程序代码

接下来的教程会用到BOSCH官方给的文档《BMI088 6-axis Motion Tracking for High-performance Applications》,文档版本1.8,下载地址如下。

https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi088-ds001.pdficon-default.png?t=N7T8https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi088-ds001.pdf

上图说的是,加速度计三轴x、y、z的加速度值各自分成高八位和低八位,x轴低八位存储在0x12,x轴高八位在0x13,y轴低八位在0x14,y轴高八位在0x15,z轴低八位在0x16,z后高八位在0x17。我们之后的任务就是读取0x12到0x17这六个寄存器的值,然后各自的低八位和高八位拼接。

上图说的是,PA4置0,图中的CSB变低,SPI开始工作。PA4置1,图中的CSB变高,SPI停止工作。

下图说的是,PA4置0,SPI开始工作。master给slave发送8个比特:Bit #0和Bit #1-7,Bit #0决定是写还是读,Bit #1-7表示slave的某个寄存器的地址,比如0x12。如果Bit #0是0,写,master给slave发送8个比特:Bit #8-15,这个值会被写入0x12寄存器里,PA4置1,SPI停止工作,操作完成。如果Bit #0是1,读,master从slave接收8个比特:Bit #8-15,这个值是0x12寄存器里的值,加速度计比较特殊,它的Bit #8-15是无效值,所以需要master从slave再接收8个比特:Bit #16-23,这个值才是0x12寄存器里的值,PA4置1,SPI停止工作,操作完成。PA4也可以不置1,master从slave再接收8个比特: Bit #24-31,这个值是0x13寄存器里的值。

上图说的是,向寄存器0x7E 写入值0xB6,加速度计的各个寄存器的值会恢复为默认值,这个叫做软件复位,需要1ms来完成。复位除了软件复位,还有硬件复位比如上电。每次复位后都要向寄存器0x7D写入值0x04,以便获取加速度计的值,。

下图解释了为什么。因为上电之后,陀螺仪会进入正常模式。而加速度计会进入暂停模式,暂停模式里加速度计的整个模拟部分关断,不执行数据采集,寄存器的值不更新,但仍然可以读取。向寄存器ACC_PWR_CTRL(即寄存器0x7D)写入值0x04,使加速度计进入正常模式,需要450us,即0.45ms,HAL_Delay()函数最小只能延时1ms,所以我们程序里这里按1ms来延时,影响不大。

下图说的是,不仅是软件复位,加速度计的硬件复位(上电) 之后也需要1ms时间。

前边说的啰里啰唆,其实代码思路还是很简单的,就大致三步。软件复位,从暂停模式进入正常模式,读寄存器的值并拼接。陀螺仪的代码更简单只有两步。软件复位,读寄存器的值并拼接

#define BMI088_ACCEL_3G_SEN 0.0008974358974f    //这个数字我也不知道哪来的
float BMI088_ACCEL_SEN = BMI088_ACCEL_3G_SEN;
float accelerometer[3];
uint8_t i = 0;
uint8_t buf[6]={0,0,0,0,0,0};
uint8_t pTxData;
uint8_t pRxData;

int main(void)
{
    //这9行代码,向地址0x7E处写入0xB6值,加速度计软件复位,使加速度计各个寄存器恢复为默认值
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);    //PA4置0,片选加速度计
    pTxData = (0x7E & 0x7F);    //Bit #0和Bit #1-7,Bit #0是0,表示写
    HAL_SPI_Transmit(&hspi1, &pTxData, 1, 1000);
    while(HAL_SPI_GetState(&hspi1)==HAL_SPI_STATE_BUSY_TX);    //等待SPI发送完成
    pTxData = 0xB6;    //Bit #8-15
    HAL_SPI_Transmit(&hspi1, &pTxData, 1, 1000);
    while(HAL_SPI_GetState(&hspi1)==HAL_SPI_STATE_BUSY_TX);    //等待SPI发送完成
    HAL_Delay(1);    //延时1ms
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);    //PA4置1,取消片选加速度计

    //加速度计复位后默认是暂停模式,这9行代码,向地址0x7D处写入0x04值,使加速度计进入正常模式
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);    //PA4置0,片选加速度计
    pTxData = (0x7D & 0x7F);    //Bit #0和Bit #1-7,Bit #0是0,表示写
    HAL_SPI_Transmit(&hspi1, &pTxData, 1, 1000);
    while(HAL_SPI_GetState(&hspi1)==HAL_SPI_STATE_BUSY_TX);    //等待SPI发送完成
    pTxData = 0x04;    //Bit #8-15
    HAL_SPI_Transmit(&hspi1, &pTxData, 1, 1000);
    while(HAL_SPI_GetState(&hspi1)==HAL_SPI_STATE_BUSY_TX);    //等待SPI发送完成
    HAL_Delay(1);    //延时1ms
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);    //PA4置1,取消片选加速度计

    while (1)
    {
    	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);    //PA4置0,片选加速度计
    	pTxData = (0x12 | 0x80);    //Bit #0和Bit #1-7,Bit #0是1,表示读
    	HAL_SPI_Transmit(&hspi1, &pTxData, 1, 1000);
    	while(HAL_SPI_GetState(&hspi1)==HAL_SPI_STATE_BUSY_TX);    //等待SPI发送完成
    	HAL_SPI_Receive(&hspi1, &pRxData, 1, 1000);    //Bit #8-15,无效值
    	while(HAL_SPI_GetState(&hspi1)==HAL_SPI_STATE_BUSY_RX);    //等待SPI接收完成
    	i = 0;
    	while (i < 6)
    	{
    	    HAL_SPI_Receive(&hspi1, &pRxData, 1, 1000);    //Bit #16-23,寄存器0x12的值,然后是寄存器0x13、0x14、0x15、0x16、0x17的值
    		while(HAL_SPI_GetState(&hspi1)==HAL_SPI_STATE_BUSY_RX);    //等待SPI接收完成
    		buf[i] = pRxData;
            i++;
    	}
    	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);    //PA4置1,取消片选加速度计
    	accelerometer[0] = ((int16_t)((buf[1]) << 8) | buf[0]) * BMI088_ACCEL_SEN;
    	accelerometer[1] = ((int16_t)((buf[3]) << 8) | buf[2]) * BMI088_ACCEL_SEN;
    	accelerometer[2] = ((int16_t)((buf[5]) << 8) | buf[4]) * BMI088_ACCEL_SEN;
    }
}

陀螺仪程序代码

陀螺仪和加速度计的区别主要在于,1.储存传感数据的寄存器位置不同,2.加速度计的Bit #8-15是无效值,而陀螺仪的Bit #8-15直接就是正确的值,3.软件复位寄存器不同,4.加速度计复位后默认进入暂停模式,需要向寄存器0x7D写入值0x04才能进入正常模式,而陀螺仪复位后直接就是正常模式,5.加速度计复位后只需要1ms,而陀螺仪复位后需要30ms

 上图说的是,陀螺仪三轴x、y、z的角加速度值各自分成高八位和低八位,x轴低八位存储在0x02,x轴高八位在0x03,y轴低八位在0x04,y轴高八位在0x05,z轴低八位在0x06,z后高八位在0x07。陀螺仪的0x00寄存器储存的是陀螺仪的ID 0x0F,代码里会用它来判断我们从SPI里读取到的到底是不是陀螺仪的值,不知道为什么要这样做,但是大疆C板官方教程里就是有这一步,所以我也给写上了。

 上图可以看到,与加速度计不同的是,陀螺仪的Bit #8-15就是我们需要的值,而不是无效值。

 上图可以看到,陀螺仪的软件复位寄存器是0x14寄存器,而且软件复位后需要30ms。

#define BMI088_GYRO_2000_SEN 0.00106526443603169529841533860381f    //这个数字我也不知道哪来的
float BMI088_GYRO_SEN = BMI088_GYRO_2000_SEN;
float gyro[3];
uint8_t i = 0;
uint8_t buf[8]={0,0,0,0,0,0};
uint8_t pTxData;
uint8_t pRxData;

int main(void)
{
    //这9行代码,向地址0x14处写入0xB6值,陀螺仪软件复位,使陀螺仪各个寄存器恢复为默认值
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);    //PB0置0,片选陀螺仪
    pTxData = (0x14 & 0x7F);    //Bit #0和Bit #1-7,Bit #0是0,表示写
    HAL_SPI_Transmit(&hspi1, &pTxData, 1, 1000);
    while(HAL_SPI_GetState(&hspi1)==HAL_SPI_STATE_BUSY_TX);    //等待SPI发送完成
    pTxData = 0xB6;    //Bit #8-15
    HAL_SPI_Transmit(&hspi1, &pTxData, 1, 1000);
    while(HAL_SPI_GetState(&hspi1)==HAL_SPI_STATE_BUSY_TX);    //等待SPI发送完成
    HAL_Delay(30);    //延时30ms
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);    //PB0置1,取消片选陀螺仪

    while (1)
    {
    	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);    //PB0置0,片选陀螺仪
    	pTxData = (0x00 | 0x80);    //Bit #0和Bit #1-7,Bit #0是1,表示读
    	HAL_SPI_Transmit(&hspi1, &pTxData, 1, 1000);
    	while(HAL_SPI_GetState(&hspi1)==HAL_SPI_STATE_BUSY_TX);    //等待SPI发送完成
    	i = 0;
    	while (i < 8)
    	{
    		HAL_SPI_Receive(&hspi1, &pRxData, 1, 1000);    //Bit #8-15,寄存器0x00的值,然后是寄存器0x01、0x02、0x03、0x04、0x05、0x06、0x07的值
    		while(HAL_SPI_GetState(&hspi1)==HAL_SPI_STATE_BUSY_RX);    //等待SPI接收完成
    		buf[i] = pRxData;
    		i++;
    	}
    	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);    //PB0置1,取消片选陀螺仪
    	if(buf[0] == 0x0F)	//buf[0]储存GYRO_CHIP_ID,应该为0x0F,判断我们读取到的是不是陀螺仪的值。
    	{
    		gyro[0] = ((int16_t)((buf[3]) << 8) | buf[2]) * BMI088_GYRO_SEN;
    		gyro[1] = ((int16_t)((buf[5]) << 8) | buf[4]) * BMI088_GYRO_SEN;
    		gyro[2] = ((int16_t)((buf[7]) << 8) | buf[6]) * BMI088_GYRO_SEN;
    	}
    }
}

效果演示

下一篇文章

我们刚才的操作是读取传感器的数据,下一篇文章将会把读取到的加速度计和陀螺仪的数据进行计算,得到欧拉角,也就是所谓的姿态解算。

实物教程——BMI088传感器姿态解算_操气的小虫儿的博客-CSDN博客_bmi088

参考:

[1] 《RoboMaster开发板C型嵌入式软件教程文档》

[2] 《BMI088 6-axis Motion Tracking for High-performance Applications》

ChatGPT4

用ChatGPT4理解上述代码: 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐