地磁传感器(学习笔记下)

时间:2024-10-27 07:20:15

咱们接着学习笔记上来学习哈,首先,我们编写读取方位角程序,配置好传感器以后,我们就可以读取磁力值了,我们先定义一个结构体类型,用来存放磁力值以及方位角值。这个结构体,放到qmc5883l.h文件中

typedef struct{
    int16_t mag_x; //放xyz方向的磁力值
    int16_t mag_y;
    int16_t mag_z;
    float   azimuth; //最后的azimuth方位角
}t_sQMC5883L;

这个结构体中用到了int16_t,需要包含stdint.h头文件

#include <stdint.h>

接下来,写读取地磁传感器值的函数,放到qmc5883l.c文件中

void qmc5883l_read_xyz(t_sQMC5883L *p) //该函数接受一个指向 t_sQMC5883L 结构体的指针 p,用于存储读取的磁场数据
{
    uint8_t status, data_ready=0; //status: 用于存储从传感器读取的状态寄存器值,data_ready: 用于标记数据是否准备好
    int16_t mag_reg[3]; //mag_reg[3]: 用于存储从传感器读取的磁场数据(X、Y、Z轴)

    qmc5883L_register_read(QMC5883L_STATUS, &status, 1); // 读状态寄存器 qmc5883L_register_read(QMC5883L_STATUS, &status, 1): 读取QMC5883L传感器的状态寄存器,并将结果存储在 status 变量中
    
    if (status & 0x01) //if (status & 0x01): 检查状态寄存器的最低位(0x01)是否为1,表示数据是否准备好。如果数据准备好,将 data_ready 设置为1
    {
        data_ready = 1; 
    }
    if (data_ready == 1) //if (data_ready == 1): 如果数据准备好,执行以下操作
    {
        data_ready = 0; //data_ready = 0: 重置 data_ready 标志
        qmc5883L_register_read(QMC5883L_XOUT_L, (uint8_t *)mag_reg, 6); //qmc5883L_register_read(QMC5883L_XOUT_L, (uint8_t *)mag_reg, 6): 读取QMC5883L传感器的X、Y、Z轴数据寄存器,并将结果存储在 mag_reg 数组中;//(uint8_t *)mag_reg: 将 mag_reg 数组转换为 uint8_t 指针,用于存储读取的数据;QMC5883L_XOUT_L: X轴数据的低字节寄存器地址 ;6: 读取的数据长度(6字节,每个轴2字节)

        p->mag_x = mag_reg[0]; // 将读取的X轴数据存储在结构体 p 的 mag_x 成员中
        p->mag_y = mag_reg[1]; //将读取的Y轴数据存储在结构体 p 的 mag_y 成员中
        p->mag_z = mag_reg[2]; //将读取的Z轴数据存储在结构体 p 的 mag_z 成员中
    }
}

函数中,先读取状态寄存器,看看磁力值是否可读,然后再读。读到后的值,最终传入t_sQMC5883L定义的结构体,注意一下这里面的mag_reg数据变量,定义的时候是16位的3个元素,在读寄存器的时候,强制为8位指针变量,读6个字节。这里,大家可以看一下寄存器定义,磁力值寄存器有6个,每个值都是由低字节寄存器和高字节寄存器组成。然后我们再写一个计算方位角的函数,使用磁力值计算方位角,最简单的方式,只需要一个公式。我们把这个函数放到qmc5883l.c文件中

void qmc5883l_fetch_azimuth(t_sQMC5883L *p)
{
    qmc5883l_read_xyz(p);

    p->azimuth = (float)atan2(p->mag_y, p->mag_x) * 180.0 / 3.1415926 + 180.0;
}

这个函数里面用到了atan2函数,需要包含头文件math.h文件

#include <math.h>

我们把这个计算方位角的函数在qmc5883l.h文件中进行声明

extern void qmc5883l_fetch_azimuth(t_sQMC5883L *p);

然后我们在app_main函数中调用它

void app_main(void)
{
    ESP_ERROR_CHECK(i2c_master_init());
    ESP_LOGI(TAG, "I2C initialized successfully");

    qmc5883l_init();

    while (1)
    {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        qmc5883l_fetch_azimuth(&QMC5883L);
        ESP_LOGI(TAG, "azimuth = %.1f", QMC5883L.azimuth);
    }
}

在主函数中,qmc5883l初始化以后,每间隔1秒钟计算1次方位角值,然后通过串口发送到终端。

这里面把读取到的值给了QMC5883这个结构体变量,需要在主函数前面定义一下

t_sQMC5883L QMC5883L;

函数里面用到了freeRTOS的延时函数,需要在main.c文件的最前面包含相关头文件

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"