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

上节我们学的是温湿传感器,这节我们学的是姿态传感器,虽然都是传感器,但是它们还是有很大的区别的,这节的传感器我们通过学习可知,开发板上的姿态传感器型号是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,其它不做修改。

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

相关推荐
Rabitebla7 小时前
【Linux 底层原理】进程(十):进程等待详解---从僵尸进程到 wait、waitpid 与 status
linux·c++·笔记·学习·visual studio
小lu飞9 小时前
2026小红书小工具怎么制作:纯前端 ZIP 打包、沙箱限制与笔记挂载流程
前端·笔记·ai·ai编程
无心水12 小时前
24、系统架构师论文写作专题 核心考点与学习笔记
笔记·学习·系统架构·架构师·安全架构·软考架构师·软考系统架构设计师
蒸蒸yyyyzwd12 小时前
邓明 Agent 系统面试-意图识别学习笔记
笔记·学习
Zhao-Jichao15 小时前
AI Prompting for Everyone 课程笔记 - P21 总结 Conclusion
人工智能·笔记
欢欢李16 小时前
【LTE L3 笔记 05】LTE同步信号
笔记·无线通信·物理层·lte·空口协议
La Pulga17 小时前
【FreeRTOS源码学习笔记】空闲任务与阻塞延时
笔记·mcu·学习·嵌入式·freertos·实时操作系统
蒸蒸yyyyzwd17 小时前
秋招学习笔记 day106
笔记·学习
小李不想当小白19 小时前
WDG看门狗(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
欢欢李19 小时前
【LTE L3 笔记 04】LTE帧结构
笔记·无线通信·物理层·lte·空口协议