传感器介绍
开发板上的姿态传感器型号是QMI8658C,内部集成3轴加速度传感器和3轴陀螺仪传感器,支持SPI和I2C通信,在我们的开发板上使用的是I2C通信,ESP32-C3只有1个I2C外设,我们开发板上的所有I2C设备,都使用一个I2C通信接口,通过I2C设备的地址,来决定和谁通信,QMI8658C的I2C地址是0x6A。
本例程,我们将最终完成测量XYZ三个轴的角度,把角度数据通过串口传输到终端。
编写QMI8658C驱动程序
- 我们需要在main中新建qmi8658c.c、qmi8658c.h两个文件。myi2c.c、myi2c.h沿用第三课里的,CMakeLists.txt里会自动添加。
- main文件夹里的CMakeLists.txt
-
idf_component_register(SRCS "qmi8658c.c" "attitude_main.c" "gxhtc3.c" "myi2c.c" "qmi8658c.h" "gxhtc3.h" "myi2c.h" INCLUDE_DIRS "")
- 项目文件夹里的CMakeLists.txt,其中的project(attitude) #姿态控制,换了一下。
- 并将main文件夹里的main.c,改名成为attitude_main.c
#以下样板行必须在您的项目中
#CMakeList 在这个确切的顺序 cmake 工作正常
#cmke版本说明,
#包含cmake的具体地址
#项目名称,通常只需要改这个。
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(attitude) #姿态控制
接下来开始qmi8658c.h的编写(搬运加更改)
- pragma once 运行一次以防重复包含。
- 需要用到整数类型头文件<stdint.h>。
- 查资料得QMI8658C的I2C地址为0x6A,
- 定义QMI8658C寄存器地址,
- 定义QMI8658C数据结构体,
- 初始化QMI8658C,
- 获取QMI8658C的角度
#pragma once // 防止头文件被重复包含
#include <stdint.h> // 包含整数类型的头文件
// 定义QMI8658C的I2C地址
#define QMI8658C传感器地址 0x6A
// 定义QMI8658C寄存器地址
enum qmi8658c_reg
{
QMI8658C我是谁,
QMI8658C版本号,
QMI8658C控制1,
QMI8658C控制2,
QMI8658C控制3,
QMI8658C控制4,
QMI8658C控制5,
QMI8658C控制6,
QMI8658C控制7,
QMI8658C控制8,
QMI8658C控制9,
QMI8658C控制1_L,
QMI8658C控制1_H,
QMI8658C控制2_L,
QMI8658C控制2_H,
QMI8658C控制3_L,
QMI8658C控制3_H,
QMI8658C控制4_L,
QMI8658C控制4_H,
QMI8658C_FIFO_WTM_TH,
QMI8658C_FIFO_CTRL,
QMI8658C_FIFO_SMPL_CNT,
QMI8658C_FIFO_STATUS,
QMI8658C_FIFO_DATA,
QMI8658C_I2CM_STATUS = 44,
QMI8658C中断,
QMI8658C状态0,
QMI8658C_状态1,
QMI8658C时间戳低,
QMI8658C时间戳中,
QMI8658C时间戳高,
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复位 = 96
};
// 定义QMI8658C数据结构体
typedef struct{
int16_t 加速器y;
int16_t 加速器x;
int16_t 加速器z;
int16_t 陀螺仪y;
int16_t 陀螺仪x;
int16_t 陀螺仪z;
float 角度X;
float 角度Y;
float 角度Z;
}t_sQMI8658C;
void qmi8658c_init(void); // 初始化QMI8658C
void qmi8658c_fetch_angleFromAcc(t_sQMI8658C *p); // 获取QMI8658C的角度
接下来开始qmi8658c.c的编写(搬运加更改)
- 先是包含的头文件,不按先后分别为qmi8658c.h,driver/i2c.h,esp_log.h, myi2c.h, freertos/FreeRTOS.h, freertos/task.h, math.h。
- 建标签QMI8658C的变量
- 加速度计和陀螺仪的校准值的函数
- 写一个字节到 QMI8658C 寄存器的函数
- 初始化 QMI8658C 传感器的函数
- 读加速器和陀螺仪的函数
- 从加速器计算角度的函数
#include "qmi8658c.h" // 包含 QMI8658C 传感器驱动头文件
#include "driver/i2c.h" // 包含I2C驱动程序的头文件
#include "esp_log.h" // 包含日志相关的头文件
#include "myi2c.h" // 包含自定义的I2C初始化函数
#include "freertos/FreeRTOS.h" // 包含 FreeRTOS 头文件
#include "freertos/task.h" // 包含任务相关的头文件
#include <math.h> // 包含数学函数库头文件
static const char *标签 = "QMI8658C";
// 加速度计和陀螺仪的校准值
esp_err_t qmi8658c_register_read(uint8_t 寄存器地址, uint8_t *数据, size_t 长度)
{
return i2c_master_write_read_device(I2C主端口, QMI8658C传感器地址, &寄存器地址, 1, 数据, 长度, I2C自动超时 / portTICK_PERIOD_MS);
}
// 写一个字节到 QMI8658C 寄存器
esp_err_t qmi8658c_register_write_byte(uint8_t 寄存器地址, uint8_t 数据)
{
uint8_t write_buf[2] = {寄存器地址, 数据};
return i2c_master_write_to_device(I2C主端口, QMI8658C传感器地址, write_buf, sizeof(write_buf), I2C自动超时 / portTICK_PERIOD_MS);
}
// 初始化 QMI8658C 传感器
void qmi8658c_init(void)
{
uint8_t id = 0;
qmi8658c_register_read(QMI8658C我是谁, &id ,1); // 读 ID
while (id != 0x05)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
qmi8658c_register_read(QMI8658C我是谁, &id ,1);// 读 ID
}
ESP_LOGI(标签, "QMI8658C OK!");
qmi8658c_register_write_byte(QMI8658C复位, 0xb0); // 复位
vTaskDelay(10 / portTICK_PERIOD_MS); // 延时
qmi8658c_register_write_byte(QMI8658C控制1, 0x40); // CTRL1 设置地址自动增加
qmi8658c_register_write_byte(QMI8658C控制7, 0x03); // CTRL7 允许加速器和陀螺仪
qmi8658c_register_write_byte(QMI8658C控制2, 0x95); // CTRL2 设置ACC 4g 250Hz
qmi8658c_register_write_byte(QMI8658C控制3, 0xd5); // CTRL3 设置GRY 512dps 250Hz
}
void qmi8658c_Read_AccAndGry(t_sQMI8658C *p) // 读加速器和陀螺仪
{
uint8_t 状态, 数据就绪=0;
int16_t buf[6];
qmi8658c_register_read(QMI8658C状态0, &状态, 1); // 读状态寄存器
if (状态 & 0x03) // 判断加速器和陀螺仪数据是否可读
{
数据就绪 = 1; // 数据就绪标志置为1
}
if (数据就绪 == 1) // 如果数据就绪
{
数据就绪 = 0; // 数据就绪标志清零
qmi8658c_register_read(QMI8658C_AX_L, (uint8_t *)buf, 12); // 读加速器值
p->加速器x = buf[0];
p->加速器y = buf[1];
p->加速器z = buf[2];
p->陀螺仪x = buf[3];
p->陀螺仪y = buf[4];
p->陀螺仪z = buf[5];
}
}
void qmi8658c_fetch_angleFromAcc(t_sQMI8658C *p) // 从加速器计算角度
{
float temp;
qmi8658c_Read_AccAndGry(p); // 读加速器值
temp = (float)p->加速器x / sqrt( ((float)p->加速器y * (float)p->加速器y + (float)p->加速器z * (float)p->加速器z) );
p->角度X = atan(temp)*57.3f; // 180/3.14=57.3
temp = (float)p->加速器y / sqrt( ((float)p->加速器x * (float)p->加速器x + (float)p->加速器z * (float)p->加速器z) );
p->角度Y = atan(temp)*57.3f; // 180/3.14=57.3
temp = (float)p->加速器z / sqrt( ((float)p->加速器x * (float)p->加速器x + (float)p->加速器y * (float)p->加速器y) );
p->角度Z = atan(temp)*57.3f; // 180/3.14=57.3
}
myi2c不需要更改驱动,延用第三课的
更改attitude_main.c文件添加实现方式
#include "qmi8658c.h" 自定义的 QMI8658C 传感器驱动头文件
t_sQMI8658C QMI8658C; // QMI8658C 传感器结构体变量
static const char *标签 = "姿态控制程序"; // 用于 ESP-IDF 中的日志输出
注释掉第三课的变量和函数,加入QMI8658C的函数。
调用初始化函数 qmi8658c_init();
延时1s
调用qmi8658c_fetch_angleFromAcc 函数,并且用ESP_ERROR_CHECK 检测是否初始化成功。
OK,构建如果没有出错,就可以烧录了
与官方文件的差别在于,尽量汉化代码,另外,在qmi8658的驱动,将基本能汉化的都汉化了。
遗憾的是,其中函数很多名称都不能汉化。否则编译器会报错。
手打不易,看到的还请一键三连。