STM32 SPI驱动读取LSM6DSRTR

提示:通过SPI驱动读取传感器数据


前言

制作一个倾角传感器,通过SPI读取LSM6DSRTR的加速度数据转换为角度,不用IIC的原因是考虑IIC通讯的协议过于繁琐,且会影响后续的发包速率。


一、LSM6DSRTR

六轴传感器,最好用ST的芯片来读取,主要是ST在这块已经提供好驱动了,其它也行,都一样简单。其次就是,你需要配置好SPI,这个很重要,不然很容易读不出来。

二、配置步骤

1.配置SPI

注意:通过STM32CUBEMX 来构建代码

static void MX_SPI1_Init(void)
{
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */
}

2.引入 LSM驱动库

在这里插入图片描述
案例代码

#include <string.h>
#include <stdio.h>
#include "lsm6dsr_reg.h"
#include "stm32l0xx_hal.h"
#include "main.h"

#define CS_Pin GPIO_PIN_4
#define CS_GPIO_Port GPIOA
#define LED_Pin GPIO_PIN_12
#define LED_GPIO_Port GPIOA
#define BOOT_TIME 10 // ms
#define PI 3.1415926
extern SPI_HandleTypeDef hspi1;

extern UART_HandleTypeDef huart1;
static stmdev_ctx_t dev_ctx;

/* Private variables ---------------------------------------------------------*/
static int16_t data_raw_acceleration[3];
static int16_t data_raw_angular_rate[3];
static int16_t data_raw_temperature;
static float acceleration_mg[3];
static float angular_rate_mdps[3];
static uint8_t whoamI, rst;
static uint8_t tx_buffer[1000];

static int32_t platform_write(void *handle, uint8_t reg, const uint8_t *bufp,
                              uint16_t len);
static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp,
                             uint16_t len);
static void tx_com(uint8_t *tx_buffer, uint16_t len);
static void platform_delay(uint32_t ms);

/* Main Example --------------------------------------------------------------*/
//在主函数里面调用这个接口就行
void lsm6dsr_read_angle_data_polling(void)
{

    uint8_t reg;
    /* Read output only if new xl value is available */
    lsm6dsr_xl_flag_data_ready_get(&dev_ctx, &reg);

    if (reg)
    {
        /* Read acceleration field data */
        memset(data_raw_acceleration, 0x00, 3 * sizeof(int16_t));
        lsm6dsr_acceleration_raw_get(&dev_ctx, data_raw_acceleration);
        acceleration_mg[0] =
            lsm6dsr_from_fs2g_to_mg(data_raw_acceleration[0]);
        acceleration_mg[1] =
            lsm6dsr_from_fs2g_to_mg(data_raw_acceleration[1]);
        acceleration_mg[2] =
            lsm6dsr_from_fs2g_to_mg(data_raw_acceleration[2]);

        /* 注意:atan算出来的是弧度值, 然后1弧度 = 180/Π */
        float angle_x = atan(acceleration_mg[0] / sqrt(acceleration_mg[2] * acceleration_mg[2] + acceleration_mg[1] * acceleration_mg[1])) * 180 / PI;
        float angle_y = atan(acceleration_mg[1] / sqrt(acceleration_mg[0] * acceleration_mg[0] + acceleration_mg[2] * acceleration_mg[2])) * 180 / PI;
        float angle_z = atan(acceleration_mg[2] / sqrt(acceleration_mg[0] * acceleration_mg[0] + acceleration_mg[1] * acceleration_mg[1])) * 180 / PI;

        sprintf((char *)tx_buffer,
                "Acceleration [mg]:%4.2f\t%4.2f\t%4.2f\r\n",
                acceleration_mg[0], acceleration_mg[1], acceleration_mg[2]);
        //这边是计算出来的角度值
        sprintf((char *)tx_buffer,
                "Angle :x %4.2f\t y %4.2f\t z %4.2f\r\n",
                angle_x, angle_y, angle_z);
        tx_com(tx_buffer, strlen((char const *)tx_buffer));
    }

    // lsm6dsr_gy_flag_data_ready_get(&dev_ctx, &reg);

    // if (reg)
    // {
    //     /* Read angular rate field data */
    //     memset(data_raw_angular_rate, 0x00, 3 * sizeof(int16_t));
    //     lsm6dsr_angular_rate_raw_get(&dev_ctx, data_raw_angular_rate);
    //     angular_rate_mdps[0] =
    //         lsm6dsr_from_fs2000dps_to_mdps(data_raw_angular_rate[0]);
    //     angular_rate_mdps[1] =
    //         lsm6dsr_from_fs2000dps_to_mdps(data_raw_angular_rate[1]);
    //     angular_rate_mdps[2] =
    //         lsm6dsr_from_fs2000dps_to_mdps(data_raw_angular_rate[2]);
    //     sprintf((char *)tx_buffer,
    //             "Angular rate [mdps]:%4.2f\t%4.2f\t%4.2f\r\n",
    //             angular_rate_mdps[0], angular_rate_mdps[1], angular_rate_mdps[2]);
    //     tx_com(tx_buffer, strlen((char const *)tx_buffer));
    // }
    platform_delay(1000);
}

/*
 * @brief  Write generic device register (platform dependent)
 *
 * @param  handle    customizable argument. In this examples is used in
 *                   order to select the correct sensor bus handler.
 * @param  reg       register to write
 * @param  bufp      pointer to data to write in register reg
 * @param  len       number of consecutive register to write
 *
 */
static int32_t platform_write(void *handle, uint8_t reg, const uint8_t *bufp,
                              uint16_t len)
{
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET);
    HAL_SPI_Transmit(handle, &reg, 1, 1000);
    HAL_SPI_Transmit(handle, (uint8_t *)bufp, len, 1000);
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);

    return 0;
}

/*
 * @brief  Read generic device register (platform dependent)
 *
 * @param  handle    customizable argument. In this examples is used in
 *                   order to select the correct sensor bus handler.
 * @param  reg       register to read
 * @param  bufp      pointer to buffer that store the data read
 * @param  len       number of consecutive register to read
 *
 */
static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp,
                             uint16_t len)
{
    reg |= 0x80;
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET);
    HAL_SPI_Transmit(handle, &reg, 1, 1000);
    HAL_SPI_Receive(handle, bufp, len, 1000);
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);
    return 0;
}

/*
 * @brief  Send buffer to console (platform dependent)
 *
 * @param  tx_buffer     buffer to transmit
 * @param  len           number of byte to send
 *
 */
static void tx_com(uint8_t *tx_buffer, uint16_t len)
{
    HAL_UART_Transmit(&huart1, tx_buffer, len, 1000);
}

/*
 * @brief  platform specific delay (platform dependent)
 *
 * @param  ms        delay in ms
 *
 */
static void platform_delay(uint32_t ms)
{
    HAL_Delay(ms);
}

/*
 * @brief  platform specific initialization (platform dependent)
 */
void platform_init(void)
{
    /* Initialize mems driver interface */
    dev_ctx.write_reg = platform_write;
    dev_ctx.read_reg = platform_read;
    dev_ctx.handle = &hspi1;

    /* Wait sensor boot time */
    platform_delay(BOOT_TIME);
    /* Check device ID */
    while (1)
    {
        // 考虑如何喂狗
        lsm6dsr_device_id_get(&dev_ctx, &whoamI);
        if (whoamI == LSM6DSR_ID)
        {
            sprintf((char *)tx_buffer,
                    "Read id :0x%2x\r\n",
                    whoamI);
            tx_com(tx_buffer, strlen((char const *)tx_buffer));

            break;
        }
        platform_delay(BOOT_TIME);
    }
    /* Restore default configuration */
    lsm6dsr_reset_set(&dev_ctx, PROPERTY_ENABLE);
    do
    {
        lsm6dsr_reset_get(&dev_ctx, &rst);
    } while (rst);

    /* Disable I3C interface */
    lsm6dsr_i3c_disable_set(&dev_ctx, LSM6DSR_I3C_DISABLE);
    /* Enable Block Data Update */
    lsm6dsr_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);
    /* Set Output Data Rate */
    lsm6dsr_xl_data_rate_set(&dev_ctx, LSM6DSR_XL_ODR_12Hz5);
    lsm6dsr_gy_data_rate_set(&dev_ctx, LSM6DSR_GY_ODR_12Hz5);
    /* Set full scale */
    lsm6dsr_xl_full_scale_set(&dev_ctx, LSM6DSR_2g);
    lsm6dsr_gy_full_scale_set(&dev_ctx, LSM6DSR_2000dps);
    /* Configure filtering chain(No aux interface)
     * Accelerometer - LPF1 + LPF2 path
     */
    lsm6dsr_xl_hp_path_on_out_set(&dev_ctx, LSM6DSR_LP_ODR_DIV_100);
    lsm6dsr_xl_filter_lp2_set(&dev_ctx, PROPERTY_ENABLE);
}

3.结果

在这里插入图片描述


总结

有什么问题,可以评论区里面提一下,看到都会帮忙解决,这个案例只是简单应用,没有涉及复杂的使用过程。

<think>嗯,用户需要关于LSM6DSR的I2C驱动实现或教程。首先,我应该确认LSM6DSR和之前提到的LSM6DS3是否属于同一产品线。LSM6DS系列通常都是ST的IMU传感器,所以驱动可能有相似之处。用户可能已经看过LSM6DS3的中文手册,但需要LSM6DSR的具体信息。 接下来,我需要考虑I2C驱动的实现步骤。通常,这包括初始化I2C总线、配置传感器寄存器、读取数据等。可能需要参考LSM6DSR的数据手册,但用户可能没有该文档,所以需要提供获取途径。此外,ST的HAL库或标准外设库可能包含示例代码,可以引导用户查找这些资源。 用户可能需要具体的代码示例,比如如何通过I2C发送和接收数据。可能需要给出一个基本的框架,比如在STM32上使用HAL库的示例。同时,需要注意寄存器地址是否正确,以及I2C地址的配置,因为LSM6DSR的I2C地址可能和DS3不同。 另外,用户可能遇到问题,比如通信失败或数据读取错误,应该提醒常见问题排查步骤,比如检查硬件连接、I2C地址、时钟速度等。可能还需要提到使用逻辑分析仪或示波器来调试信号。 然后,生成相关问题,考虑用户可能的后续需求,比如SPI驱动、FIFO配置、数据解析等。这些相关问题可以帮助用户进一步深入开发。 最后,确保所有提到的资源都有引用,比如ST的社区、GitHub代码库,以及之前提到的中文手册,虽然主要是DS3的,但可能有参考价值。</think>### LSM6DSR I2C驱动实现要点 LSM6DSR是STMicroelectronics推出的六轴惯性传感器,支持I2C/SPI通信协议。其I2C驱动实现主要包括以下步骤: 1. **硬件连接** - SDA/SCL引脚需接上拉电阻(典型值4.7kΩ) - I2C时钟频率建议不超过400kHz(快速模式) - 设备地址:$0xD6$(SA0接高电平)或$0xD4$(SA0接低电平)[^1] 2. **初始化流程**: ```c // STM32 HAL库示例 void LSM6DSR_Init(I2C_HandleTypeDef *hi2c) { uint8_t config[2] = {0}; // 使能加速度计(104Hz,±4g) config[0] = 0x10; // CTRL1_XL寄存器地址 config[1] = 0x40; // ODR_XL3 = 0, ODR_XL[3:0]=0100 (104Hz), FS_XL=00(±4g) HAL_I2C_Master_Transmit(hi2c, LSM6DSR_ADDRESS, config, 2, 100); // 使能陀螺仪(104Hz,±500dps) config[0] = 0x11; // CTRL2_G寄存器地址 config[1] = 0x4C; // ODR_G[3:0]=0100 (104Hz), FS_G=10(±500dps) HAL_I2C_Master_Transmit(hi2c, LSM6DSR_ADDRESS, config, 2, 100); } ``` 3. **数据读取**: ```c void LSM6DSR_ReadAccel(I2C_HandleTypeDef *hi2c, float *accel) { uint8_t buffer[6]; uint8_t reg = 0x28; // OUTX_L_A寄存器地址 HAL_I2C_Master_Transmit(hi2c, LSM6DSR_ADDRESS, &reg, 1, 100); HAL_I2C_Master_Receive(hi2c, LSM6DSR_ADDRESS, buffer, 6, 100); // 数据转换(假设±4g量程) accel[0] = (int16_t)(buffer[1]<<8 | buffer[0]) * 0.122 / 1000; // X轴(单位:g) accel[1] = (int16_t)(buffer[3]<<8 | buffer[2]) * 0.122 / 1000; // Y轴 accel[2] = (int16_t)(buffer[5]<<8 | buffer[4]) * 0.122 / 1000; // Z轴 } ``` 4. **调试建议**: - 使用逻辑分析仪验证I2C波形 - 检查传感器ID寄存器(0x0F,默认值$0x6C$) - 验证供电电压(1.71V-3.6V) - 确保I2C时序满足tSU;STA(最小值250ns)和tHD;STA(最小值250ns)要求[^1]
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值