树莓派4B iio子系统 mpu6050

news2024/11/25 19:38:43

编写基于iio的mpu6050

遇到的问题,在读取数据时,读出来的数据不能直接拼接成int类型
在这里插入图片描述
需要先将其转换成short int,再转换成int
在这里插入图片描述
在这里插入图片描述

效果如图所示
在这里插入图片描述
注:驱动是使用的modprobe加载的

画的思维导图(部分,上传的文件中有完整的)
在这里插入图片描述
设备树修改部分:
在这里插入图片描述

参考资料:正点原子 I.MX6U嵌入式linux驱动开发指南
mpu6050.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


#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

/***************************************************************
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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1292226.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

预付费远传水表和传统水表有什么不同?

随着科技的发展&#xff0c;预付费远传水表作为一种新型智能水表&#xff0c;与传统水表相比有着许多不同之处。那么&#xff0c;预付费远传水表和传统水表究竟有什么不同呢&#xff1f; 首先&#xff0c;预付费远传水表具备智能化功能。与传统水表只能记录用水总量不同&#x…

代码随想录算法训练营第五十七天【动态规划part17】 | 647. 回文子串、516.最长回文子序列

647. 回文子串 题目链接 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 求解思路 动规五部曲 1.确定dp数组及其下标含义 布尔类型的dp[i][j]&#xff1a;表示区间范围[i,j] &#xff08;注意是左闭右闭&#xff09;的子串是否是回文子串&#…

springboot 整合 Spring Security 中篇(RBAC权限控制)

1.先了解RBAC 是什么 RBAC(Role-Based Access control) &#xff0c;也就是基于角色的权限分配解决方案 2.数据库读取用户信息和授权信息 1.上篇用户名好授权等信息都是从内存读取实际情况都是从数据库获取&#xff1b; 主要设计两个类 UserDetails和UserDetailsService 看下…

linux高级篇基础理论七(Tomcat)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️不能因为人生的道路坎坷,就使自己的身躯变得弯曲;不能因为生活的历程漫长,就使求索的 脚步迟缓。 ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xff1a;云计算技…

主食罐头哪个牌子好?猫主食罐头品牌盘点

养猫的这几年德罐也买了不少了&#xff0c;很早以前德罐给我的感觉就是&#xff0c;物美价廉&#xff0c;而且质量保障也不错&#xff0c;很美丽。但最近的德罐恕在下高攀不起了。 猫罐头侠登场&#xff01;养猫这么久了我就把我吃的不错的猫罐头分享一下&#xff01;别纠结了…

Dockerfile 指令的最佳实践

这些建议旨在帮助您创建一个高效且可维护的Dockerfile。 一、FROM 尽可能使用当前的官方镜像作为镜像的基础。Docker推荐Alpine镜像&#xff0c;因为它受到严格控制&#xff0c;体积小&#xff08;目前不到6 MB&#xff09;&#xff0c;同时仍然是一个完整的Linux发行版。 FR…

【FPGA】Quartus18.1打包封装网表文件(.qxp)详细教程

当我们在做项目的过程中&#xff0c;编写的底层Verilog代码不想交给甲方时怎么办呢&#xff1f;此时可以将源代码打包封装成网表文件&#xff08;.qxp&#xff09;进行加密&#xff0c;并且在工程中进行调用。 Quartus II的.qxp文件为QuartusII Exported Partition&#xff0c;…

马来西亚虾皮选品工具:如何优化您的电商业务

随着电子商务的快速发展&#xff0c;越来越多的商家开始将目光投向在线市场。在马来西亚&#xff0c;虾皮&#xff08;Shopee&#xff09;平台成为了一个备受瞩目的电商平台&#xff0c;吸引了大量的商家和消费者。然而&#xff0c;要在这个竞争激烈的市场中脱颖而出并取得成功…

基于JavaSE+JDBC使用控制台操作的简易购物系统【源码+数据库】

1、项目简介 本项目是一套基于JavaSEJDBC使用控制台操作的简易购物系统&#xff0c;主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目可以直接作为bishe使用。 项目都经过严格调试&…

计算n的阶乘-递归与迭代之间的相爱相杀

n的阶乘是指从1连乘到n的结果&#xff0c;通常用符号n!表示。例如&#xff0c;3的阶乘表示为3!&#xff0c;计算过程如下&#xff1a; 3! 3 2 1 6 一般地&#xff0c;n的阶乘可以用递归或迭代的方式计算&#xff0c;公式为&#xff1a; n! n (n-1) (n-2) ... 2 1 …

UEM 在企业 IT 管理数字化转型有什么帮助

近年大多数公司都在努力实现数字化转型&#xff0c;业务应用程序正在迁移到云端&#xff0c;日常 IT 运营正变得更加面向移动化&#xff0c;高管们使用各种设备。员工不仅使用公司提供的台式机&#xff0c;还经常使用公司拥有的、个人启用的&#xff08;COPE&#xff09;笔记本…

浅析AI智能视频监控技术在城市交通中的作用及意义

城市交通作为整个城市的整体脉络&#xff0c;每天都发挥着重要作用&#xff0c;为了最大程度地避免城市交通堵塞、提高城市交通效率&#xff0c;智能视频监控系统发挥了重要作用。具体表现在以下几个方面&#xff1a; 1、交通违规监管&#xff1a;TSINGSEE青犀智能视频监控系统…

LeetCode刷题--- 计算布尔二叉树的值

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏&#xff1a;http://t.csdnimg.cn/ZxuNL http://t.csdnimg.cn/c9twt 前言&#xff1a;这个专栏主要讲述递归递归、搜索与回溯算法&#xff0c;所以下面题目主要也是这些算法做的 我讲述…

反钓鱼防盗号,共筑校园安全防线!Coremail出席CERNET学术年会

11月27日-30日&#xff0c;中国教育和科研计算机网CERNET第二十八/二十九届学术年会在福州隆重举办&#xff0c;Coremail受邀出席&#xff0c;就高校数字化及网络安全等相关话题与高校老师、行业专家进行广泛交流。 △11月27-30日&#xff0c;Coremail在会场设展&#xff0c;为…

Vue实现注册页面的用户交互

&#x1f4d1;前言 本文主要是【Vue】——Vue实现注册页面的用户交互的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每…

CRM客户管理系统,不止管理客户。

CRM系统现在已经成为企业与客户建立良好关系、提高销售业绩的优先选择。关于CRM的功能&#xff0c;不同的企业包括CRM软件厂商都对CRM系统有不同的定义。基于此&#xff0c;我们来聊聊CRM客户管理系统除了管客户还有什么功能&#xff1f; 1、客户管理 有些企业管理客户的方式…

【互斥锁不当使用导致的条件竞争】2021_DiceCTF_hashbrown

前言 这个题目还挺有意思的&#xff0c;他并不像之前做的题目直接给你一个贴脸的 UAF 等&#xff0c;而是把 UAF 放在了条件竞争的环境下&#xff0c;其实条件竞争这个漏洞在内核中经常出现。 这里题目没有去符号&#xff0c;所以逆向的难度不是很大&#xff0c;但作者似乎在…

【Axure教程】树筛选中继器表格

树和表格是信息系统中两个重要的元件&#xff0c;树结构是一种层次化的数据结构&#xff0c;它以树的形式展示数据的层次关系&#xff1b;表格是一种二维结构&#xff0c;由行和列组成。每一行表示一个记录&#xff0c;每一列表示一个属性。在实际应用中&#xff0c;这两种结构…

陈睿接手一年后,B站全力一搏的游戏业务怎样了

11月末&#xff0c;哔哩哔哩公布了截至2023年9月30日的第三季度财报。 就在去年的这个时候&#xff0c;陈睿宣布亲自接手了B站的游戏业务。因为做游戏比给游戏打广告利润高&#xff0c;因为自研游戏利润更高&#xff0c;更因为年年亏损的B站需要这么高利润的业务来拯救。 但一…

Python文件操作(txt + xls + json)

文章目录 简介1、使用with_open读取和保存&#xff1a;.txt .bin&#xff08;二进制文本&#xff09;1.1、with open语句详解1.1、项目实战 2、使用pandas读取和保存&#xff1a;.xls .xlsx2.1、pandas简介2.2、环境配置2.3、项目实战 3、 使用json.dump读取和保存&#xff1…