做好相关准备后,我们关注的焦点在于怎么控制对应的I2C设备文件。Linux下一切皆文件,控制I2C设备也是通过控制对应的文件来实现的,下面是打开I2C文件过程。
bool MPU6050::openMPU6050()
{
char fileNameBuffer[32];
sprintf(fileNameBuffer,"/dev/i2c-%d", kI2CBus);
kI2CFileDescriptor = open(fileNameBuffer, O_RDWR);
if (kI2CFileDescriptor < 0) {
// Could not open the file
error = errno ;
return false ;
}
//set slave address
if (ioctl(kI2CFileDescriptor, I2C_SLAVE, kI2CAddress) < 0) {
// Could not open the device on the bus
error = errno ;
return false ;
}
return true ;
}
其中kI2CBus是前面提到过的序号,kI2CFileDescriptor是对应的文件描述符。用ioctl来配置对应的从机地址。第二个参数I2C_SLAVE在<linux/i2c-dev.h>头文件下定义,用于绑定第三个从机地址。完成openMPU6050操作后,就可以通过read,write等函数来读写从机寄存器了。
int MPU6050::i2cwrite(uchar writeAddr, uchar writeValue) {
int toReturn = i2c_smbus_write_byte_data(kI2CFileDescriptor, writeAddr, writeValue);
if (toReturn < 0) {
printf("MPU6050 Write error: %d",errno) ;
error = errno ;
toReturn = -1 ;
}
return toReturn ;
}
uchar MPU6050::i2cread(uchar writeAddr){
uchar res = i2c_smbus_read_byte_data(kI2CFileDescriptor, writeAddr);
if (res < 0) {
printf("MPU6050 Read error: %d",errno) ;
error = errno ;
res = -1 ;
}
return res ;
}
上面是两个关于I2C读写的方法。i2c_smbus_write_byte_data是在kI2CFileDescriptor所指示I2C文件中在writeAddr地址写writeValue数据,也就是给从机寄存器写数据;i2c_smbus_read_byte_data函数则是在指定地址读取数据。i2c_smbus相关函数还有很多,这里不一一列举。
对于MPU6050来说,操作I2C比较容易,无非是配置参数(指定寄存器写数据),读数据(指定寄存器读数据)。例如初始化initMPU6050:(PWR_MGMT_1等参数均是自己宏定义的)
i2cwrite(PWR_MGMT_1, 0x00); //解除休眠状态
i2cwrite(SMPLRT_DIV, 0x07); //陀螺仪采样率,典型值:0x07(125Hz)
i2cwrite(CONFIG, 0x06); //低通滤波频率,典型值:0x06(5Hz)
i2cwrite(GYRO_CONFIG, 0x18);//陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
i2cwrite(ACCEL_CONFIG, 0x01);//加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
从MPU6050读数据:Linux下short是2字节16位
short MPU6050::readData(uchar readAddr){
char h,l;
h=i2cread(readAddr);
l=i2cread(readAddr+1);
return (h<<8)+l; //合成数据
}
用户操作时只需要
MPU6050 *acc = new MPU6050();
int err = acc->openMPU6050();
if (err < 0){
printf("Error: %d", acc->error);
}
else {
printf("MPU6050 Device Address: 0x%02X\n",acc->kI2CAddress) ;
acc->initMPU6050();
x = acc->readData(ACCEL_XOUT_H);
y = acc->readData(ACCEL_YOUT_H);
z = acc->readData(ACCEL_ZOUT_H);
}
注意:这里得出的值并不是真实的重力值,而是灵敏度。要得到正确值还需要进行转换。下图是测出来x、y、z轴的灵敏度
如果设置ACCEL_CONFIG是 0x01的话,查表可知满量程是2G, LSB灵敏度是16384
i2cwrite(ACCEL_CONFIG, 0x01);//加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
上图的AFS_SEL实际上是ACCEL_CONFIG的第3,4位,从二进制的00~11分别代表设置加速度的满量程单位为2g~16G。
因此有转换公式:加速度值 = 灵敏度值/16384 (量程2G情况下)
同理,角速度也是一样的。下一节介绍AM2320相关内容。
参考资料:
关于I2C_smbus函数讲解可以参考 https://blog.csdn.net/mcgrady_tracy/article/details/50970717
I2C的类构成参考自https://github.com/jetsonhacks/JHLEDBackpack.git