树莓派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
相关产品推荐
相关产品推荐

