极客秀
搜索

STM32获取航向角,磁偏角!HMC5883L数字磁力计的使用

** 1 **

** 前言 **

指南针,作为中国古代四大发明之一,在人类历史上起到了不可磨灭的作用。

现在如今手机上也都集成了指南针以供我们随时查看,那么在单片机中如何或者我们的方向呢?

这时候就就可以使用 ** 数字磁力计 ** 来测量磁场强度了。

HMC5883L是一款常用的数字磁力计(三轴磁力计),能够测量地球磁场或其他磁场的强度。它通常用于电子罗盘、导航系统、方向传感器等应用。

它能够测量三个垂直轴(X、Y、Z)方向上的磁场强度,提供完整的三维磁场数据。通过I2C接口来通讯。

当我们知道XY方向的磁场强度时利用反正切函数即可计算当前角度:arctan(Y/X)

不过在实际测量过程中可能会由于周围的磁场环境收到干扰。

本期我们利用 ** STM32F103C8T6以及HMC5883L ** 实现磁场方向的获取。

** 2 **

** CubeMX设置 **



除了基础设置之外,我们需要开启STM32的硬件I2C。

PB6和PB7分别是I2C_SCL和I2C_SDA。

** 3 **

** 代码实现 **

具体的寄存器配置大家可以从芯片手册中查看,这里不对每个具体的寄存器做过多赘述。


// 数据结构体typedef struct {    int16_t x;    int16_t y;     int16_t z;} HMC5883L_Data_t;  
typedef struct {    float heading;      // 航向角(0-360度)    float magnitude;    // 磁场强度    float inclination; // 倾角    struct {        float x;        // X轴磁场分量(单位:高斯)        float y;        // Y轴磁场分量        float z;        // Z轴磁场分量    } gauss;} HMC5883L_Measure_t;// HMC5883L寄存器地址定义#define HMC5883L_ADDR          (0x1E << 1)  // I2C地址 (0x3C)#define HMC5883L_CONFIG_A      0x00  // 配置寄存器A#define HMC5883L_CONFIG_B      0x01  // 配置寄存器B#define HMC5883L_MODE          0x02  // 模式寄存器#define HMC5883L_DATA_X_MSB    0x03  // X轴数据高字节#define HMC5883L_DATA_X_LSB    0x04  // X轴数据低字节#define HMC5883L_DATA_Z_MSB    0x05  // Z轴数据高字节#define HMC5883L_DATA_Z_LSB    0x06  // Z轴数据低字节#define HMC5883L_DATA_Y_MSB    0x07  // Y轴数据高字节#define HMC5883L_DATA_Y_LSB    0x08  // Y轴数据低字节#define HMC5883L_STATUS        0x09  // 状态寄存器#define HMC5883L_ID_A          0x0A  // 识别寄存器A#define HMC5883L_ID_B          0x0B  // 识别寄存器B#define HMC5883L_ID_C          0x0C  // 识别寄存器C

我们定义数据结构体和HMC5883L的句柄结构体,数据结构体包括了XYZ三个方向的具体值。句柄结构体包含了计算得到的航向角,磁场强度(XYZ向量和的模值)以及倾角(根据Z计算得到)


HAL_StatusTypeDef HMC5883L_Init(void){    uint8_t data;    HAL_StatusTypeDef status;    // 配置寄存器A: 采样平均数=8, 输出速率=15Hz, 正常测量配置    data = 0x70;  // 0111 0000    status = HAL_I2C_Mem_Write(&hi2c1, HMC5883L_ADDR, HMC5883L_CONFIG_A, 1, &data, 1, HAL_MAX_DELAY);    if(status != HAL_OK) return status;    // 配置寄存器B: 增益设置为1090 LSB/Gauss    data = 0x20;  // 0010 0000    status = HAL_I2C_Mem_Write(&hi2c1, HMC5883L_ADDR, HMC5883L_CONFIG_B, 1, &data, 1, HAL_MAX_DELAY);    if(status != HAL_OK) return status;    // 模式寄存器: 连续测量模式    data = 0x00;    status = HAL_I2C_Mem_Write(&hi2c1, HMC5883L_ADDR, HMC5883L_MODE, 1, &data, 1, HAL_MAX_DELAY);    return status;}

根据手册配置输出速率、增益大小以及将模式配置为连续输出模式。


HAL_StatusTypeDef HMC5883L_ReadData(HMC5883L_Data_t *magData){    uint8_t buf[6];    HAL_StatusTypeDef status;    status = HAL_I2C_Mem_Read(&hi2c1, HMC5883L_ADDR, HMC5883L_DATA_X_MSB, 1, buf, 6, HAL_MAX_DELAY);    if(status != HAL_OK) return status;    //组合高八位和低八位    magData->x = (int16_t)((buf[0] << 8) | buf[1]);    magData->z = (int16_t)((buf[2] << 8) | buf[3]);    magData->y = (int16_t)((buf[4] << 8) | buf[5]);    return HAL_OK;}

从参考手册中可以看到,总共从0x00~0x05六个八位寄存器中存放着XYZ的各自高低八位的数据,所以我们可以用I2C从0x00~0x05连续读取六个数据并将高八位低八位组合起来获得XYZ数据。


/** * @brief  计算航向角(单位:度) * @param  magData: 磁力计数据结构体指针 * @retval 航向角(0-360度) */float HMC5883L_GetHeadingDegrees(HMC5883L_Data_t *magData){    float heading = atan2f((float)magData->y, (float)magData->x);        // 转换为角度    heading *= 180.0f / 3.14159f;        // 确保角度在0-360范围内    if(heading < 0)        heading += 360.0f;            return heading;}  
/** * @brief  获取所有测量数据 * @param  rawData: 原始磁力计数据结构体指针 * @param  measures: 存储测量数据的结构体指针 * @retval HAL状态 */HAL_StatusTypeDef HMC5883L_GetAllMeasures(HMC5883L_Data_t *rawData, HMC5883L_Measure_t *measures){    const float scale = 0.92; // mG/LSB for ±1.3Ga量程    // 转换为高斯单位    measures->gauss.x = rawData->x * scale / 1000.0f;    measures->gauss.y = rawData->y * scale / 1000.0f;    measures->gauss.z = rawData->z * scale / 1000.0f;    // 计算航向角    measures->heading = atan2f(measures->gauss.y, measures->gauss.x);    measures->heading *= 180.0f / 3.14159f;    if(measures->heading < 0) {        measures->heading += 360.0f;    }    // 计算磁场强度(模值)    measures->magnitude = sqrtf(        measures->gauss.x * measures->gauss.x +         measures->gauss.y * measures->gauss.y +         measures->gauss.z * measures->gauss.z    );    // 计算倾角(与水平面的夹角)    measures->inclination = atan2f(        measures->gauss.z,         sqrtf(measures->gauss.x * measures->gauss.x + measures->gauss.y * measures->gauss.y)    );    measures->inclination *= 180.0f / 3.14159f;    return HAL_OK;}

最后利用XYZ计算航向角,倾角以及磁场强度即可。

实测这个航向角测得还挺准

所有代码均上传到交流群的群文件中,可以在主页加群获取哦~

1.转载请保留原文链接谢谢!
2.本站所有资源文章出自互联网收集整理,本站不参与制作,如果侵犯了您的合法权益,请联系本站我们会及时删除。
3.本站发布资源来源于互联网,可能存在水印或者引流等信息,请用户擦亮眼睛自行鉴别,做一个有主见和判断力的用户。
4.本站资源仅供研究、学习交流之用,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担。
5.联系方式(#替换成@):pm#vimge.com

  相关内容