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

树莓派3上i2c_smbus_write_byte_data写入MPU6050失败

问题排查与解决建议

你的问题核心是用户态C程序调用writeMPU无法修改MPU6050的寄存器,但i2cset命令可以正常完成操作,且读功能完全正常,下面是几个高概率的排查方向:

1. 修复返回值的类型错误(最可能的根因)

i2c_smbus_write_byte_data的返回值是int类型:成功返回0,失败返回负数(比如-1表示IO错误)。但你的writeMPU函数里把返回值存在unsigned char res中,负数会被强制转换成无符号的大数值(例如-1会变成255),导致res < 0的错误判断永远不成立——你误以为写操作成功了,但实际上操作已经失败,只是错误提示没被触发。

修改方法:将res的类型改为int,同时调整函数返回值类型:

int writeMPU(unsigned char reg, unsigned char val) {
    int res;

    printf("%x %x\n", reg, val);
    res = i2c_smbus_write_byte_data(file, reg, val);
    if (res < 0) {
        printf("Writing: %X at register %X failed\n", val, reg);
    }
    return res;
}

调用该函数后,务必检查返回值是否为0,以此确认写操作是否真的成功。

2. 确认i2c设备文件的打开权限

读操作正常说明file描述符有效,但如果打开i2c节点时仅使用了O_RDONLY只读权限,写操作会直接失败。检查你的设备打开代码:

// 错误示例:只读打开,无法执行写操作
file = open("/dev/i2c-1", O_RDONLY);
// 正确写法:以读写权限打开
file = open("/dev/i2c-1", O_RDWR);

i2cset命令能成功,是因为它默认以读写权限打开i2c设备。

3. 检查i2c从设备地址的有效性

在执行读写操作前,需要通过ioctl设置目标设备的i2c地址:

int mpu_addr = 0x68; // MPU6050默认地址,若AD0引脚接高电平则为0x69
if (ioctl(file, I2C_SLAVE, mpu_addr) < 0) {
    perror("Failed to set i2c slave address");
    close(file);
    return -1;
}

虽然读操作正常说明地址大概率正确,但如果写操作前地址被意外修改,也会导致写入失败。

4. 尝试用底层i2c操作替代SMBus函数

如果SMBus函数存在兼容性问题,可以直接用i2c_msg和ioctl(I2C_RDWR)实现写操作,绕开SMBus的封装:

int writeMPU_raw(int file, unsigned char reg, unsigned char val) {
    unsigned char buf[2] = {reg, val};
    struct i2c_msg msg = {
        .addr = 0x68, // 你的MPU6050实际地址
        .flags = 0,   // 0表示写操作
        .len = 2,
        .buf = buf
    };
    struct i2c_rdwr_ioctl_data data = {
        .msgs = &msg,
        .nmsgs = 1
    };
    return ioctl(file, I2C_RDWR, &data);
}

这种方式更贴近硬件层面的i2c通信逻辑,兼容性更强。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 10:02:49