九轴运动传感器–BMX160,硬件开发与程序设计
前言
??和之前OPT3001传感器一块板子上的九轴传感器的代码我写完啦,和大家分享一下
硬件部分介绍
BMX160介绍
??BMX160是博世的九轴运动传感器,集成了加速度、陀螺仪、磁力计三种传感器,其中加速度传感器基于BMI160,磁力计基于BMM150,可以说是BMX160是由BMI160、BMM150组成的。但性能参数在一些地方有差距。但在程序设计过程中,可以感觉到加速度陀螺仪和磁力计两部分的寄存器之间是有割裂的。磁力计的部分需要做特殊的间接读写。 ??BMX160支持SPI和IIC通讯,支持FIFO、多种运动中断等高级玩法。
应用
??我想集成运动传感器的最初始的想法只是想要知道目前姿态,来设置屏幕的水平和垂直,但为了学习和日后的高级玩法,我还是喜欢功能、性能多一些的传感器。
电路部分
参考官方的的电路,电路部分很简单。
程序设计
程序架构介绍
程序一共有7个文件,所以我没有直接集成在ST的库中,而是直接单列了个文件夹。 ??BMX160_use.c:主要存放功能函数,一般外部文件只需要调用该文件中的函数,也是架构最外层的部分 ??BMX160_Control.c:主要存放底层函数和设备配置策略函数,比如SPI、IIC的读写,BMX160初始化过程中的配置参数、IIC地址、中断引脚等,一般移植需要修改这部分参数。 ??BMX160_Algorithm.c:主要存放一些计算类的函数,方便use文件直接调用。目前因为没有涉及太多的姿态运算,所以该文件目前只有些二进制位运算函数。 ??BMX160_Register.h:主要存放BMX160的寄存器位置。处于架构的最内层
移植部分
移植只需要BMX160_Control.c文件中的这部分。
Sensor_BMX160 BMX160_1;
int BMX160_Pretreatment(void)
{
BMX160_1.COM_Mode = BMX160_COM_Mode;
#if BMX160_COM_Mode == BMX160_IIC
BMX160_1.IIC_Aisle = hi2c1;
BMX160_1.IIC_ADDR = 0x69;
#else
BMX160_1.SPI_Aisle;
#endif
BMX160_1.ACC_CONF_RANGE.ACC_RANGE = BMX160_ACC_RANGE_2g;
BMX160_1.GYR_CONF_RANGE.GYR_RANGE = BMX160_GYR_RANGE_125;
BMX160_1.MAG_CONF_RANGE.MAG_XY_Mode = BMX160_MAG_Mode_HighPrecision;
BMX160_1.MAG_CONF_RANGE.MAG_Z_Mode = BMX160_MAG_Mode_HighPrecision;
BMX160_1.MAG_CONF_RANGE.MAG_odr = BMX160_MAG_RANGE_12_5;
BMX160_1.ACC_GYR_FOC_off.FOC_GYR_EN = BMX160_FOC_GYR_ON;
BMX160_1.ACC_GYR_FOC_off.FOC_ACC_X = BMX160_FOC_ACC_Recoup_0g;
BMX160_1.ACC_GYR_FOC_off.FOC_ACC_Y = BMX160_FOC_ACC_Recoup_0g;
BMX160_1.ACC_GYR_FOC_off.FOC_ACC_Z = BMX160_FOC_ACC_Recoup_P_1g;
BMX160_1.ACC_GYR_FOC_off.Off_ACC_EN = BMX160_off_ACC_ON;
BMX160_1.ACC_GYR_FOC_off.Off_GYR_EN = BMX160_off_GYR_ON;
return BMX160_OK;
}
??默认是使用IIC通讯,SPI通讯的接口我做了兼容,但底层函数需要自己写一下。然后修改BMX160_Control.h这行代码
#define BMX160_COM_Mode BMX160_IIC
修改为:
#define BMX160_COM_Mode BMX160_SPI
??其中如果没有其他特殊需求,四个配置策略不用修改,只需要修改接口部分的参数就可以了。 ??在BMX160_use.c中的初始化函数中,我做了一个例程,循环输出三种传感器的数值
int BMX160_Init(void)
{
if (BMX160_Pretreatment() != BMX160_OK)
{
return BMX160_Error;
}
uint8_t DATA = {0};
BMX160_Get_ChipID(&BMX160_1, &DATA);
printf("%X\n", DATA);
BMX160_CMD(&BMX160_1, BMX106_CMD_Softreset);
HAL_Delay(100);
BMX160_CMD(&BMX160_1, BMX106_CMD_PMU_ACC_Normal);
HAL_Delay(10);
BMX160_CMD(&BMX160_1, BMX106_CMD_PMU_GYR_Normal);
HAL_Delay(80);
BMX160_CMD(&BMX160_1, BMX106_CMD_PMU_MAG_Normal);
HAL_Delay(10);
int Mode[3];
BMX160_Get_PMU_STATUS(&BMX160_1, &Mode[0], &Mode[1], &Mode[2], Report_Y);
float DATA1 = 0;
BMX160_Get_Temperature(&BMX160_1, &DATA1);
printf("%f\n", DATA1);
BMX160_ACC_Sampling_Mode(&BMX160_1, BMX160_ACC_Normal_Oversampling, BMX160_ACC_ODR_100);
BMX160_ACC_RANGE(&BMX160_1, BMX160_1.ACC_CONF_RANGE.ACC_RANGE);
BMX160_GYR_Sampling_Mode(&BMX160_1, BMX160_GYR_Normal_Oversampling, BMX160_GYR_ODR_100);
BMX160_GYR_RANGE(&BMX160_1, BMX160_1.GYR_CONF_RANGE.GYR_RANGE);
BMX160_MAG_Sampling_Mode(&BMX160_1, BMX160_1.MAG_CONF_RANGE.MAG_XY_Mode, BMX160_1.MAG_CONF_RANGE.MAG_Z_Mode, BMX160_1.MAG_CONF_RANGE.MAG_odr);
BMX160_Auto_Calibration(&BMX160_1);
float ACC_DATA[3] = {0};
float GYR_DATA[3] = {0};
float MAG_DATA[3] = {0};
while (1)
{
BMX160_Get_ACC(&BMX160_1, &ACC_DATA[0], &ACC_DATA[1], &ACC_DATA[2]);
BMX160_Get_GYR(&BMX160_1, &GYR_DATA[0], &GYR_DATA[1], &GYR_DATA[2]);
BMX160_Get_MAG(&BMX160_1, &MAG_DATA[0], &MAG_DATA[1], &MAG_DATA[2]);
printf("加速度:");
printf("X:%.2f", ACC_DATA[0]);
printf(",");
printf("Y:%.2f", ACC_DATA[1]);
printf(",");
printf("Z:%.2f", ACC_DATA[2]);
printf("\r\n");
printf("陀螺仪:");
printf("X:%.2f", GYR_DATA[0]);
printf(",");
printf("Y:%.2f", GYR_DATA[1]);
printf(",");
printf("Z:%.2f", GYR_DATA[2]);
printf("\r\n");
printf("磁力计:");
printf("X:%.2f", MAG_DATA[0]);
printf(",");
printf("Y:%.2f", MAG_DATA[1]);
printf(",");
printf("Z:%.2f", MAG_DATA[2]);
printf("\r\n\r\n\r\n");
HAL_Delay(500);
}
}
在校准程序之后的代码都可以根据自己需要进行修改,但不建议删除输出数据上面的一些配置代码。配置策略的配置参数在BMX160_Control.h中存放,可以直接赋值过来修改。
API介绍
当初始化完成之后,最主要的就是三个传感器+温度的数据获取了。
int BMX160_Get_MAG(Sensor_BMX160 *BMX160, float *DATA_X, float *DATA_Y, float *DATA_Z)
int BMX160_Get_ACC(Sensor_BMX160 *BMX160, float *DATA_X, float *DATA_Y, float *DATA_Z)
int BMX160_Get_GYR(Sensor_BMX160 *BMX160, float *DATA_X, float *DATA_Y, float *DATA_Z)
int BMX160_Get_Temperature(Sensor_BMX160 *BMX160, float *DATA)
BMX160比较有意思的是,有一个寄存器比较特殊,CMD命令寄存器,重置、调整三传感器的功率模式等都需要通过该寄存器实现。
int BMX160_CMD(Sensor_BMX160 *BMX160, uint8_t CMD)
CMD命令可以为(在BMX_use.h文件中复制):
#define BMX160_CMD_PMU_ACC_Suspend 0x10
#define BMX160_CMD_PMU_ACC_Normal 0x11
#define BMX160_CMD_PMU_ACC_LowPower 0x12
#define BMX160_CMD_PMU_GYR_Suspend 0x14
#define BMX160_CMD_PMU_GYR_Normal 0x15
#define BMX160_CMD_PMU_GYR_FastStartUp 0x17
#define BMX160_CMD_PMU_MAG_Suspend 0x18
#define BMX160_CMD_PMU_MAG_Normal 0x19
#define BMX160_CMD_PMU_MAG_LowPower 0x1a
#define BMX160_CMD_StartFoc 0x03
#define BMX160_CMD_ProgNvm 0xa0
#define BMX160_CMD_FifoFlush 0xb0
#define BMX160_CMD_IntReset 0xb1
#define BMX160_CMD_Softreset 0xb6
#define BMX160_CMD_StepCntClr 0xb2
中断部分
BMX160的中断部分比较复杂,我目前还不打算写,一是目前没有这个需求,因为只是在面包板阶段,等到了集成到总电路板的时候,我也会写。二是需要运动测试,面包板太大不太方便测试,到做成手持设备时候在测试就好多了。可以期待一下吧,当然,我如果写中断部分也是全部写完了,不会需要那部分写哪部分了。
开源地址
和OPT3001是一个库,后续的两个传感器我也会抓紧开发。 可以去白嫖了~下载的时候求求点一下星星,抱拳了! github :https://github.com/lijinlong21549/Sensor-collection 关于硬件有什么问题欢迎私信。
|