LIS3DH三轴加速度计-实现欧拉角(俯仰角,横滚角)

项目场景:

使用的是ESP32C3模块, 大家可以参考一下怎么实现LIS3DH三轴加速度计-实现欧拉角(俯仰角,横滚角)

加速度->欧拉角 转换公式

*pitch = (atan(acce->AcceX / sqrt(acce->AcceY * acce->AcceY + acce->AcceZ * acce->AcceZ))) * 57.3f; // *57.3f = *180/3.14
*roll = (atan(acce->AcceY / sqrt(acce->AcceX * acce->AcceX + acce->AcceZ * acce->AcceZ))) * 57.3f;  // *57.3f = *180/3.14

lis3dh.h

#ifndef __LIS3DH_H
#define __LIS3DH_H

#include <stdio.h>
#include "esp_log.h"
#include "driver/i2c.h"
#include "sdkconfig.h"

typedef struct
{
    short AcceX; //x加速度
    short AcceY; //y加速度
    short AcceZ; //z加速度
} lis3dh_acce_xyz_t;
extern lis3dh_acce_xyz_t lis3dh_acce_xyz;

uint8_t lis3dh_Init(void);
uint8_t Get_Accelerometer(lis3dh_acce_xyz_t *acce_xyz);
void lis3dh_task(void);
void LIS3DH_get_angleXY(lis3dh_acce_xyz_t *acce, float *pitch, float *roll);

#endif

lis3dh.c

#include "lis3dh.h"
#include "math.h"

static const char *TAG = "lis3dh";

#define I2C_MASTER_SDA_IO 19
#define I2C_MASTER_SCL_IO 18
#define I2C_MASTER_FREQ_HZ 100000
#define I2C_MASTER_PORT I2C_NUM_0

#define ACK_CHECK_EN 0x1           /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0          /*!< I2C master will not check ack from slave */
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT I2C_MASTER_READ   /*!< I2C master read */
#define ACK_VAL 0x0                /*!< I2C ack value */
#define NACK_VAL 0x1               /*!< I2C nack value */

/********************************************/
#define I2C_MASTER_ADDR 0x18 //设备地址ID:0x33
#define WHO_AM_I 0x33
#define LIS3DH_REG_WHO_AM_I 0x0f
#define LIS3DH_REG_STATUS_AUX 0x07
#define LIS3DH_REG_OUT_ADC1_L 0x08
#define LIS3DH_REG_OUT_ADC1_H 0x09
#define LIS3DH_REG_OUT_ADC2_L 0x0a
#define LIS3DH_REG_OUT_ADC2_H 0x0b
#define LIS3DH_REG_OUT_ADC3_L 0x0c
#define LIS3DH_REG_OUT_ADC3_H 0x0d
#define LIS3DH_REG_INT_COUNTER 0x0e
#define LIS3DH_REG_WHO_AM_I 0x0f
#define LIS3DH_REG_TEMP_CFG 0x1f
#define LIS3DH_REG_CTRL1 0x20
#define LIS3DH_REG_CTRL2 0x21
#define LIS3DH_REG_CTRL3 0x22
#define LIS3DH_REG_CTRL4 0x23
#define LIS3DH_REG_CTRL5 0x24
#define LIS3DH_REG_CTRL6 0x25
#define LIS3DH_REG_REFERENCE 0x26
#define LIS3DH_REG_STATUS 0x27
#define LIS3DH_REG_OUT_X_L 0x28
#define LIS3DH_REG_OUT_X_H 0x29
#define LIS3DH_REG_OUT_Y_L 0x2a
#define LIS3DH_REG_OUT_Y_H 0x2b
#define LIS3DH_REG_OUT_Z_L 0x2c
#define LIS3DH_REG_OUT_Z_H 0x2d
#define LIS3DH_REG_FIFO_CTRL 0x2e
#define LIS3DH_REG_FIFO_SRC 0x2f
#define LIS3DH_REG_INT1_CFG 0x30
#define LIS3DH_REG_INT1_SRC 0x31
#define LIS3DH_REG_INT1_THS 0x32
#define LIS3DH_REG_INT1_DUR 0x33
#define LIS3DH_REG_INT2_CFG 0x34
#define LIS3DH_REG_INT2_SRC 0x35
#define LIS3DH_REG_INT2_THS 0x36
#define LIS3DH_REG_INT2_DUR 0x37
#define LIS3DH_REG_CLICK_CFG 0x38
#define LIS3DH_REG_CLICK_SRC 0x39
#define LIS3DH_REG_CLICK_THS 0x3a
#define LIS3DH_REG_TIME_LIMIT 0x3b
#define LIS3DH_REG_TIME_LATENCY 0x3c
#define LIS3DH_REG_TIME_WINDOW 0x3d

lis3dh_acce_xyz_t lis3dh_acce_xyz = {0};
/*
  初始化I2C
*/
static esp_err_t IIC_Init(void)
{
  i2c_config_t conf = {
      .mode = I2C_MODE_MASTER,
      .sda_io_num = I2C_MASTER_SDA_IO,
      .sda_pullup_en = GPIO_PULLUP_ENABLE,
      .scl_io_num = I2C_MASTER_SCL_IO,
      .scl_pullup_en = GPIO_PULLUP_ENABLE,
      .master.clk_speed = I2C_MASTER_FREQ_HZ,
      // .clk_flags = 0,          /*!< Optional, you can use I2C_SCLK_SRC_FLAG_* flags to choose i2c source clock here. */
  };
  esp_err_t err = i2c_param_config(I2C_MASTER_PORT, &conf);
  if (err != ESP_OK)
  {
    return err;
  }
  return i2c_driver_install(I2C_MASTER_PORT, conf.mode, 0, 0, 0);
}

/*
  IIC写一个字节
  reg:寄存器地址
  data:数据
  返回值:0,正常
  其他,错误代码
*/
static esp_err_t I2C_Write_Byte(uint8_t reg, uint8_t data)
{
  int ret;
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, I2C_MASTER_ADDR << 1 | WRITE_BIT, ACK_CHECK_EN); //设备地址
  i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);                              //寄存器
  i2c_master_write_byte(cmd, data, ACK_CHECK_EN);                             //数据
  i2c_master_stop(cmd);
  ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);
  return ret;
}
/*
  IIC读一个字节
  reg:寄存器地址
  返回值:读到的数据
*/
static esp_err_t I2C_Read_Byte(uint8_t reg, uint8_t *redata)
{
  int ret;
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, I2C_MASTER_ADDR << 1 | WRITE_BIT, ACK_CHECK_EN); //设备地址+写
  i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);                              //寄存器
  i2c_master_stop(cmd);
  ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);
  if (ret != ESP_OK)
  {
    return ret;
  }
  vTaskDelay(30 / portTICK_RATE_MS);
  cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, I2C_MASTER_ADDR << 1 | READ_BIT, ACK_CHECK_EN); //设备地址+读
  i2c_master_read_byte(cmd, redata, NACK_VAL);
  i2c_master_stop(cmd);
  ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);
  return ret;
}
/*
  IIC读多个字节
  reg:寄存器地址
  返回值:读到的数据Len
*/
static esp_err_t I2C_Read_Len(uint8_t reg, uint8_t len, uint8_t *buf)
{
  int ret;
  i2c_cmd_handle_t cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, I2C_MASTER_ADDR << 1 | WRITE_BIT, ACK_CHECK_EN); //设备地址
  i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);                              //寄存器
  i2c_master_stop(cmd);
  ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);
  if (ret != ESP_OK)
  {
    return ret;
  }
  vTaskDelay(30 / portTICK_RATE_MS);
  cmd = i2c_cmd_link_create();
  i2c_master_start(cmd);
  i2c_master_write_byte(cmd, I2C_MASTER_ADDR << 1 | READ_BIT, ACK_CHECK_EN);
  if (len > 1)
  {
    i2c_master_read(cmd, buf, len - 1, ACK_VAL);
  }
  i2c_master_read_byte(cmd, buf + len - 1, NACK_VAL);
  i2c_master_stop(cmd);
  ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_RATE_MS);
  i2c_cmd_link_delete(cmd);
  return ret;
}

/*
  初始化lis3dh
  返回值:0,成功
  其他,错误代码
*/
uint8_t lis3dh_Init(void)
{
  uint8_t res = 0;
  ESP_ERROR_CHECK(IIC_Init());              //初始化IIC总线
  I2C_Read_Byte(LIS3DH_REG_WHO_AM_I, &res); //
  if (res == WHO_AM_I)                      //器件ID正确
  {
    ESP_LOGI(TAG, "LIS3DH_WHO_AM_I is:0x%X\n", res);

    I2C_Write_Byte(LIS3DH_REG_CTRL5, 0x80); //启动内存的内容
    vTaskDelay(5 / portTICK_PERIOD_MS);
    I2C_Write_Byte(LIS3DH_REG_CTRL1, 0x77); //开启XYZ加速度,高分辨率模式,400Hz
    vTaskDelay(5 / portTICK_PERIOD_MS);
    I2C_Write_Byte(LIS3DH_REG_CTRL4, 0x88); //2g,输出寄存器直到MSB和LSB读取才更新,高分辨率启用
  }
  else
  {
    ESP_LOGE(TAG, "LIS3DH_WHO_AM_I err:%X\n", res);
    return 1;
  }
  return 0;
}

/*
  得到加速度值(转换成真实加速度值)
  lis3dh_acce_xyz_t *acce x,y,z轴加速度的读数(带符号)
  返回值:0,成功
  其他,错误代码
*/
uint8_t Get_Accelerometer(lis3dh_acce_xyz_t *acce)
{
  uint8_t buf[6], res;
  /*
    获取的数据是
    高精度:12位,带符号,左对齐
  */
  I2C_Read_Byte(LIS3DH_REG_OUT_X_L, &buf[0]);
  I2C_Read_Byte(LIS3DH_REG_OUT_X_H, &buf[1]);
  I2C_Read_Byte(LIS3DH_REG_OUT_Y_L, &buf[2]);
  I2C_Read_Byte(LIS3DH_REG_OUT_Y_H, &buf[3]);
  I2C_Read_Byte(LIS3DH_REG_OUT_Z_L, &buf[4]);
  res = I2C_Read_Byte(LIS3DH_REG_OUT_Z_H, &buf[5]);
  if (res == 0)
  {
    // 左移4位后,得到真实的加速度
    acce->AcceX = (short)(((short)buf[1] << 8) | buf[0]) >> 4;
    acce->AcceY = (short)(((short)buf[3] << 8) | buf[2]) >> 4;
    acce->AcceZ = (short)(((short)buf[5] << 8) | buf[4]) >> 4;
    printf("aacx:%d aacy:%d aacz:%d \n", acce->AcceX, acce->AcceY, acce->AcceZ);
  }
  else
  {
    ESP_LOGI(TAG, "Get_Accelerometer err:%X\n", res);
  }
  return res;
}

/*
  lis3dh_acce_xyz_t *acce   XYZ加速度(实际数据)
  float *pitch              俯仰角
  float *roll               横滚角
*/
void LIS3DH_get_angleXY(lis3dh_acce_xyz_t *acce, float *pitch, float *roll)
{
  *pitch = (atan(acce->AcceX / sqrt(acce->AcceY * acce->AcceY + acce->AcceZ * acce->AcceZ))) * 57.3f; // *57.3f = *180/3.14
  *roll = (atan(acce->AcceY / sqrt(acce->AcceX * acce->AcceX + acce->AcceZ * acce->AcceZ))) * 57.3f;  // *57.3f = *180/3.14
  printf("*pitch=%.3f, *roll=%.3f,\r\n", *pitch, *roll);
}

/*
  测试任务
*/
void lis3dh_task(void)
{
  float pitch, roll;
  lis3dh_Init(); //初始化lis3dh
  while (1)
  {
    Get_Accelerometer(&lis3dh_acce_xyz);                 //获取加速度
    LIS3DH_get_angleXY(&lis3dh_acce_xyz, &pitch, &roll); //转换成俯仰角,横滚角
    vTaskDelay(50 / portTICK_PERIOD_MS);
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值