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