树莓派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 0int 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.hqwc.cn/news/257264.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RAG应用程序的12种调优策略:使用“超参数”和策略优化来提高检索性能

本文从数据科学家的角度来研究检索增强生成(retrieve - augmented Generation, RAG)管道。讨论潜在的“超参数”&#xff0c;这些参数都可以通过实验来提高RAG管道的性能。与本文还将介绍可以应用的不同策略&#xff0c;这些策略虽然不是超参数&#xff0c;但对性能也会产生很大…

看图学源码之 CopyOnWriteArrayList 源码分析

基本简介&#xff1a; 是Java中的一个线程安全的List实现&#xff0c;也是ArrayList 的安全版本&#xff0c;所以就不会有ArrayList 的并发修改异常 的问题产生了 原理 每次在对 List 进行修改时&#xff0c;创建一个新的副本&#xff08;即拷贝&#xff09;&#xff0c;而不…

web:[GXYCTF2019]BabyUpload(文件上传、一句话木马、文件过滤)

题目 页面显示为文件上传 随便上传一个文件看看 上传一个文本文件显示 上传了一个图片显示 上传包含一句话木马的图片 上传了一个包含php一句话木马的文件&#xff0c;显示如上 换一个写法 上传成功 尝试上传.htaccess&#xff0c;上传失败&#xff0c;用抓包修改文件后缀 …

Open-Falcon(一)环境配置

目录 ip划分一、主机准备二、环境配置2.1修改主机名、修改hosts文件2.2配置阿里源&#xff0c;安装工具2.3关闭防火墙、selinux2.4配置时间2.5安装go2.6安装redis2.7 安装mysql初始化MySQL表结构 ip划分 主机名IP服务open-faclon-server192.168.150.200open-faclon-serverngin…

【Python】Faker库详解:创建测试数据轻而易举

Python Faker库详解&#xff1a;创建测试数据轻而易举 在软件开发和测试过程中&#xff0c;通常需要大量的测试数据来模拟真实环境。Python的Faker库为开发者提供了一个方便、灵活且强大的工具&#xff0c;用于生成各种虚构数据。本文将深入介绍Faker库&#xff0c;演示其基本…

基于ssm人事管理信息系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本人事管理信息系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息…

优化系统性能:深入性能测试的重要性与最佳实践

目录 引言 1. 为什么性能测试重要&#xff1f; 1.1 用户体验 1.2 系统稳定性 1.3 成本节约 1.4 品牌声誉 2. 性能测试的关键步骤 2.1 制定性能测试计划 2.2 确定性能测试类型 2.3 设计性能测试用例 2.4 配置性能测试环境 2.5 执行性能测试 2.6 分析和优化 2.7 回…

编程实战:自己编写HTTP服务器(系列3:处理框架)

系列入口&#xff1a;编程实战&#xff1a;自己编写HTTP服务器&#xff08;系列1&#xff1a;概述和应答&#xff09;-CSDN博客 本文介绍处理框架。 一、框架概述 处理框架针对的是一个连接&#xff0c;里面用了循环&#xff0c;支持HTTP1.1&#xff0c;如果不循环就是1.0了&am…

Spring 依赖注入的三种方式优缺点

小王学习录 前言属性注入1. 属性注入的优点2. 属性注入的缺点 Setter注入Setter注入的优点Setter注入的缺点 构造方法注入1. 构造方法的优点 总结补充Aurowired注解和Resource注解的区别 前言 在前面的文章中介绍了基于注解的方式将Bean存储到Spring中, 接下来介绍如何基于注解…

什么是https加密协议,相比http的好处在哪?

先了解什么是http HTTP&#xff08;Hypertext Transfer Protocol&#xff09;是一种用于在计算机网络上传输超文本的应用层协议。它是一种无状态的、无连接的协议&#xff0c;通常用于在Web浏览器和服务器之间传输HTML页面、图片、音频、视频以及其他数据资源。 以下是HTTP的…

光伏项目开发的步骤

光伏项目开发是一种将太阳能转化为电能的过程&#xff0c;它涉及到多个步骤和因素。下面将详细介绍光伏项目开发的步骤。 一、项目选址 选择合适的场地是光伏项目开发的第一步。选址时要考虑太阳辐射强度、地理位置、地形和气候等因素。通常来说&#xff0c;阳光充足、遮挡物少…

docker镜像仓库hub.docker.com无法访问

docker镜像仓库hub.docker.com无法访问 文章主要内容&#xff1a; 介绍dockerhub为什么无法访问解决办法 1 介绍dockerhub为什么无法访问 最近许多群友都询问为什么无法访问Docker镜像仓库&#xff0c;于是我也尝试去访问&#xff0c;结果果然无法访问。 大家的第一反应就是…