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

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

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

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

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

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

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

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

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

  PB6和PB7分别是I2C_SCL和I2C_SDA。

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


// 数据结构体
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计算航向角,倾角以及磁场强度即可。

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

嘉立创PCB

还没有评论,抢个沙发!