贴个IIC的代码和MPU6050寄存器地址的文档(MOVE版)

Posted eternal-wisdom

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了贴个IIC的代码和MPU6050寄存器地址的文档(MOVE版)相关的知识,希望对你有一定的参考价值。

IIC代码:

里面的UV_Delay()那几个要自己定义一下。还有那几个子函数也要自己定义在一个头文件里面。比如:

#ifndef        _IIC_H
#define       _IIC_H

#define       UV_Delay()            delay5us()       
#define       UV_SDA_SET()       P2^0 = 1
#define       UV_SDA_RESET()   P2^0 = 0
#define       UV_SCL_SET()        P2^1 = 1 
#define       UV_SCL_RESET()    P2^1 = 0

//void Fasong_data(unsigned char DevAddress, unsigned char RegAddress, unsigned char Massageess);
//char Jieshou_data(unsigned char DevAddress, unsigned char RegAddress);
void IIC_Start();
void IIC_Stop();
void UV_SCL_single_clock();
unsigned char IIC_ACKme();
void IIC_ACKher(unsigned char MyAnswer)
void IIC_Sent_iBit(unsigned short i, unsigned short store);
unsigned short IIC_Rcev_iBit(unsigned short i)

#endif

 

/*
UV_SDA_SET()
UV_SDA_RESET()
UV_SCL_SET()
UV_SCL_RESET()
UV_Delay()
*/

/**
  *\\filename    IIC communication protocol example\\IIC通信协议举例
  *\\author
  *\\version        1.0.1
  *\\date        forgeted
  *\\brief        This is a simple example for IIC communication protocol and save as
  *            .txt format, to be easy to move.
  *            \\这是一个简单的IIC通信协议的例子,保存为txt格式以便于搬运。
  *    functions:
  *            IIC_Start()        \\\\起始IIC信号
  *            IIC_Stop()        \\\\终止IIC信号
  *            UV_SCL_single_clock()        \\\\时钟线SCL产生一个脉冲的功能
  *            IIC_ACKme()        \\\\她回答我
  *            IIC_ACKher(unsigned char MyAnswer)        \\\\我回答她
  *            IIC_Sent_iBit(unsigned short i, unsigned short store)        \\\\发送i个比特\\\\这两个还可以优化一下发送缓冲区
  *            IIC_Rcev_iBit(unsigned short i)        \\\\接收i个比特
  *            
  */

#define is       ==
#define Yes      1

/***********************************************************************************************
void Fasong_data(unsigned char DevAddress, unsigned char RegAddress, unsigned char Massageess)

    IIC_Start();
    IIC_Sent_iBit(8, DevAddress);
    IIC_ACKme();
    IIC_Sent_iBit(8, RegAddress);
    IIC_ACKme();
    IIC_Sent_iBit(8, Massageess);
    IIC_ACKme();
    IIC_Stop();


char Jieshou_data(unsigned char DevAddress, unsigned char RegAddress)

    uint8_t The_Massage_I_Recived_Just_Now;
    IIC_Start();
    IIC_Sent_iBit(8, DevAddress);
    IIC_ACKme();
    IIC_Sent_iBit(8, RegAddress);
    IIC_ACKme();
    IIC_Start();
    IIC_Sent_iBit(8, DevAddress+1);
    IIC_ACKme();
    The_Massage_I_Recived_Just_Now = IIC_Rcev_iBit(8);
    IIC_ACKher(1);
    IIC_Stop();
    return The_Massage_I_Recived_Just_Now;

*************************************************************************************************/
/*************************************************************************************************
For example:
    #define MPU6050      0xD0
    #define WHO_AM_I      0x75
    #define PWR_MGMT_1  0x6B
                  \\\\比如发送个 0x00⬇
    Fasong_data(MPU6050, PWR_MGMT_1, 0x00);
                  \\\\接收的数据放到The_Data_I_Recived
    unsigned char The_Data_I_Recived;
                       \\\\设备地址⬇        ⬇设备中WHO_AM_I寄存器的地址
    The_Data_I_Recived = Jieshou_data(MPU6050, WHO_AM_I);
*************************************************************************************************/




void IIC_Start()//IIC protocol start signal

    UV_SDA_SET();//Set SDA line to high level
    UV_SCL_SET();//Set SCL line to high level
    UV_Delay();//Wait a minute
    UV_SDA_RESET();//SDA line falling to low level when SCL line is high level
    UV_Delay();//Wait a minute
    UV_SCL_RESET();//And SCL line also falling to low level
    UV_Delay();//Wait minute


void IIC_Stop()//IIC protocol stop signal

    UV_SDA_RESET();//Make sure that SDA line is low level so that SDA line is stop state
    UV_SCL_SET();//Rase the SCL line prepare for stop SCL line state
    UV_Delay();//Wait a minute
    UV_SDA_SET();//Rasing for stop this transmission
    UV_Delay();//Wait a minute


void UV_SCL_single_clock()

    UV_Delay();
    UV_SCL_SET();
    UV_Delay();
    UV_SCL_RESET();
    UV_Delay();


unsigned char IIC_ACKme()

    unsigned char HerAnswer;
    HerAnswer=UV_SDA_State;
    UV_SCL_single_clock();
    return HerAnswer;


void IIC_ACKher(unsigned char MyAnswer)

    if(MyAnswer is Yes)
    
        UV_SDA_SET();
    
    else
    
        UV_SDA_RESET();
    
    UV_SCL_single_clock();


void IIC_Sent_iBit(unsigned short i, unsigned short store)//After start signal, following the simple shift

    while(i)
    
        if((store>>(i-1))&0x01)//Transfer the MSB to SDA line
        
            UV_SDA_SET();//"1" level correspond to high level
        
        else
        
            UV_SDA_RESET();//"0" level correspond to low level
        
        UV_SCL_single_clock();
        i--;//"i" shift the position of the transfer bit back to "if"
    //When "i" subtract to "0", transmission will be end


unsigned short IIC_Rcev_iBit(unsigned short i)//Old way, receive "i" bits\' data, just simple shift

    unsigned short store=0;//A before state is both lines is low level
    while(i)
    
        store<<=1;//Shift the position for next bit
        UV_SCL_SET();//Rasing SCL line will put the bit from the slave device up to the SDA line
        UV_Delay();//Wait a minute
        store|=UV_SDA_State;//Load the bit in store
        UV_SCL_RESET();//SCL line return to low level for next bit
        UV_Delay();//Wait a minute
        i--;//"i" shift the position of the receive bit back to "if"
    
    retuen store;

MPU6050寄存器值:

#define    AUX_VDDIO                0x01        //1
#define    SMPLRT_DIV                0x19        //2
#define    CONFIG                0x1A        //3
#define    GYRO_CONFIG                0x1B        //4
#define    ACCEL_CONFIG            0x1C        //5
#define    FF_THR                0x1D        //6
#define    FF_DUR                0x1E        //7
#define    MOT_THR                0x1F        //8
#define    MOT_DUR                0x20        //9
#define    ZRMOT_THR                0x21        //10
#define    ZRMOT_DUR                0x22        //11
#define    FIFO_EN                0x23        //12
#define    I2C_MST_CTRL            0x24        //13
#define    I2C_SLV0_ADDR            0x25        //14
#define    I2C_SLV0_REG            0x26        //15
#define    I2C_SLV0_CTRL            0x27        //16
#define    I2C_SLV1_ADDR            0x28        //17
#define    I2C_SLV1_REG            0x29        //18
#define    I2C_SLV1_CTRL            0x2A        //19
#define    I2C_SLV2_ADDR            0x2B        //20
#define    I2C_SLV2_REG            0x2C        //21
#define    I2C_SLV2_CTRL            0x2D        //22
#define    I2C_SLV3_ADDR            0x2E        //23
#define    I2C_SLV3_REG            0x2F        //24
#define    I2C_SLV3_CTRL            0x30        //25
#define    I2C_SLV4_ADDR            0x31        //26
#define    I2C_SLV4_REG            0x32        //27
#define    I2C_SLV4_DO                0x33        //28
#define    I2C_SLV4_CTRL            0x34        //29
#define    I2C_SLV4_DI                0x35        //30
#define    I2C_MST_STATUS            0x36        //31
#define    INT_PIN_CFG                0x37        //32
#define    INT_ENABLE                0x38        //33
#define    INT_STATUS                0x3A        //34
#define    ACCEL_XOUT_H            0x3B        //35
#define    ACCEL_XOUT_L            0x3C        //36
#define    ACCEL_YOUT_H            0x3D        //37
#define    ACCEL_YOUT_L            0x3E        //38
#define    ACCEL_ZOUT_H            0x3F        //39
#define    ACCEL_ZOUT_L            0x40        //40
#define    TEMP_OUT_H                0x41        //41
#define    TEMP_OUT_L                0x42        //42
#define    GYRO_XOUT_H                0x43        //43
#define    GYRO_XOUT_L                0x44        //44
#define    GYRO_YOUT_H                0x45        //45
#define    GYRO_YOUT_L                0x46        //46
#define    GYRO_ZOUT_H                0x47        //47
#define    GYRO_ZOUT_L                0x48        //48
#define    EXT_SENS_DATA_00            0x49        //49
#define    EXT_SENS_DATA_01            0x4A        //50
#define    EXT_SENS_DATA_02            0x4B        //51
#define    EXT_SENS_DATA_03            0x4C        //52
#define    EXT_SENS_DATA_04            0x4D        //53
#define    EXT_SENS_DATA_05            0x4E        //54
#define    EXT_SENS_DATA_06            0x4F        //55
#define    EXT_SENS_DATA_07            0x50        //56
#define    EXT_SENS_DATA_08            0x51        //57
#define    EXT_SENS_DATA_09            0x52        //58
#define    EXT_SENS_DATA_10            0x53        //59
#define    EXT_SENS_DATA_11            0x54        //60
#define    EXT_SENS_DATA_12            0x55        //61
#define    EXT_SENS_DATA_13            0x56        //62
#define    EXT_SENS_DATA_14            0x57        //63
#define    EXT_SENS_DATA_15            0x58        //64
#define    EXT_SENS_DATA_16            0x59        //65
#define    EXT_SENS_DATA_17            0x5A        //66
#define    EXT_SENS_DATA_18            0x5B        //67
#define    EXT_SENS_DATA_19            0x5C        //68
#define    EXT_SENS_DATA_20            0x5D        //69
#define    EXT_SENS_DATA_21            0x5E        //70
#define    EXT_SENS_DATA_22            0x5F        //71
#define    EXT_SENS_DATA_23            0x60        //72
#define    MOT_DETECT_STATUS            0x61        //73
#define    I2C_SLV0_DO                0x63        //74
#define    I2C_SLV1_DO                0x64        //75
#define    I2C_SLV2_DO                0x65        //76
#define    I2C_SLV3_DO                0x66        //77
#define    I2C_MST_DELAY_CTRL        0x67        //78
#define    SIGNAL_PATH_RESET            0x68        //79
#define    MOT_DETECT_CTRL            0x69        //80
#define    USER_CTRL                0x6A        //81
#define    PWR_MGMT_1                0x6B        //82
#define    PWR_MGMT_2                0x6C        //83
#define    FIFO_COUNTH                0x72        //84
#define    FIFO_COUNTL                0x73        //85
#define    FIFO_R_W                0x74        //86
#define    WHO_AM_I                0x75        //87
#define    MPU_Address                0xD0        //88

 

驱动程序实例:mpu6050(IIC + cdev)

在我们实际开发中,I2C 总线驱动一般芯片原厂会提供,我们开发一般是设计设备驱动。

本文结合之前对Linux内核的IIC子系统的分析 ,以及对字符设备的cdev接口的分析,本文将编写基于IIC总线与cdev接口的MPU6050设备的实例代码并对其进行分析。

IIC子系统分析:详见Linux IIC总线驱动框架

字符设备的cdev接口分析:详见Linux字符设备驱动(一):cdev接口

硬件接口:

  CPU:s5pv210;

  挂载IIC总线编号:0。

IIC从设备驱动挂载在IIC总线下,IIC总线管理着IIC从设备的设备信息(i2c_client)与设备驱动(i2c_driver)。因此,IIC从设备驱动的编写分为两个部分:注册IIC从设备信息、编写IIC从设备驱动程序。

1. 注册IIC从设备信息

在/kernel/arch/arm/mach-s5pv210/mach-x210.c文件中添加如下信息,向Linux内核注册IIC从设备信息。

static struct i2c_board_info mpu6050_i2c_devs0[] __initdata = 
{
    {
        I2C_BOARD_INFO("mpu6050", 0x2b),//构建i2c_board_info结构体,0x2b为从设备的地址
    },
};


static void __init smdkc110_machine_init(void)
{
    ... ...
    i2c_register_board_info(0, mpu6050_i2c_devs0, ARRAY_SIZE(mpu6050_i2c_devs0));//向内核注册IIC从设备信息,0表示该从设备挂载在IIC总线适配器0
    ... ...
}    

2. 编写IIC从设备驱动程序

(1)mpu6050_common.h

将mpu6050_common.h文件添加至/kernel/drivers/i2c/busses目录下。

技术分享图片
#ifndef _MPU6050_COMMON_H_
#define _MPU6050_COMMON_H_

#define MPU6050_MAGIC ‘K‘

//mpu6050数据结构
union mpu6050_data
{
    struct {
        short x;
        short y;
        short z;
    }accel;
    struct {
        short x;
        short y;
        short z;
    }gyro;
    unsigned short temp;
};

//mpu6050的ioctl的命令定义
#define GET_ACCEL _IOR(MPU6050_MAGIC, 0, union mpu6050_data)//读取加速度计的数据
#define GET_GYRO  _IOR(MPU6050_MAGIC, 1, union mpu6050_data)//读取陀螺仪的数据 
#define GET_TEMP  _IOR(MPU6050_MAGIC, 2, union mpu6050_data)//读取温度的数据

#endif
mpu6050_common.h

 

(2)mpu6050_dev.h

mpu6050_dev.h文件是mpu6050的寄存器地址的定义文件,将其添加至添加至/kernel/drivers/i2c/busses目录下。

技术分享图片
#ifndef _MPU6050_DEV_H_
#define _MPU6050_DEV_H_

#define SMPLRT_DIV      0x19    //陀螺仪采样率,典型值:0x07(125Hz)
#define CONFIG          0x1A    //低通滤波频率,典型值:0x06(5Hz)
#define GYRO_CONFIG     0x1B    //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define ACCEL_CONFIG    0x1C    //加速计自检、测量范围及高通滤波,典型值:0x18(不自检,2G,5Hz)
#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    //陀螺仪z轴角速度数据寄存器(高位)
#define GYRO_ZOUT_L     0x48    //陀螺仪z轴角速度数据寄存器(低位)
#define PWR_MGMT_1      0x6B    //电源管理,典型值:0x00(正常启用)
#define WHO_AM_I        0x75    //IIC地址寄存器(默认数值0x68,只读)
#define SlaveAddress    0x68    //MPU6050-I2C地址寄存器

#endif
mpu6050_dev.h

 

(3)mpu6050.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/cdev.h>

#include "mpu6050_dev.h"
#include "mpu6050_common.h"


#define DEV_MINOR 100       //IIC从设备的起始次设备号
#define DEV_CNT 1           //IIC从设备的个数
#define DEV_NAME "mpu6050"  //IIC从设备名称

static struct i2c_client *mpu6050_client;

static struct cdev mpu6050_dev;
static dev_t mpu6050_devnum;       //设备号
static struct class *mpu6050_class;//设备类

/*
*    功能:向mpu6050从设备写入数据
*
*    参数:struct i2c_client *client:指向mpu6050从设备
*          const unsigned char reg:需写入的mpu6050的寄存器
*          const unsigned char val:写入的数值
*/
static void mpu6050_write_byte(struct i2c_client *client, const unsigned char reg, const unsigned char val)
{ 
    char txbuf[2] = {reg, val};//数据缓存buffer
    
    //封装msg
    struct i2c_msg msg[2] = {
    
        [0] = 
        {
            .addr = client->addr,
            .flags= 0,
            .len = sizeof(txbuf),
            .buf = txbuf,
        },
    };
    
    i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));//与从设备进行数据通信
}


/*
*    功能:向mpu6050从设备读取数据
*
*    参数:struct i2c_client *client:指向mpu6050从设备
*          const unsigned char reg:需读取的mpu6050的寄存器
*
*    返回值:char:读取的数据
*/
static char mpu6050_read_byte(struct i2c_client *client,const unsigned char reg)
{
    char txbuf[1] = {reg};//数据缓冲buffer
    char rxbuf[1] = {0};
    
    //封装msg
    struct i2c_msg msg[2] = 
    {
        [0] = 
        {
            .addr = client->addr,
            .flags = 0,
            .len = sizeof(txbuf),
            .buf = txbuf,
        },
        
        [1] = 
        {
            .addr = client->addr,
            .flags = I2C_M_RD,
            .len = sizeof(rxbuf),
            .buf = rxbuf,
        },
    };

    i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); //与从设备进行数据通信
    
    return rxbuf[0];
}

//mpu6050硬件初始化
static void mpu6050_init(struct i2c_client *client)
{
    mpu6050_write_byte(client, PWR_MGMT_1, 0x00);
    mpu6050_write_byte(client, SMPLRT_DIV, 0x07);
    mpu6050_write_byte(client, CONFIG, 0x06);
    mpu6050_write_byte(client, GYRO_CONFIG, 0x18);
    mpu6050_write_byte(client, ACCEL_CONFIG, 0x0);
}


static int mpu6050_open(struct inode *ip, struct file *fp)
{
    return 0;
}
static int mpu6050_release(struct inode *ip, struct file *fp)
{
    return 0;
}

static long mpu6050_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
    int res = 0;
    union mpu6050_data data = {{0}};
    
    switch(cmd)
    {
        //读取加速度计的数据
        case GET_ACCEL:
            data.accel.x = mpu6050_read_byte(mpu6050_client,ACCEL_XOUT_L);
            data.accel.x|= mpu6050_read_byte(mpu6050_client,ACCEL_XOUT_H)<<8;
            data.accel.y = mpu6050_read_byte(mpu6050_client,ACCEL_YOUT_L);
            data.accel.y|= mpu6050_read_byte(mpu6050_client,ACCEL_YOUT_H)<<8;
            data.accel.z = mpu6050_read_byte(mpu6050_client,ACCEL_ZOUT_L);
            data.accel.z|= mpu6050_read_byte(mpu6050_client,ACCEL_ZOUT_H)<<8;
            break;
        
        //读取陀螺仪的数据
        case GET_GYRO:
            data.gyro.x = mpu6050_read_byte(mpu6050_client,GYRO_XOUT_L);
            data.gyro.x|= mpu6050_read_byte(mpu6050_client,GYRO_XOUT_H)<<8;
            data.gyro.y = mpu6050_read_byte(mpu6050_client,GYRO_YOUT_L);
            data.gyro.y|= mpu6050_read_byte(mpu6050_client,GYRO_YOUT_H)<<8;
            data.gyro.z = mpu6050_read_byte(mpu6050_client,GYRO_ZOUT_L);
            data.gyro.z|= mpu6050_read_byte(mpu6050_client,GYRO_ZOUT_H)<<8;
            printk("gyro:x %d, y:%d, z:%d
",data.gyro.x,data.gyro.y,data.gyro.z);
            break;
        
        //读取温度的数据
        case GET_TEMP:
            data.temp = mpu6050_read_byte(mpu6050_client,TEMP_OUT_L);
            data.temp|= mpu6050_read_byte(mpu6050_client,TEMP_OUT_H)<<8;
            printk("temp: %d
",data.temp);
            break;
            
        default:
            printk(KERN_INFO "invalid cmd");
            break;
    }
    printk("acc:x %d, y:%d, z:%d
",data.accel.x,data.accel.y,data.accel.z);
    res = copy_to_user((void *)arg,&data,sizeof(data));
    return sizeof(data);
}

//mpu6050操作集
static const struct file_operations mpu6050_fops = 
{
    .owner = THIS_MODULE,
    .open  = mpu6050_open,
    .release = mpu6050_release,
    .unlocked_ioctl = mpu6050_ioctl,
};

static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    struct device *dev;
    
    mpu6050_client = client;
    
    /*****************************初始化硬件设备******************************/
    //初始化mpu6050
    mpu6050_init(client);
    
    dbg("probe:name = %s,flag =%d,addr = %d,adapter = %d,driver = %s
", client->name,
         client->flags,client->addr,client->adapter->nr,client->driver->driver.name );
    
    /*********************************创建接口********************************/
    cdev_init(&mpu6050_dev, &mpu6050_fops);                            //关联dev与fops
    alloc_chrdev_region(&mpu6050_devnum, DEV_MINOR, DEV_CNT, DEV_NAME);//自动分配设备号
    cdev_add(&mpu6050_dev, mpu6050_devnum, DEV_CNT);                   //添加设备至设备链表
    
    mpu6050_class = class_create(THIS_MODULE,DEV_NAME);                         //创建设备类
    dev = device_create(mpu6050_class, NULL , mpu6050_devnum, "%s%d", DEV_NAME);//创建mpu6050设备
    if (IS_ERR(dev))
    {
        dbg("device create error
");
        goto out;
    }
    
    return 0;
out:
    return -1;
}

static int  mpu6050_remove(struct i2c_client *client)
{
    dbg("remove
");
    
    device_destroy(mpu6050_class, mpu6050_devnum);
    class_destroy(mpu6050_class);
    unregister_chrdev_region(mpu6050_devnum,DEV_CNT);
    
    return 0;
}

//与mpu6050的设备信息匹配
static struct i2c_device_id mpu6050_ids[] = 
{
    {"mpu6050",0x2b},
    {}
};

//声明mpu6050_ids是i2c类型的一个设备表
MODULE_DEVICE_TABLE(i2c,mpu6050_ids);

//定义并初始化从设备驱动信息
static struct i2c_driver mpu6050_driver = 
{
    .probe    = mpu6050_probe,
    .remove   = mpu6050_remove,
    .id_table = mpu6050_ids,
    .driver = 
    {
        .name = "mpu6050",
        .owner = THIS_MODULE,
    },
};

static int __init mpu6050_i2c_init(void)
{
    return i2c_add_driver(&mpu6050_driver);//注册设备驱动
}


static void __exit mpu6050_i2c_exit(void)
{
    i2c_del_driver(&mpu6050_driver);       //注销设备驱动
}

 
MODULE_AUTHOR("Lin");
MODULE_DESCRIPTION("mpu6050 driver");
MODULE_LICENSE("GPL");
module_init(mpu6050_i2c_init);
module_exit(mpu6050_i2c_exit);

以上是关于贴个IIC的代码和MPU6050寄存器地址的文档(MOVE版)的主要内容,如果未能解决你的问题,请参考以下文章

MPU-6050:从 FIFO 寄存器正确读取数据

HAL库硬件IIC_MPU6050_DMP移植

STM32CubeMX移植MPU6050的DMP库读取角度信息

MPU6050数值没变化?

Arduino ESP8266网页同步更新MPU6050数据模型化显示

Arduino ESP32网页同步更新MPU6050数据模型化显示