本文将介绍如何使用 LSM6DSOW 传感器来读取数据。主要步骤包括初始化传感器接口、验证设备ID、配置传感器的数据输出率和滤波器,以及通过轮询方式持续读取加速度、角速率和温度数据。读取到的数据会被转换为适当的单位并通过串行通信输出。这个代码是一个很好的起点,用于了解如何操作 LSM6DSOW 传感器并获取其数据。
最近在弄ST和瑞萨RA的课程,需要样片的可以加群申请:615061293 。
[https://www.bilibili.com/video/BV1eS421X7J6/]
[https://www.wjx.top/vm/OhcKxJk.aspx#]
[https://download.csdn.net/download/qq_24312945/89590384]
首先需要准备一个开发板,这里我准备的是自己绘制的开发板,需要的可以进行申请。
主控为STM32H503CB,陀螺仪为LSM6DSOW,磁力计为LIS2MDL。
LSM6DSOW 和 LSM6DSO 是两款惯性测量单元(IMU),都具备三轴数字加速度计和三轴数字陀螺仪功能。它们之间的主要区别如下:
对于LSM6DSOW,可以使用SPI或者IIC进行通讯。 最小系统图如下所示。
在CS管脚为1的时候,为IIC模式。
本文使用的板子原理图如下所示。
在在使用IIC通讯模式的时候,SA0是用来控制IIC的地址位的。
对于IIC的地址,可以通过SDO/SA0引脚修改。SDO/SA0引脚可以用来修改设备地址的最低有效位。如果SDO/SA0引脚连接到电源电压,LSb(最低有效位)为'1'(地址1101011b);否则,如果SDO/SA0引脚连接到地线,LSb的值为'0'(地址1101010b)。
接口如下所示。 主要使用的管脚为CS、SCL、SDA、SA0。
该模块支持的速度为普通模式(100k)和快速模式(400k)。
用STM32CUBEMX生成例程,这里使用MCU为STM32H503CB。 配置时钟树,配置时钟为250M。
查看原理图,PA9和PA10设置为开发板的串口。
配置串口,速率为2000000。
LSM6DSOW最大IIC通讯速率为400k,配置IIC速度为400k
由于还有一个磁力计,需要把该CS也使能。
打开魔术棒,勾选MicroLIB
在main.c中,添加头文件,若不添加会出现 identifier "FILE" is undefined报错。
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
函数声明和串口重定向:
/* USER CODE BEGIN PFP */
int fputc(int ch, FILE *f){
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END PFP */
[https://github.com/STMicroelectronics/lsm6dso-pid]
由于需要向LSM6DSO_I2C_ADD_L写入以及为IIC模式。
所以使能CS为高电平,配置为IIC模式。 配置SA0为低电平。
printf("HELLO!n");
HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SA0_GPIO_Port, SA0_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(CS2_GPIO_Port, CS2_Pin, GPIO_PIN_SET);
HAL_Delay(100);
stmdev_ctx_t dev_ctx;
/* Initialize mems driver interface */
dev_ctx.write_reg = platform_write;
dev_ctx.read_reg = platform_read;
dev_ctx.mdelay = platform_delay;
dev_ctx.handle = &SENSOR_BUS;
/* Init test platform */
// platform_init();
/* Wait sensor boot time */
platform_delay(BOOT_TIME);
可以向WHO_AM_I (0Fh)获取固定值,判断是否为0x6C
lsm6dso_device_id_get为获取函数。
对应的获取ID驱动程序,如下所示。
/* Check device ID */
lsm6dso_device_id_get(&dev_ctx, &whoamI);
printf("LSM6DSO_ID=0x%x,whoamI=0x%x",LSM6DSO_ID,whoamI);
if (whoamI != LSM6DSO_ID)
while (1);
可以向CTRL3 (12h)的SW_RESET寄存器写入1进行复位。
lsm6dso_reset_set为重置函数。
对应的驱动程序,如下所示。
/* Restore default configuration */
lsm6dso_reset_set(&dev_ctx, PROPERTY_ENABLE);
do {
lsm6dso_reset_get(&dev_ctx, &rst);
} while (rst);
/* Disable I3C interface */
lsm6dso_i3c_disable_set(&dev_ctx, LSM6DSO_I3C_DISABLE);
在很多传感器中,数据通常被存储在输出寄存器中,这些寄存器分为两部分:MSB和LSB。这两部分共同表示一个完整的数据值。例如,在一个加速度计中,MSB和LSB可能共同表示一个加速度的测量值。
连续更新模式(BDU = ‘0’):在默认模式下,输出寄存器的值会持续不断地被更新。这意味着在你读取MSB和LSB的时候,寄存器中的数据可能会因为新的测量数据而更新。这可能导致一个问题:当你读取MSB时,如果寄存器更新了,接下来读取的LSB可能就是新的测量值的一部分,而不是与MSB相对应的值。这样,你得到的就是一个“拼凑”的数据,它可能无法准确代表任何实际的测量时刻。
块数据更新(BDU)模式(BDU = ‘1’):当激活BDU功能时,输出寄存器中的内容不会在读取MSB和LSB之间更新。这就意味着一旦开始读取数据(无论是先读MSB还是LSB),寄存器中的那一组数据就被“锁定”,直到两部分都被读取完毕。这样可以确保你读取的MSB和LSB是同一测量时刻的数据,避免了读取到代表不同采样时刻的数据。
简而言之,BDU位的作用是确保在读取数据时,输出寄存器的内容保持稳定,从而避免读取到拼凑或错误的数据。这对于需要高精度和稳定性的应用尤为重要。
可以向CTRL3 (12h)的BDU寄存器写入1进行开启。
对应的驱动程序,如下所示。
/* Enable Block Data Update */
lsm6dso_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);
速率可以通过CTRL1 (10h)设置加速度速率和CTRL2 (11h)进行设置角速度速率。
设置加速度量程可以通过CTRL1 (10h)进行设置。
设置角速度量程可以通过CTRL2 (11h)进行设置。
设置加速度和角速度的量程和速率可以使用如下函数。
/* Set Output Data Rate */
lsm6dso_xl_data_rate_set(&dev_ctx, LSM6DSO_XL_ODR_12Hz5);
lsm6dso_gy_data_rate_set(&dev_ctx, LSM6DSO_GY_ODR_12Hz5);
/* Set full scale */
lsm6dso_xl_full_scale_set(&dev_ctx, LSM6DSO_2g);
lsm6dso_gy_full_scale_set(&dev_ctx, LSM6DSO_2000dps);
/* Configure filtering chain(No aux interface)
* Accelerometer - LPF1 + LPF2 path
*/
lsm6dso_xl_hp_path_on_out_set(&dev_ctx, LSM6DSO_LP_ODR_DIV_100);
lsm6dso_xl_filter_lp2_set(&dev_ctx, PROPERTY_ENABLE);
进入一个无限循环,不断检查是否有新的数据(加速度、角速率、温度)可用。
对于每种类型的数据(加速度、角速率、温度),如果有新数据,就读取原始数据,转换为对应的单位(毫克、毫度每秒、摄氏度),并通过串行输出打印。
对于数据是否准备好,可以访问STATUS_REG (1Eh)进行判断。
/* Read output only if new xl value is available */
lsm6dso_xl_flag_data_ready_get(&dev_ctx, ®);
对于加速度数据,可以通过28-2D进行获取。
加速度数据首先以原始格式(通常是整数)读取,然后需要转换为更有意义的单位,如毫重力(mg)。这里的转换函数 lsm6dso_from_fs2_to_mg() 根据加速度计的量程(这里假设为±2g)将原始数据转换为毫重力单位。
acceleration_mg[0] = lsm6dso_from_fs2_to_mg(data_raw_acceleration[0]);等三行代码分别转换 X、Y、Z 轴的加速度数据。
/* Read output only if new xl value is available */
lsm6dso_xl_flag_data_ready_get(&dev_ctx, ®);
if (reg) {
/* Read acceleration field data */
memset(data_raw_acceleration, 0x00, 3 * sizeof(int16_t));
lsm6dso_acceleration_raw_get(&dev_ctx, data_raw_acceleration);
acceleration_mg[0] =
lsm6dso_from_fs2_to_mg(data_raw_acceleration[0]);
acceleration_mg[1] =
lsm6dso_from_fs2_to_mg(data_raw_acceleration[1]);
acceleration_mg[2] =
lsm6dso_from_fs2_to_mg(data_raw_acceleration[2]);
printf( "Acceleration [mg]:%4.2ft%4.2ft%4.2frn",
acceleration_mg[0], acceleration_mg[1], acceleration_mg[2]);
}
对于角速度数据,可以通过22-27进行获取。
lsm6dso_gy_flag_data_ready_get(&dev_ctx, ®);
if (reg) {
/* Read angular rate field data */
memset(data_raw_angular_rate, 0x00, 3 * sizeof(int16_t));
lsm6dso_angular_rate_raw_get(&dev_ctx, data_raw_angular_rate);
angular_rate_mdps[0] =
lsm6dso_from_fs2000_to_mdps(data_raw_angular_rate[0]);
angular_rate_mdps[1] =
lsm6dso_from_fs2000_to_mdps(data_raw_angular_rate[1]);
angular_rate_mdps[2] =
lsm6dso_from_fs2000_to_mdps(data_raw_angular_rate[2]);
printf("Angular rate [mdps]:%4.2ft%4.2ft%4.2frn",
angular_rate_mdps[0], angular_rate_mdps[1], angular_rate_mdps[2]);
}
对于温度数据,可以通过20-21进行获取。
lsm6dso_temp_flag_data_ready_get(&dev_ctx, ®);
if (reg) {
/* Read temperature data */
memset(&data_raw_temperature, 0x00, sizeof(int16_t));
lsm6dso_temperature_raw_get(&dev_ctx, &data_raw_temperature);
temperature_degC =
lsm6dso_from_lsb_to_celsius(data_raw_temperature);
printf("Temperature [degC]:%6.2frn", temperature_degC);
}
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
uint8_t reg;
/* Read output only if new xl value is available */
lsm6dso_xl_flag_data_ready_get(&dev_ctx, ®);
if (reg) {
/* Read acceleration field data */
memset(data_raw_acceleration, 0x00, 3 * sizeof(int16_t));
lsm6dso_acceleration_raw_get(&dev_ctx, data_raw_acceleration);
acceleration_mg[0] =
lsm6dso_from_fs2_to_mg(data_raw_acceleration[0]);
acceleration_mg[1] =
lsm6dso_from_fs2_to_mg(data_raw_acceleration[1]);
acceleration_mg[2] =
lsm6dso_from_fs2_to_mg(data_raw_acceleration[2]);
printf( "Acceleration [mg]:%4.2ft%4.2ft%4.2frn",
acceleration_mg[0], acceleration_mg[1], acceleration_mg[2]);
}
lsm6dso_gy_flag_data_ready_get(&dev_ctx, ®);
if (reg) {
/* Read angular rate field data */
memset(data_raw_angular_rate, 0x00, 3 * sizeof(int16_t));
lsm6dso_angular_rate_raw_get(&dev_ctx, data_raw_angular_rate);
angular_rate_mdps[0] =
lsm6dso_from_fs2000_to_mdps(data_raw_angular_rate[0]);
angular_rate_mdps[1] =
lsm6dso_from_fs2000_to_mdps(data_raw_angular_rate[1]);
angular_rate_mdps[2] =
lsm6dso_from_fs2000_to_mdps(data_raw_angular_rate[2]);
printf("Angular rate [mdps]:%4.2ft%4.2ft%4.2frn",
angular_rate_mdps[0], angular_rate_mdps[1], angular_rate_mdps[2]);
}
lsm6dso_temp_flag_data_ready_get(&dev_ctx, ®);
if (reg) {
/* Read temperature data */
memset(&data_raw_temperature, 0x00, sizeof(int16_t));
lsm6dso_temperature_raw_get(&dev_ctx, &data_raw_temperature);
temperature_degC =
lsm6dso_from_lsb_to_celsius(data_raw_temperature);
printf("Temperature [degC]:%6.2frn", temperature_degC);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
审核编辑 黄宇
全部0条评论
快来发表一下你的评论吧 !