You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于MSP432G2553与HMC5883L的I2C通信数据读取问题求助

排查HMC5883L与MSP432G2553 I2C通信无数据问题

我明白你现在卡在I2C读HMC5883L数据这一步了,而且还踩了个大坑——代码里用的是MSP430的头文件,但实际硬件是MSP432,这俩芯片的外设寄存器完全不一样,旧代码肯定跑不起来!咱们一步步从硬件到软件排查,搞定这个问题。

一、先把硬件连接搞对,这是基础

  • 供电要匹配:HMC5883L只能用3.3V供电,别接成5V烧了模块;MSP432的IO也是3.3V兼容,这点要注意。
  • I2C引脚别接错:MSP432G2553的默认I2C引脚是P1.6(SCL)和P1.7(SDA),一定要对应接HMC5883L的SCL、SDA引脚。
  • 别漏上拉电阻:I2C总线必须给SCL和SDA各接一个4.7kΩ左右的上拉电阻到3.3V,没这个电阻总线根本没法传输信号,很多新手都会忽略这点。
  • 确认设备地址:HMC5883L的7位I2C地址是0x1E(写操作地址是0x3C,读是0x3D),但这个地址会随ADDR引脚变化:接GND是0x1E,接VCC是0x1C,悬空是0x1D,别搞混了。

二、适配MSP432的I2C代码修正

下面给你一套能直接用的基础代码,每部分都标了关键说明,你可以直接替换旧代码:

1. I2C和GPIO初始化

#include "msp.h"
#include <stdint.h>

#define HMC5883L_ADDR 0x1E  // HMC5883L的7位I2C地址

void I2C_Init(void) {
    // 配置P1.6(SCL)、P1.7(SDA)为I2C功能引脚
    P1->SEL0 |= BIT6 | BIT7;
    P1->SEL1 &= ~(BIT6 | BIT7);

    // 复位I2C模块
    EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_SWRST;

    // 配置主模式、SMCLK时钟源、7位地址、自动停止
    EUSCI_B0->CTLW0 = EUSCI_B_CTLW0_SWRST |
                      EUSCI_B_CTLW0_MODE_3 |  // 启用I2C模式
                      EUSCI_B_CTLW0_MST |     // 主设备模式
                      EUSCI_B_CTLW0_SYNC |    // 同步通信
                      EUSCI_B_CTLW0_SSEL__SMCLK;  // 时钟源选SMCLK(默认3MHz)

    // 设置I2C时钟为100kHz:3MHz / 30 = 100kHz
    EUSCI_B0->BRW = 30;

    // 释放复位,启动I2C模块
    EUSCI_B0->CTLW0 &= ~EUSCI_B_CTLW0_SWRST;

    // 清除中断标志,避免干扰
    EUSCI_B0->IFG &= ~(EUSCI_B_IFG_TXIFG | EUSCI_B_IFG_RXIFG);
}

2. 向HMC5883L写入配置寄存器

HMC5883L需要先配置才能输出数据,比如设置测量模式、增益:

void HMC5883L_WriteReg(uint8_t reg, uint8_t data) {
    // 等待I2C总线空闲
    while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTP);

    // 发送起始信号+设备写地址
    EUSCI_B0->I2CSA = HMC5883L_ADDR;
    EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TR | EUSCI_B_CTLW0_TXSTT;

    // 等待发送缓冲区就绪
    while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG));

    // 发送目标寄存器地址
    EUSCI_B0->TXBUF = reg;
    while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG));

    // 发送配置数据
    EUSCI_B0->TXBUF = data;
    while (!(EUSCI_B0->IFG & EUSCI_B_IFG_TXIFG));

    // 发送停止信号
    EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTP;
    while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTP);
}

3. 读取三轴数据

注意!HMC5883L的寄存器顺序是X高、X低、Z高、Z低、Y高、Y低,不是常规的X-Y-Z,别搞反了:

void HMC5883L_ReadData(int16_t *x, int16_t *y, int16_t *z) {
    uint8_t buf[6];

    // 先指定要读取的起始寄存器(0x03是X轴高位寄存器)
    HMC5883L_WriteReg(0x03, 0x00);

    // 等待总线空闲
    while (EUSCI_B0->CTLW0 & EUSCI_B_CTLW0_TXSTP);

    // 发送起始信号+设备读地址
    EUSCI_B0->I2CSA = HMC5883L_ADDR;
    EUSCI_B0->CTLW0 &= ~EUSCI_B_CTLW0_TR;  // 切换到接收模式
    EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTT;

    // 连续读取6个字节数据
    for (int i = 0; i < 6; i++) {
        // 等待接收缓冲区就绪
        while (!(EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG));
        buf[i] = EUSCI_B0->RXBUF;

        // 最后一个字节读取前发送停止信号
        if (i == 5) {
            EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_TXSTP;
        }
    }

    // 组合成16位带符号数据
    *x = (buf[0] << 8) | buf[1];
    *z = (buf[2] << 8) | buf[3];
    *y = (buf[4] << 8) | buf[5];
}

4. 主函数示例

int main(void) {
    // 关闭看门狗
    WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD;

    // 初始化I2C
    I2C_Init();

    // 配置HMC5883L:连续测量模式、采样1次、增益1.3Ga
    HMC5883L_WriteReg(0x00, 0x70);  // 配置寄存器A
    HMC5883L_WriteReg(0x01, 0x20);  // 配置寄存器B
    HMC5883L_WriteReg(0x02, 0x00);  // 模式寄存器:连续测量

    int16_t x, y, z;

    while (1) {
        // 读取三轴数据
        HMC5883L_ReadData(&x, &y, &z);

        // 这里可以加数据处理或UART打印逻辑,比如把x/y/z输出到串口
        // 延时100ms再读取下一次(3MHz时钟下)
        __delay_cycles(300000);
    }
}

三、额外排查小技巧

  • 检查时钟配置:如果你的MSP432修改过SMCLK频率,要同步修改I2C初始化里的BRW值(公式:BRW = SMCLK频率 / 目标I2C频率)。
  • 用工具看总线信号:如果硬件连接没问题,用示波器或逻辑分析仪观察SCL和SDA的波形,看有没有起始信号、地址发送和设备应答,能快速定位是发送端还是接收端的问题。
  • 交叉验证:用其他I2C设备(比如OLED模块)测试MSP432的I2C功能,排除芯片本身的问题;或者换一个HMC5883L模块,确认不是模块损坏。

内容的提问来源于stack exchange,提问作者Alex044

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:33:42