树莓派4B iio子系统 mpu6050

编写基于iio的mpu6050

遇到的问题,在读取数据时,读出来的数据不能直接拼接成int类型

需要先将其转换成short int,再转换成int

效果如图所示

注:驱动是使用的modprobe加载的

画的思维导图(部分,上传的文件中有完整的)

设备树修改部分:

参考资料:正点原子 I.MX6U嵌入式linux驱动开发指南

mpu6050.c文件代码

c 复制代码
/***************************************************************
文件名		: mpu6050.c
作者	  	: kun
版本	   	: V1.0
描述	   	: mpu6050驱动程序
其他	   	: 无
日志	   	: 初版V1.0 2023/12/5 kun创建
			 V1.1 2023/12/5	
***************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/regmap.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include "mpu6050.h"

#define MPU6050_NAME "mpu6050"

#define MPU6050_CHAN(ty_pe, channel_2 , index)    \
    {                                              \
        .type = ty_pe,                             \
        .modified = 1,                             \
        .channel2 = channel_2,                     \
        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)  |       \
                            BIT(IIO_CHAN_INFO_CALIBBIAS),     \
        .scan_index = index,                                 \
        .scan_type = {                                        \
            .sign = 's',                                      \
            .realbits = 16,                                   \
            .storagebits = 16,                                \
            .shift = 0,                                       \
            .endianness = IIO_BE,                             \
        },                                                    \
    }

enum inv_mpu6050_scan {
    INV_MPU6050_SCAN_ACCL_X,
    INV_MPU6050_SCAN_ACCL_Y,
    INV_MPU6050_SCAN_ACCL_Z,
    INV_MPU6050_SCAN_GYRO_X,
    INV_MPU6050_SCAN_GYRO_Y,
    INV_MPU6050_SCAN_GYRO_Z,
};

struct mpu6050_dev{
	struct i2c_client *client;	/* i2c 设备  保存mpu6050设备对应的i2c_client结构体,匹配成功后由.prob函数带回。*/
	struct mutex lock;
	struct iio_trigger  *trig;
};

/*
 * mpu6050陀螺仪分辨率,对应250、500、1000、2000,计算方法:
 * 以正负250度量程为例,500/2^16=0.007629,扩大1000000倍,就是7629
 */
static const int gyro_scale_mpu6050[] = {7629, 15258, 30517, 61035};

/* 
 * mpu6050加速度计分辨率,对应2、4、8、16 计算方法:
 * 以正负2g量程为例,4/2^16=0.000061035,扩大1000000000倍,就是61035
 */
static const int accel_scale_mpu6050[] = {61035, 122070, 244140, 488281};



/*
* MPU6050 通道 3路陀螺仪,3路加速度
*/

static const struct iio_chan_spec mpu6050_channels[]={
    MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X),
    MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y),
    MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z),

    MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X),
    MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y),
    MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z),
};

/*------------------IIC设备内容----------------------*/

/*通过i2c 向mpu6050写入数据
*mpu6050_client:mpu6050的i2c_client结构体。
*address, 数据要写入的地址,
*data, 要写入的数据
*返回值,错误,-1。成功,0  
*/
static int i2c_write_mpu6050(struct i2c_client *mpu6050_client, u8 address, u8 data)
{
	int error = 0;
	u8 write_data[2];
	struct i2c_msg send_msg; //要发送的数据结构体

	/*设置要发送的数据*/
	write_data[0] = address;
	write_data[1] = data;

	/*发送 iic要写入的地址 reg*/
	send_msg.addr = mpu6050_client->addr; //mpu6050在 iic 总线上的地址
	send_msg.flags = 0;					  //标记为发送数据
	send_msg.buf = write_data;			  //写入的首地址
	send_msg.len = 2;					  //reg长度

	/*执行发送*/
	error = i2c_transfer(mpu6050_client->adapter, &send_msg, 1);
	if (error != 1)
	{
		printk(KERN_DEBUG "\n i2c_transfer error \n");
		return -1;
	}
	return 0;
}

/*通过i2c 向mpu6050写入数据
*mpu6050_client:mpu6050的i2c_client结构体。
*address, 要读取的地址,
*data,保存读取得到的数据
*length,读长度
*返回值,错误,-1。成功,0
*/
static int i2c_read_mpu6050(struct i2c_client *mpu6050_client, u8 address, void *data, u32 length)
{
	int error = 0;
	u8 address_data = address;
	struct i2c_msg mpu6050_msg[2];
	/*设置读取位置msg*/
	mpu6050_msg[0].addr = mpu6050_client->addr; //mpu6050在 iic 总线上的地址
	mpu6050_msg[0].flags = 0;					//标记为发送数据
	mpu6050_msg[0].buf = &address_data;			//写入的首地址
	mpu6050_msg[0].len = 1;						//写入长度

	/*设置读取位置msg*/
	mpu6050_msg[1].addr = mpu6050_client->addr; //mpu6050在 iic 总线上的地址
	mpu6050_msg[1].flags = I2C_M_RD;			//标记为读取数据
	mpu6050_msg[1].buf = data;					//读取得到的数据保存位置
	mpu6050_msg[1].len = length;				//读取长度

	error = i2c_transfer(mpu6050_client->adapter, mpu6050_msg, 2);

	if (error != 2)
	{
		printk(KERN_DEBUG "\n i2c_read_mpu6050 error \n");
		return -1;
	}
	return 0;
}

/*初始化i2c
*返回值,成功,返回0。失败,返回 -1
*/
static int mpu6050_init(struct mpu6050_dev *dev)
{
#if 0
	int error = 0;
	/*配置mpu6050*/
	error += i2c_write_mpu6050(dev->client, PWR_MGMT_1, 0X80);
    mdelay(50);
    error += i2c_write_mpu6050(dev->client, PWR_MGMT_1, 0X01);
    mdelay(50);
	error += i2c_write_mpu6050(dev->client, SMPLRT_DIV, 0X00);       /* 输出速率是内部采样率*/ 
    error += i2c_write_mpu6050(dev->client, GYRO_CONFIG, 0X18);      /* 陀螺仪±2000dps量程 */
    error += i2c_write_mpu6050(dev->client, ACCEL_CONFIG, 0X18);     /* 加速度计±16G量程 */    
	error += i2c_write_mpu6050(dev->client, CONFIG, 0X04);           /* 陀螺仪低通滤波BW=20Hz */  
    error += i2c_write_mpu6050(dev->client, ACCEL_CONFIG2, 0X04);    /* 加速度计低通滤波BW=21.2Hz */
    error += i2c_write_mpu6050(dev->client, PWR_MGMT_2, 0X00);       /* 打开加速度计和陀螺仪所有轴 */
    error += i2c_write_mpu6050(dev->client, LP_MODE_CFG, 0X00);      /* 关闭低功耗 */
    
    error += i2c_write_mpu6050(dev->client, INT_ENABLE, 0X01);       /* 使能FIFO溢出以及数据就绪中断 */

	if (error < 0)
	{
		/*初始化错误*/
		printk(KERN_DEBUG "\n mpu6050_init error \n");
		return -1;
	}
	return 0;
#endif
#if 1
int error = 0;
	/*配置mpu6050*/
	error += i2c_write_mpu6050(dev->client, PWR_MGMT_1, 0X01);
    error += i2c_write_mpu6050(dev->client, PWR_MGMT_2, 0X00);
	error += i2c_write_mpu6050(dev->client, SMPLRT_DIV, 0X09);
	error += i2c_write_mpu6050(dev->client, CONFIG, 0X06);
	error += i2c_write_mpu6050(dev->client, GYRO_CONFIG, 0X18);      /* 陀螺仪±2000dps量程 */
    error += i2c_write_mpu6050(dev->client, ACCEL_CONFIG, 0X18);     /* 加速度计±16G量程 */ 

	if (error < 0)
	{
		/*初始化错误*/
		printk(KERN_DEBUG "\n mpu6050_init error \n");
		return -1;
	}
	return 0;
#endif
}

/*
* @description : 读取MPU6050传感器数据,可用于陀螺仪、加速度
* @param - dev : mpu6050设备
* @param - reg : 要读取的通道寄存器首地址
* @param - axis :需要读取的通道,比如x,y,z
* @param - *val : 保存读取到的值
* @return     :1(IIO_VAL_INT),成功;其他值,错误 
*/
static int mpu6050_sensor_show( struct mpu6050_dev *dev, 
                                int reg,
                                int axis,
                                int *val)
{
    int ind;
    int error=0;
    char data_H;
	char data_L;
    short int data = -1;
    ind = (axis-IIO_MOD_X) * 2;
    error += i2c_read_mpu6050(dev->client, reg + ind, &data_H, 1);
	error += i2c_read_mpu6050(dev->client, reg + ind +1, &data_L, 1);
    printk("%d\r\n",data);
    printk("%d\r\n",(int)data_H);
    printk("%d\r\n",(int)data_L);
    data =(data_H<<8) +data_L;
    *val = (int)data;
    printk("%d\r\n",*val);
    if(error !=0 )
        return  -EINVAL;
    return IIO_VAL_INT;
}

/*
* @description :读取MPU6050 陀螺仪、加速度计值
* @param -indio_dev : iio设备
* @param -chan      :通道
* @param -val : 保存读取到的通道值
* @return :1(IIO_VAL_INT),成功;其他值:错误
*/
static int mpu6050_read_channel_data( struct iio_dev *indio_dev,
                                      struct iio_chan_spec const * chan,
                                      int *val)
{
    struct mpu6050_dev *dev = iio_priv(indio_dev);
    int ret = 0;
    switch(chan->type){
        case IIO_ANGL_VEL:  /* 读取陀螺仪数据 */
            ret = mpu6050_sensor_show(dev, GYRO_XOUT_H, chan->channel2 ,val);   /* channel2 为x ,y,z轴 */
            break;
        case IIO_ACCEL:    /* 读取加速度计 数据 */
            ret = mpu6050_sensor_show(dev, ACCEL_XOUT_H, chan->channel2,val);
            break;
        default:
            ret = -EINVAL;
    }
    return ret;
}

/*
  * @description     	: 读函数,当读取sysfs中的文件的时候最终此函数会执行,此函数
  * 					:里面会从传感器里面读取各种数据,然后上传给应用。
  * @param - indio_dev	: iio_dev
  * @param - chan   	: 通道
  * @param - val   		: 读取的值,如果是小数值的话,val是整数部分。
  * @param - val2   	: 读取的值,如果是小数值的话,val2是小数部分。
  * @return				: 0,成功;其他值,错误
  */
static int mpu6050_read_raw(struct iio_dev *indio_dev,
			   struct iio_chan_spec const *chan,
			   int *val, int *val2, long mask)
{
    int ret = 0;
    int error = 0;
    struct mpu6050_dev *dev = iio_priv(indio_dev);
    unsigned char regdata = 0;
    printk("mpu6050_read_raw\r\n");

    switch (mask) {
        case IIO_CHAN_INFO_RAW:      /*读取加速度、陀螺仪原始值*/
            printk("read raw data\r\n");
            mutex_lock(&dev->lock);	                 /* 上锁 */
            ret = mpu6050_read_channel_data(indio_dev, chan, val);
            mutex_unlock(&dev->lock);
            return ret;
        case IIO_CHAN_INFO_SCALE:
            switch (chan->type){
                case IIO_ANGL_VEL:
                    mutex_lock(&dev->lock);
                    printk("read gyro scale\r\n");
                    error = i2c_read_mpu6050(dev->client, GYRO_CONFIG, &regdata, 1);  
                    if(error != 0){
                        return -EINVAL;
                    }  
                    regdata = (regdata & 0x18) >>3;  /* 提取陀螺仪量程*/
                    *val = 0;
                    *val2 = gyro_scale_mpu6050[regdata];
                    mutex_unlock(&dev->lock);
                    return IIO_VAL_INT_PLUS_MICRO;   /* 值为val + val2/1000000 */
                case IIO_ACCEL:
                    printk("read accel sacle\r\n");
                    mutex_lock(&dev->lock);
                    error = i2c_read_mpu6050(dev->client, ACCEL_CONFIG, &regdata, 1);  
                    if(error != 0){
                        return -EINVAL;
                    }  
                    regdata = (regdata & 0x18) >>3;  /* 提取陀螺仪量程*/
                    *val = 0;
                    *val2 = accel_scale_mpu6050[regdata];
                    mutex_unlock(&dev->lock);
                    return IIO_VAL_INT_PLUS_NANO;   /* 值为val + val2/1000000000 */
                default:
                    return -EINVAL;
            }
        case IIO_CHAN_INFO_CALIBBIAS:         /*mpu6050 加速度计和陀螺仪校准值 */
            switch (chan->type){
                case IIO_ANGL_VEL:          /*陀螺仪的校准值*/
                    printk("read gyro calibbias \r\n");
                    mutex_lock(&dev->lock);
                    ret = mpu6050_sensor_show(dev, XG_OFFS_USRH ,chan->channel2, val);
                    mutex_unlock(&dev->lock);
                    return ret;
                case IIO_ACCEL:                /* 加速度计的校准值 */
                    printk("read accel calibbias \r\n"); 
                    mutex_lock(&dev->lock);
                    ret = mpu6050_sensor_show(dev, XA_OFFSET_H ,chan->channel2, val);
                    mutex_unlock(&dev->lock);    
                    return ret;
                default:
                    return -EINVAL;
            }
        return -EINVAL;
    }
	return ret;
}

/*
* @description : 设置MPU6050传感器,可用于陀螺仪校准
* @param - dev : mpu6050设备
* @param - reg : 要设置的通道寄存器首地址
* @param - axis :要设置的通道,比如x,y,z
* @param - *val : 要设置的值
* @return     :0,成功;其他值,错误 
*/
static int mpu6050_sensor_set_1( struct mpu6050_dev *dev, 
                                int reg,
                                int axis,
                                int val)
{
    int ind;
    int error=0;
    char data_H;
	char data_L;
    ind = (axis-IIO_MOD_X) * 2;
    data_H = val>>8;
    data_L = val&0xff;
    error = i2c_write_mpu6050(dev->client, reg + ind, data_H);
    error = i2c_write_mpu6050(dev->client, reg + ind + 1, data_L);
    if(error !=0 )
        return  -EINVAL;
    return 0;
}

/*
* @description : 设置MPU6050传感器,可用于加速度计校准
* @param - dev : mpu6050设备
* @param - reg : 要设置的通道寄存器首地址
* @param - axis :要设置的通道,比如x,y,z
* @param - *val : 要设置的值
* @return     :0,成功;其他值,错误 
*/
static int mpu6050_sensor_set_2( struct mpu6050_dev *dev, 
                                int reg,
                                int axis,
                                int val)
{
    int ind;
    int error=0;
    char data_H;
	char data_L;
    ind = (axis-IIO_MOD_X) * 3;
    data_H = val>>8;
    data_L = val&0xff;
    error = i2c_write_mpu6050(dev->client, reg + ind, data_H);
    error = i2c_write_mpu6050(dev->client, reg + ind + 1, data_L);
    if(error !=0 )
        return  -EINVAL;
    return 0;
}

/*
  * @description  	: 设置mpu6050的陀螺仪计量程(分辨率)
  * @param - dev	: icm20608设备
  * @param - val   	: 量程(分辨率值)。
  * @return			: 0,成功;其他值,错误
  */
static int mpu6050_write_gyro_scale(struct mpu6050_dev *dev, int val)
{
	int result, i;
	u8 d;

	for (i = 0; i < ARRAY_SIZE(gyro_scale_mpu6050); ++i) {
		if (gyro_scale_mpu6050[i] == val) {
			d = (i << 3);
			result = i2c_write_mpu6050(dev->client, GYRO_CONFIG, d);
			if (result)
				return result;
			return 0;
		}
	}
	return -EINVAL;
}

/*
  * @description  	: 设置mpu6050的加速度计量程(分辨率)
  * @param - dev	: mpu6050设备
  * @param - val   	: 量程(分辨率值)。
  * @return			: 0,成功;其他值,错误
  */
static int mpu6050_write_accel_scale(struct mpu6050_dev *dev, int val)
{
	int result, i;
	u8 d;

	for (i = 0; i < ARRAY_SIZE(accel_scale_mpu6050); ++i) {
		if (accel_scale_mpu6050[i] == val) {
			d = (i << 3);
            result = i2c_write_mpu6050(dev->client, ACCEL_CONFIG, d);
			if (result)
				return result;
			return 0;
		}
	}
	return -EINVAL;
}

/* @description     	: 写函数,当向sysfs中的文件写数据的时候最终此函数会执行,一般在此函数
  * 					:里面设置传感器,比如量程等。
  * @param - indio_dev	: iio_dev
  * @param - chan   	: 通道
  * @param - val   		: 应用程序写入的值,如果是小数值的话,val是整数部分。
  * @param - val2   	: 应用程序写入的值,如果是小数值的话,val2是小数部分。
  * @param - mask       : 掩码,用于指定我们读取的是什么数据
  * @return				: 0,成功;其他值,错误
  */
static int mpu6050_write_raw(struct iio_dev *indio_dev,
			    struct iio_chan_spec const *chan,
			    int val, int val2, long mask)
{
    int ret = 0;
    struct mpu6050_dev *dev = iio_priv(indio_dev);
    printk("mpu6050_write_raw\r\n");
    switch(mask){
        case IIO_CHAN_INFO_SCALE:      /* 设置陀螺仪和加速度计的分辨率*/
            switch (chan->type){
                case IIO_ANGL_VEL:     /* 设置陀螺仪 */
                    mutex_lock(&dev->lock);
                    ret = mpu6050_write_gyro_scale(dev,val2);
                    mutex_unlock(&dev->lock);
                    break;
                case IIO_ACCEL:       /* 设置加速度计*/
                    mutex_lock(&dev->lock);
                    ret = mpu6050_write_accel_scale(dev,val2);
                    mutex_unlock(&dev->lock);
                    break;
                default:
                    ret = -EINVAL;
                    break;
            }
            break;
        case IIO_CHAN_INFO_CALIBBIAS:   /* 设置陀螺仪和加速度计的校准值 */
            switch (chan->type){
                case IIO_ANGL_VEL:       /* 设置陀螺仪校准值 */
                    mutex_lock(&dev->lock);
                    ret = mpu6050_sensor_set_1(dev, XG_OFFS_USRH, chan->channel2, val);
                    mutex_unlock(&dev->lock);
                    break;
                case IIO_ACCEL:          /* 加速度计校准值 */
                    mutex_lock(&dev->lock);
                    ret = mpu6050_sensor_set_2(dev, XA_OFFSET_H, chan->channel2, val);
                    mutex_unlock(&dev->lock);
                    break;
                default:
                    ret = -EINVAL;
                    break;
            }
            break;
        default: 
            ret = -EINVAL; 
            break;
    }
    return ret;
}

/*
  * @description     	: 用户空间写数据格式,比如我们在用户空间操作sysfs来设置传感器的分辨率,
  * 					:如果分辨率带小数,那么这个小数传递到内核空间应该扩大多少倍,此函数就是
  *						: 用来设置这个的。
  * @param - indio_dev	: iio_dev
  * @param - chan   	: 通道
  * @param - mask   	: 掩码
  * @return				: 0,成功;其他值,错误
  */
static int mpu6050_write_raw_get_fmt(struct iio_dev *indio_dev,
				 struct iio_chan_spec const *chan, long mask)
{
    printk("mpu6050_write_raw_get_fmt\r\n");
    switch (mask){
        case IIO_CHAN_INFO_SCALE:
            switch (chan->type) {
                case IIO_ANGL_VEL:                  /* 用户空间写的陀螺仪分辨率数据要乘以1000000*/
                    return IIO_VAL_INT_PLUS_MICRO;
                default:                           /* 用户空间写的加速度计分辨率数据要乘以1000000000 */
                    return IIO_VAL_INT_PLUS_NANO;
            }
        default:
            return IIO_VAL_INT_PLUS_MICRO;
    }
    return -EINVAL;
}
/*
 * iio_info结构体变量
 */
static const struct iio_info mpu6050_info = {
	.read_raw		= mpu6050_read_raw,
	.write_raw		= mpu6050_write_raw,
	.write_raw_get_fmt = &mpu6050_write_raw_get_fmt,	/* 用户空间写数据格式 */
};

/*----------------平台驱动函数集-----------------*/
static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret;
    struct mpu6050_dev *dev;
    struct iio_dev *indio_dev;

    /* 1、申请iio_dev内存*/
    indio_dev = devm_iio_device_alloc(&client->dev,sizeof(*dev));

    /* 2、获取mpu6050结构体地址*/
    dev = iio_priv(indio_dev);
    dev->client =client;
    i2c_set_clientdata(client, indio_dev);    /*保存indio_dev数据至i2c_client*/
    mutex_init(&dev->lock);
  

    /* 3、iio_dev的其他成员变量初始化*/
    indio_dev->dev.parent = &client->dev;
    indio_dev->info = &mpu6050_info;   /*驱动开发人员编写,从用户空间读取IIO设备内部数据,最终调用的就是iio_info里面的函数*/
    indio_dev->name = MPU6050_NAME; 
    indio_dev->modes = INDIO_DIRECT_MODE;  /*直接模式,提供sysfs接口*/
    indio_dev->channels = mpu6050_channels;
    indio_dev->num_channels = ARRAY_SIZE(mpu6050_channels);

    /*  4、注册iio_dev*/
    ret = iio_device_register(indio_dev);
    if (ret <0){
        dev_err(&client->dev, "iio_device_register failed \n");
        goto err_iio_register;
    }
    mpu6050_init(dev);             /*初始化MPU6050*/
    printk("iio_device_register successfully\r\n");
    return 0;
err_iio_register:
    return ret;
}


static int mpu6050_remove(struct i2c_client *client)
{
	struct iio_dev *indio_dev = i2c_get_clientdata(client);
	struct ap3216c_dev *dev;
	
	dev = iio_priv(indio_dev);

	/* 2、注销IIO */
	iio_device_unregister(indio_dev);
	return 0;
}



/*定义ID 匹配表*/
static const struct i2c_device_id gtp_device_id[] = {
	{"kun,i2c_mpu6050", 0},
	{}};

/*定义设备树匹配表*/
static const struct of_device_id mpu6050_of_match_table[] = {
	{.compatible = "kun,i2c_mpu6050"},
	{/* sentinel */}};

/*定义i2c总线设备结构体*/
struct i2c_driver mpu6050_driver = {
	.probe = mpu6050_probe,
	.remove = mpu6050_remove,
	.id_table = gtp_device_id,
	.driver = {
		.name = "kun,i2c_mpu6050",
		.owner = THIS_MODULE,
		.of_match_table = mpu6050_of_match_table,
	},
};

/*
*驱动初始化函数
*/
static int __init mpu6050_driver_init(void)
{
	int ret;
	pr_info("mpu6050_driver_init\n");
	ret = i2c_add_driver(&mpu6050_driver);
	return ret;
}

/*
*驱动注销函数
*/
static void __exit mpu6050_driver_exit(void)
{
	pr_info("mpu6050_driver_exit\n");
	i2c_del_driver(&mpu6050_driver);
}

module_init(mpu6050_driver_init);
module_exit(mpu6050_driver_exit);

MODULE_LICENSE("GPL");

mpu6050.h

c 复制代码
#ifndef MPU6050_H
#define MPU6050_H


//宏定义
/* 陀螺仪静态偏移 */
#define	XG_OFFS_USRH			                    0x13
#define	XG_OFFS_USRL			                    0x14
#define	YG_OFFS_USRH			                    0x15
#define	YG_OFFS_USRL			                    0x16
#define	ZG_OFFS_USRH			                    0x17
#define	ZG_OFFS_USRL			                    0x18

#define SMPLRT_DIV                                  0x19
#define CONFIG                                      0x1A
#define GYRO_CONFIG                                 0x1B
#define ACCEL_CONFIG                                0x1C
#define ACCEL_CONFIG2                               0x1D
#define LP_MODE_CFG                                 0x1E
#define INT_ENABLE                                  0x38
#define ACCEL_XOUT_H                                0x3B
#define ACCEL_XOUT_L                                0x3C
#define ACCEL_YOUT_H                                0x3D
#define ACCEL_YOUT_L                                0x3E
#define ACCEL_ZOUT_H                                0x3F
#define ACCEL_ZOUT_L                                0x40
#define TEMP_OUT_H                                  0x41
#define TEMP_OUT_L                                  0x42
#define GYRO_XOUT_H                                 0x43
#define GYRO_XOUT_L                                 0x44
#define GYRO_YOUT_H                                 0x45
#define GYRO_YOUT_L                                 0x46
#define GYRO_ZOUT_H                                 0x47
#define GYRO_ZOUT_L                                 0x48
#define PWR_MGMT_1                                  0x6B
#define PWR_MGMT_2                                  0x6C
#define WHO_AM_I                                    0x75

/*加速度静态偏移*/
#define XA_OFFSET_H                                 0x77
#define XA_OFFSET_L                                 0x78
#define	YA_OFFSET_H			                        0x7A
#define	YA_OFFSET_L			                        0x7B
#define	ZA_OFFSET_H			                        0x7D
#define	ZA_OFFSET_L 			                    0x7E

#define SlaveAddress                                0xD0
#define Address                                     0x68                  //MPU6050地址
#define I2C_RETRIES                                 0x0701
#define I2C_TIMEOUT                                 0x0702
#define I2C_SLAVE                                   0x0703       //IIC从器件的地址设置
#define I2C_BUS_MODE                                0x0780


#endif

mpu6050App.c

c 复制代码
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名		: icm20608.c
作者	  	: 左忠凯
版本	   	: V1.0
描述	   	: icm20608设备iio框架测试程序。
其他	   	: 无
使用方法	 :./icm20608App 
论坛 	   	: www.openedv.com
日志	   	: 初版V1.0 2021/8/17 左忠凯创建
***************************************************************/
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>

/* 字符串转数字,将浮点小数字符串转换为浮点数数值 */
#define SENSOR_FLOAT_DATA_GET(ret, index, str, member)\
	ret = file_data_read(file_path[index], str);\
	dev->member = atof(str);\
	
/* 字符串转数字,将整数字符串转换为整数数值 */
#define SENSOR_INT_DATA_GET(ret, index, str, member)\
	ret = file_data_read(file_path[index], str);\
	dev->member = atoi(str);\

/* icm20608 iio框架对应的文件路径 */
static char *file_path[] = {
	"/sys/bus/iio/devices/iio:device0/in_accel_scale",
	"/sys/bus/iio/devices/iio:device0/in_accel_x_calibbias",
	"/sys/bus/iio/devices/iio:device0/in_accel_x_raw",
	"/sys/bus/iio/devices/iio:device0/in_accel_y_calibbias",
	"/sys/bus/iio/devices/iio:device0/in_accel_y_raw",
	"/sys/bus/iio/devices/iio:device0/in_accel_z_calibbias",
	"/sys/bus/iio/devices/iio:device0/in_accel_z_raw",
	"/sys/bus/iio/devices/iio:device0/in_anglvel_scale",
	"/sys/bus/iio/devices/iio:device0/in_anglvel_x_calibbias",
	"/sys/bus/iio/devices/iio:device0/in_anglvel_x_raw",
	"/sys/bus/iio/devices/iio:device0/in_anglvel_y_calibbias",
	"/sys/bus/iio/devices/iio:device0/in_anglvel_y_raw",
	"/sys/bus/iio/devices/iio:device0/in_anglvel_z_calibbias",
	"/sys/bus/iio/devices/iio:device0/in_anglvel_z_raw",
};

/* 文件路径索引,要和file_path里面的文件顺序对应 */
enum path_index {
	IN_ACCEL_SCALE = 0,
	IN_ACCEL_X_CALIBBIAS,
	IN_ACCEL_X_RAW,
	IN_ACCEL_Y_CALIBBIAS,
	IN_ACCEL_Y_RAW,
	IN_ACCEL_Z_CALIBBIAS,
	IN_ACCEL_Z_RAW,
	IN_ANGLVEL_SCALE,
	IN_ANGLVEL_X_CALIBBIAS,
	IN_ANGLVEL_X_RAW,
	IN_ANGLVEL_Y_CALIBBIAS,
	IN_ANGLVEL_Y_RAW,
	IN_ANGLVEL_Z_CALIBBIAS,
	IN_ANGLVEL_Z_RAW,
};

/*
 * icm20608数据设备结构体
 */
struct icm20608_dev{
	int accel_x_calibbias, accel_y_calibbias, accel_z_calibbias;
	int accel_x_raw, accel_y_raw, accel_z_raw;

	int gyro_x_calibbias, gyro_y_calibbias, gyro_z_calibbias;
	int gyro_x_raw, gyro_y_raw, gyro_z_raw;


	float accel_scale, gyro_scale, temp_scale;

	float gyro_x_act, gyro_y_act, gyro_z_act;
	float accel_x_act, accel_y_act, accel_z_act;
};

struct icm20608_dev icm20608;

 /*
 * @description			: 读取指定文件内容
 * @param - filename 	: 要读取的文件路径
 * @param - str 		: 读取到的文件字符串
 * @return 				: 0 成功;其他 失败
 */
static int file_data_read(char *filename, char *str)
{
	int ret = 0;
	FILE *data_stream;

    data_stream = fopen(filename, "r"); /* 只读打开 */
    if(data_stream == NULL) {
		printf("can't open file %s\r\n", filename);
		return -1;
	}

	ret = fscanf(data_stream, "%s", str);
    if(!ret) {
        printf("file read error!\r\n");
    } else if(ret == EOF) {
        /* 读到文件末尾的话将文件指针重新调整到文件头 */
        fseek(data_stream, 0, SEEK_SET);  
    }
	fclose(data_stream);	/* 关闭文件 */	
	return 0;
}

 /*
 * @description	: 获取ICM20608数据
 * @param - dev : 设备结构体
 * @return 		: 0 成功;其他 失败
 */
static int sensor_read(struct icm20608_dev *dev)
{
	int ret = 0;
	char str[50];

	/* 1、获取陀螺仪原始数据 */
	SENSOR_FLOAT_DATA_GET(ret, IN_ANGLVEL_SCALE, str, gyro_scale);
	SENSOR_INT_DATA_GET(ret, IN_ANGLVEL_X_RAW, str, gyro_x_raw);
	SENSOR_INT_DATA_GET(ret, IN_ANGLVEL_Y_RAW, str, gyro_y_raw);
	SENSOR_INT_DATA_GET(ret, IN_ANGLVEL_Z_RAW, str, gyro_z_raw);

	/* 2、获取加速度计原始数据 */
	SENSOR_FLOAT_DATA_GET(ret, IN_ACCEL_SCALE, str, accel_scale);
	SENSOR_INT_DATA_GET(ret, IN_ACCEL_X_RAW, str, accel_x_raw);
	SENSOR_INT_DATA_GET(ret, IN_ACCEL_Y_RAW, str, accel_y_raw);
	SENSOR_INT_DATA_GET(ret, IN_ACCEL_Z_RAW, str, accel_z_raw);


	/* 3、转换为实际数值 */
	dev->accel_x_act = dev->accel_x_raw * dev->accel_scale;
	dev->accel_y_act = dev->accel_y_raw * dev->accel_scale;
	dev->accel_z_act = dev->accel_z_raw * dev->accel_scale;

	dev->gyro_x_act = dev->gyro_x_raw * dev->gyro_scale;
	dev->gyro_y_act = dev->gyro_y_raw * dev->gyro_scale;
	dev->gyro_z_act = dev->gyro_z_raw * dev->gyro_scale;

	return ret;
}

/*
 * @description		: main主程序
 * @param - argc 	: argv数组元素个数
 * @param - argv 	: 具体参数
 * @return 			: 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
	int ret = 0;

	if (argc != 1) {
		printf("Error Usage!\r\n");
		return -1;
	}

	while (1) {
		ret = sensor_read(&icm20608);
		if(ret == 0) { 			/* 数据读取成功 */
			printf("\r\n原始值:\r\n");
			printf("gx = %d, gy = %d, gz = %d\r\n", icm20608.gyro_x_raw, icm20608.gyro_y_raw, icm20608.gyro_z_raw);
			printf("ax = %d, ay = %d, az = %d\r\n", icm20608.accel_x_raw, icm20608.accel_y_raw, icm20608.accel_z_raw);
			printf("实际值:");
			printf("act gx = %.2f°/S, act gy = %.2f°/S, act gz = %.2f°/S\r\n", icm20608.gyro_x_act, icm20608.gyro_y_act, icm20608.gyro_z_act);
			printf("act ax = %.2fg, act ay = %.2fg, act az = %.2fg\r\n", icm20608.accel_x_act, icm20608.accel_y_act, icm20608.accel_z_act);
		}
		usleep(100000); /*100ms */
	}

	return 0;
}

文件下载地址:https://download.csdn.net/download/weixin_42963900/88606223

相关推荐
2035去旅行2 小时前
bootcmd 详细讲解
linux·嵌入式·arm·soc
陈希1233 小时前
Linux 防火墙配置实战:firewalld、iptables 与云安全组
linux·运维·服务器
女神下凡4 小时前
芯参谋(95):嵌入式文件系统_开发指南
linux·服务器·arm开发·驱动开发·设计规范
且从容.7 小时前
Ubuntu安装flume
linux·ubuntu·flume
承渊政道7 小时前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
且从容.10 小时前
ubuntu安装flink
linux·ubuntu·flink
爱和冰阔落12 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
程序员沉梦听雨12 小时前
WSL2的安装与使用
linux·wsl
微小的鱼12 小时前
Linux的渲染与显示系统链路
android·java·linux
lisanmengmeng13 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器