树莓派4B iio子系统 mpu6050
2023-12-14 17:35:41
编写基于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, ®data, 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, ®data, 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
文章来源:https://blog.csdn.net/weixin_42963900/article/details/134799741
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!