大疆C板读取BMI088传感器数据
硬件环境
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 · GitHubhttps://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,下载地址如下。
上图说的是,加速度计三轴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理解上述代码:
更多推荐
所有评论(0)