姿态传感器(学习笔记上)

上节我们学的是温湿传感器,这节我们学的是姿态传感器,虽然都是传感器,但是它们还是有很大的区别的,这节的传感器我们通过学习可知,开发板上的姿态传感器型号是QMI8658C,内部集成3轴加速度传感器和3轴陀螺仪传感器,支持SPI和I2C通信,在我们的开发板上使用的是I2C通信,ESP32-C3只有1个I2C外设,我们开发板上的所有I2C设备,都使用一个I2C通信接口,通过I2C设备的地址,来决定和谁通信,QMI8658C的I2C地址是0x6A,这个项目,我们将最终完成测量XYZ三个轴的角度,把角度数据通过串口传输到终端

接着,我们要进行编写QMI8658C驱动程序

这个和温湿传感器大致相似,也是使用sample project作为模板,们复制esp-idf-v5.1.3\examples\get-started\sample_project这个工程到我们的实验文件夹,然后把这个文件夹的名称修改为attitude,attitude是姿态的意思。

接着,进行我们经常的操作,在vscode中打开attitude文件夹,我们先点击打开attitude工程目录下的CMakeList.txt文件,修改工程的名称为attitude,然后保存关闭此文件(这步一般来说是我们的第一步,也就是我们的文件名)

cpp 复制代码
project(attitude)

我们这个项目需要用到I2C通信,现在我们把温湿度例程里面的myi2c.h和myi2c.c文件复制到attitude工程中的main目录下,然后我们点开main目录下的CMakeLists.txt文件,可以看到myi2c.c文件已经添加到编译路径

cpp 复制代码
idf_component_register(SRCS "myi2c.c" "main.c"
                    INCLUDE_DIRS ".")

点击打开qmi8658c.h文件,在最上面添加#pragma once

cpp 复制代码
#pragma once

点击打开qmi8658c.c文件,在最上面添加包含qmi8658c.h文件

cpp 复制代码
#include "qmi8658c.h"

点击打开main.c文件,添加头文件

cpp 复制代码
#include "myi2c.h"
#include "qmi8658c.h"

在app_main函数中,先调用I2C初始化函数

cpp 复制代码
void app_main(void)
{
    ESP_ERROR_CHECK(i2c_master_init());
    ESP_LOGI(TAG, "I2C initialized successfully");
}

函数里使用到了ESP_LOGI,需要包含esp_log.h头文件

cpp 复制代码
#include "esp_log.h"

还需要给ESP_LOGI里面的TAG定义一下

cpp 复制代码
static const char *TAG = "MAIN";

接下来,开始写qmi8658c的驱动函数,通过课程视频学习,我们先写两个读取qmi8658c寄存器的函数和写入qmi8658c寄存器的函数,写入函数用于配置传感器的参数,读取函数用于读取传感器的寄存器数据,例如ID号,状态等,这两个函数放入qmi8658c.c文件中

cpp 复制代码
esp_err_t qmi8658c_register_read(uint8_t reg_addr, uint8_t *data, size_t len)
{
    return i2c_master_write_read_device(I2C_MASTER_NUM, QMI8658C_SENSOR_ADDR,  &reg_addr, 1, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}

esp_err_t qmi8658c_register_write_byte(uint8_t reg_addr, uint8_t data)
{
    uint8_t write_buf[2] = {reg_addr, data};

    return i2c_master_write_to_device(I2C_MASTER_NUM, QMI8658C_SENSOR_ADDR, write_buf, sizeof(write_buf), I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}

然后我们在qmi8658c.c文件中添加这两个函数需要的头文件

cpp 复制代码
#include "driver/i2c.h"
#include "myi2c.h"

函数里面用到了QMI8658C_SENSOR_ADD,我们在qmi8658c.h文件中定义一下

cpp 复制代码
#define  QMI8658C_SENSOR_ADDR       0x6A

接下来,我们需要写一个qmi8658c初始化函数,用于读取ID号,配置加速度、陀螺仪范围等参数。这个函数涉及到了qmi8658c的寄存器,所以我们先用枚举类型定义寄存器,放到qmi8658c.h文件中

cs 复制代码
enum qmi8658c_reg
{
    QMI8658C_WHO_AM_I,
    QMI8658C_REVISION_ID,
    QMI8658C_CTRL1,
    QMI8658C_CTRL2,
    QMI8658C_CTRL3,
    QMI8658C_CTRL4,
    QMI8658C_CTRL5,
    QMI8658C_CTRL6,
    QMI8658C_CTRL7,
    QMI8658C_CTRL8,
    QMI8658C_CTRL9,
    QMI8658C_CATL1_L,
    QMI8658C_CATL1_H,
    QMI8658C_CATL2_L,
    QMI8658C_CATL2_H,
    QMI8658C_CATL3_L,
    QMI8658C_CATL3_H,
    QMI8658C_CATL4_L,
    QMI8658C_CATL4_H,
    QMI8658C_FIFO_WTM_TH,
    QMI8658C_FIFO_CTRL,
    QMI8658C_FIFO_SMPL_CNT,
    QMI8658C_FIFO_STATUS,
    QMI8658C_FIFO_DATA,
    QMI8658C_I2CM_STATUS = 44,
    QMI8658C_STATUSINT,
    QMI8658C_STATUS0,
    QMI8658C_STATUS1,
    QMI8658C_TIMESTAMP_LOW,
    QMI8658C_TIMESTAMP_MID,
    QMI8658C_TIMESTAMP_HIGH,
    QMI8658C_TEMP_L,
    QMI8658C_TEMP_H,
    QMI8658C_AX_L,
    QMI8658C_AX_H,
    QMI8658C_AY_L,
    QMI8658C_AY_H,
    QMI8658C_AZ_L,
    QMI8658C_AZ_H,
    QMI8658C_GX_L,
    QMI8658C_GX_H,
    QMI8658C_GY_L,
    QMI8658C_GY_H,
    QMI8658C_GZ_L,
    QMI8658C_GZ_H,
    QMI8658C_MX_L,
    QMI8658C_MX_H,
    QMI8658C_MY_L,
    QMI8658C_MY_H,
    QMI8658C_MZ_L,
    QMI8658C_MZ_H,
    QMI8658C_dQW_L = 73,
    QMI8658C_dQW_H,
    QMI8658C_dQX_L,
    QMI8658C_dQX_H,
    QMI8658C_dQY_L,
    QMI8658C_dQY_H,
    QMI8658C_dQZ_L,
    QMI8658C_dQZ_H,
    QMI8658C_dVX_L,
    QMI8658C_dVX_H,
    QMI8658C_dVY_L,
    QMI8658C_dVY_H,
    QMI8658C_dVZ_L,
    QMI8658C_dVZ_H,
    QMI8658C_AE_REG1,
    QMI8658C_AE_REG2,
    QMI8658C_RESET = 96
};

结合QMI8658C的数据手册中的寄存器定义表格,写出这个枚举定义。枚举类型的第一个值默认是0,和寄存器WHO_AM_I的地址一样,所以不用标出,然后依次递增,遇到地址不连续的寄存器地址时,单独标出,最后的结果如上代码所示

接下来写qmi8658c初始化函数到qmi8658c.c文件

cs 复制代码
void qmi8658c_init(void)
{
    uint8_t id = 0;

    qmi8658c_register_read(QMI8658C_WHO_AM_I, &id ,1);
    while (id != 0x05)
    {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        qmi8658c_register_read(QMI8658C_WHO_AM_I, &id ,1);
    }
    ESP_LOGI(TAG, "QMI8658C OK!");

    qmi8658c_register_write_byte(QMI8658C_RESET, 0xb0);  // 复位
    vTaskDelay(10 / portTICK_PERIOD_MS);
    qmi8658c_register_write_byte(QMI8658C_CTRL1, 0x40); // CTRL1 设置地址自动增加
    qmi8658c_register_write_byte(QMI8658C_CTRL7, 0x03); // CTRL7 允许加速度和陀螺仪
    qmi8658c_register_write_byte(QMI8658C_CTRL2, 0x95); // CTRL2 设置ACC 4g 250Hz
    qmi8658c_register_write_byte(QMI8658C_CTRL3, 0xd5); // CTRL3 设置GRY 512dps 250Hz
}

初始化函数里面,首先读取qmi8658c的ID号,如果不正确,就继续读,如果正确,往下执行。确定qmi8658c没有问题,先复位芯片,然后进行配置。CTRL1,配置地址自动增加后,我们读取一连串的加速度和陀螺仪数据,只写个首地址就可以连续读了。CTRL2配置加速度的量程和输出速率,CTRL3配置陀螺仪的量程和输出速率,CTRL7配置允许加速度和陀螺仪

函数里面用到了ESP_LOGI,用来输出信息,这里的TAG,需要定义。我们把这个TAG定义,放到qmi8658c.c文件中的包含头文件的下面

cs 复制代码
static const char *TAG = "QMI8658C";

函数里面使用了freeRTOS的延时函数,所以需要包含freeRTOS头文件

cs 复制代码
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

函数中也用到了ESP_LOGI宏,所以需要再添加它的头文件

cs 复制代码
#include "esp_log.h"

现在我们把这个函数的声明写到qmi8658c.h文件

cs 复制代码
extern void qmi8658c_init(void);

接下来我们在main.c文件中的app_main函数中调用这个初始化函数

cs 复制代码
void app_main(void)
{
    ESP_ERROR_CHECK(i2c_master_init());
    ESP_LOGI(TAG, "I2C initialized successfully");

    qmi8658c_init();
}

我们可以试编译一下,看看运行结果,依次配置VSCode左下角的配置选项,串口号、目标芯片、下载方式、menuconfig里面,把FLASH大小修改为8MB,其它不做修改。

好了,到这儿我们的姿态传感器上半部分结束!

相关推荐
东林知识库23 分钟前
2024年10月HarmonyOS应用开发者基础认证全新题库
学习·华为·harmonyos
随便取个六字34 分钟前
C++学习:类和对象(二)
c++·学习
OMGmyhair1 小时前
【 C++ 】C++11的初步学习
开发语言·c++·学习
呵呵哒( ̄▽ ̄)"2 小时前
尚硅谷-react教程-求和案例-优化3-整合UI组件和容器组件-总结优化-笔记
前端·笔记·react.js
l1x1n02 小时前
【IT基础中英笔记】符号系统与数据类型 | CompTIA ITF+
笔记·学习
大只因bug2 小时前
基于Springboot的在线考试与学习交流平台的设计与实现
java·spring boot·后端·学习·mysql·vue·在线考试与学习交流平台系统
kfepiza2 小时前
Win11GBK, idea2024.2.4, 使用Gradle8.8本地安装构建,不使用包装器, 解决utf-8乱码问题, 笔记241028
笔记·gradle·intellij-idea·idea·intellij idea
黄交大彭于晏3 小时前
第五天学习总结:C语言学习笔记 - 数组篇
c语言·笔记·学习
cl°3 小时前
WPF中视觉树和逻辑树的区别和联系
经验分享·学习·c#·wpf
Ylucius3 小时前
14天速成前端 ------学习日志(已完结)------ 后端程序员学习了解前端
java·开发语言·前端·vue.js·学习·状态模式·1024程序员节