树莓派4B iio子系统 mpu6050

编写基于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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大模型发展对教育领域的巨大影响

摘要&#xff1a; 教育是一个复杂而微妙的领域;有效的教学涉及对学生认知的推理&#xff0c;并应反映学生的学习目标。基础模型的性质在这里提出了在人工智能教育领域尚未实现的承诺&#xff1a;虽然教育中的某些许多数据流单独地过于有限&#xff0c;无法训练基础模型&#xf…

【linux系统编程】编辑器gcc/g++

目录 Linux下的编辑器 介绍&#xff1a; 1&#xff0c;编辑器gcc/g 1-1&#xff0c;系统的编译过程 1-2&#xff0c;预处理过程 1-3&#xff0c;编译过程 1-4&#xff0c;汇编过程 1-5&#xff0c;链接过程 Linux下的编辑器 介绍&#xff1a; Linux系统下可支持很多高…

祝大雪节气安康,大雪动态表情包图片带字祝福大全,大雪快乐暖心问候祝福语

1、大雪节气&#xff0c;送你防寒秘笈&#xff1a;1、天寒地冻防路滑;2、寒风呼啸防感冒;3、寒气袭人防哮喘;4、戴上耳套防冻耳;5、戴上手套防冻手;6、穿上棉鞋防冻脚;7、多喝开水防上火。8、加强锻炼防疾患。祝健康快乐。 2、奉天承运&#xff0c;皇帝诏曰&#xff1a;大雪节气…

STM32CubeMx+MATLAB Simulink串口输出实验

STM32CubeMxMATLAB Simulink串口输出实验 &#x1f4cc;《STM32CubeMxMATLAB Simulink点灯程序》&#x1f4cd;相关篇《MATLAB Simulink STM32硬件在环 &#xff08;HIL&#xff09;实现例程测试》&#x1f516;需要的软件支持包&#xff1a;Embedded Coder Support Package fo…

Spingboot 之spring-boot-starter-parent与spring-boot-dependencies区分

在创建spring boot工程时&#xff0c;spring-boot-starter-parent 和 spring-boot-dependencies是二选一的关系&#xff0c;在pom中引入其中一个就可以了。 那么什么时候用spring-boot-starter-parent 和 spring-boot-dependencies呢&#xff1f;从字面名称上看&#xff0c;如…

「Verilog学习笔记」根据状态转移写状态机-二段式

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 和三段式相比&#xff0c;就是将输出块和次态切换块合并。 timescale 1ns/1nsmodule fsm2(input wire clk ,input wire rst ,input wire data ,output reg flag );//****…

利器|一款集成的BurpSuite漏洞探测插件

本着市面上各大漏洞探测插件的功能比较单一&#xff0c;因此与TsojanSecTeam成员决定在已有框架的基础上修改并增加常用的漏洞探测POC&#xff0c;它会以最少的数据包请求来准确检测各漏洞存在与否&#xff0c;你只需要这一个足矣。 1、加载插件 2、功能介绍 &#xff08;1&a…

『VUE3后台—硅谷甄选』

一、准备前期 pnpm create vite

计算机操作系统3

1.虚拟机 VM 两类虚拟机的对比&#xff1a; 2.进程 进程的特征&#xff1a; 进程状态的转换&#xff08;五大状态&#xff09; 3.进程控制原语的作用 4.线程 ​​​​​线程的属性 实现方式 5.调度算法的评价指标

python-sql-spark常用操作

数据抽取提速&#xff1a; 1. 不要把rdd或者df展示出来&#xff0c;只有第一遍跑流程的时候看看中间结构&#xff0c;后面就只保存不展示。 2. 尽量使用spark.sql&#xff0c;而不是rdd。sql处理groupby会快很多。基本上10min的rdd&#xff0c;sql只需2min。所以基本除了复杂…

深度探索Linux操作系统 —— 构建内核

系列文章目录 深度探索Linux操作系统 —— 编译过程分析 深度探索Linux操作系统 —— 构建工具链 深度探索Linux操作系统 —— 构建内核 文章目录 系列文章目录前言一、内核映像的组成 前言 内核的构建系统 kbuild 基于GNU Make&#xff0c;是一套非常复杂的系统。 对于编译内核…

用 C 写一个卷积神经网络

用 C 写一个卷积神经网络 深度学习领域最近发展很快&#xff0c;前一段时间读transformer论文《Attention Is All You Need》时&#xff0c;被一些神经网络和深度学习的概念搞得云里雾里&#xff0c;其实也根本没读懂。发现深度学习和传统的软件开发工程领域的差别挺大&#xf…

19、XSS——HTTP协议安全

文章目录 一、Weak Session IDs(弱会话IDs)二、HTTP协议存在的安全问题三、HTTPS协议3.1 HTTP和HTTPS的区别3.2 SSL协议组成 一、Weak Session IDs(弱会话IDs) 当用户登录后&#xff0c;在服务器就会创建一个会话&#xff08;Session&#xff09;&#xff0c;叫做会话控制&…

tomcat配置管理员And配置访问静态资源

配置管理员 打开 tomcat\conf\tomcat-users.xml <tomcat-users xmlns"http://tomcat.apache.org/xml"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://tomcat.apache.org/xml tomcat-users.xsd"version&qu…

openai 1.3.x 版本 openai.APITimeoutError: Request timed out. 解决

问题描述 openai 1.3.x 版本 请求出现 Request timed out File "E:\Python\Python312\Lib\site-packages\openai\_base_client.py", line 920, in _request return self._retry_request( ^^^^^^^^^^^^^^^^^^^^ File "E:\Python\Python312\L…

python爬虫零基础学习之简单流程示例

文章目录 爬虫基础爬虫流程常用库爬虫示例关于Python爬虫技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小游戏源码五、面试资料六、Python兼职渠道 爬虫基础 网络爬…

微信小程序动态加载图表[echart]

1.引入Echarts &#xff08;1&#xff09;将ec-canvas文件拷贝下来放到你自己的项目中&#xff1a; &#xff08;2&#xff09;在你需要使用Echarts的页面的json文件中引入Echarts "usingComponents": {"ec-canvas": "../utils/ec-canvas/ec-canva…

STM32——PWM介绍

STM32F103C8T6 PWM资源&#xff1a; 高级定时器&#xff08;TIM1&#xff09;&#xff1a;7路 通用定时器&#xff08;TIM2~TIM4&#xff09;&#xff1a;各4路 PWM输出模式&#xff1a; PWM模式1&#xff1a;在向上计数时&#xff0c;一旦 CNT < CCRx 时输出为有效电平&…

基于Eclipse+Mysql+Servlet开发的学生信息管理系统

基于EclipseMysqlServlet开发的学生信息管理系统 项目介绍&#x1f481;&#x1f3fb; 随着信息技术的不断发展&#xff0c;学校管理学生信息的方式也在不断改进。传统的手工管理方式已经无法满足现代学校对信息管理的需求&#xff0c;因此开发一套基于EclipseMysql的学生信息管…

C#基础学习--命名空间和程序集

引用其他程序集 编译器接受源代码文件并生成一个名为程序集的输出文件。 在许多项目中&#xff0c;会想使用来自其他程序集的类或类型。这些程序集可能来自BCL或第三方供应商&#xff0c;或者自己创建的。这些程序集称为类库&#xff0c;而且它们的程序集文件的名称通常以dll…