qinyunti 发表于 2024-7-14 00:38

【超小型 Linux 开发套件Quantum Tiny Linux】MPU6050驱动编写

<div class='showpostmsg'><p>前面我们确认了mpu6050对应i2c-0,地址为0x68.</p>

<p >&nbsp;</p>

<p >现在开始就可以进行驱动编写了。</p>

<p >&nbsp;</p>

<p >先封装IIC读写接口。</p>

<p >&nbsp;</p>

<pre>
<code class="language-cpp">/**
 * \fn i2c_init
 * 初始化,打开设备
 * \param dev_path 设备路径,比如"/dev/i2c-0"
 * \return 返回打开的设备的句柄,和open返回值一样
 */
int i2c_init(char* dev_path)
{
    return open(dev_path, O_RDWR);
}

/**
 * \fn i2c_deinit
 * 解除初始化,关闭设备
 * \param fd 打开的设备句柄
 * \return 和close返回值一样
 */
int i2c_deinit(int fd)
{
    return close(fd);
}

/**
 * \fn i2c_write
 * 写数据
 * \param fd 打开的设备句柄
 * \param dev_addr I2C设备地址
 * \param reg_addr 寄存器地址
 * \param data 待写入数据
 * \param len 待写入数据字节数
 *
 * \return 0成功 其他值失败
 */
int i2c_write(int fd, uint8_t dev_addr, uint8_t reg_addr, uint8_t* data, uint32_t len)
{
    int ret = -1;
    uint8_t* buff = malloc(len+1);
    if(buff == NULL)
    {
        return -1;
    }
    buff = reg_addr;
    memcpy(&amp;buff, data, len);

    /* 构造msg */
    struct i2c_msg msg = {
        .addr = dev_addr,
        .flags = 0,
        .len = len + 1,
        .buf = buff,
    };

    struct i2c_rdwr_ioctl_data rdwr_msg = {
        .msgs = &amp;msg,
        .nmsgs = 1,
    };

    ret = ioctl(fd, I2C_RDWR, &amp;rdwr_msg);

    free(buff);
    return ret;
}

/**
 * \fn i2c_read
 * 读数据
 * \param fd 打开的设备句柄
 * \param dev_addr I2C设备地址
 * \param reg_addr 寄存器地址
 * \param data 存储读出数据
 * \param len 待读出数据字节数
 *
 * \return 0成功 其他值失败
 */
int i2c_read(int fd, uint8_t dev_addr,  uint8_t reg_addr, uint8_t* data, uint32_t len)
{
    int ret = -1;

    /* 构造msg */
    struct i2c_msg msg = {
        {
            .addr = dev_addr,   /* 设备地址 */
            .flags = 0,         /* 标志,为0表示写数据 */
            .len = 1,           /* 要写的数据的长度 */
            .buf = &amp;reg_addr,   /* 要写的数据的地址 */
        },
        {
            .addr = dev_addr,   /* 设备地址 */
            .flags = I2C_M_RD,  /* 标志,I2C_M_RD表示主机向主机读数据 */
            .len = len,         /* 要读取的数据的长度 */
            .buf = data,        /* 读取的数据存放的地址 */
        },
    };

    struct i2c_rdwr_ioctl_data rdwr_msg = {
        .msgs = msg,
        .nmsgs = 2,
    };

    ret = ioctl(fd, I2C_RDWR, &amp;rdwr_msg);

    return ret;
}</code></pre>

<p>实现mpu6050驱动</p>

<p >Mpu6050.c</p>

<pre>
<code class="language-cpp">#include "mpu6050.h"

int mpu6050_init(mpu6050_dev_st* dev)
{
    if(dev == (mpu6050_dev_st*)0)
    {
      return -1;
    }
    if(dev-&gt;init != (mpu6050_iic_init_pf)0)
    {
      dev-&gt;init();
    }
}

int mpu6050_deinit(mpu6050_dev_st* dev)
{
    if(dev == (mpu6050_dev_st*)0)
    {
      return -1;
    }
    if(dev-&gt;deinit != (mpu6050_iic_deinit_pf)0)
    {
      dev-&gt;deinit();
    }
}

int mpu6050_cfg(mpu6050_dev_st* dev, mpu6050_cfg_st* cfg, uint32_t num)
{
    if(dev == (mpu6050_dev_st*)0)
    {
      return -1;
    }
    if(cfg == (mpu6050_cfg_st*)0)
    {
      return -1;
    }
    for(uint32_t i=0; i&lt;num; i++)
    {
      if(dev-&gt;write != (mpu6050_iic_write_pf)0)
      {
            dev-&gt;write(dev-&gt;dev_addr, cfg-&gt;reg, &amp;(cfg-&gt;val), 1);
            if(dev-&gt;delayms != (mpu6050_delayms_pf)0)
            {
                dev-&gt;delayms(cfg-&gt;delay_ms);
            }
      }
    }
}

int mpu6050_get_gyro(mpu6050_dev_st* dev,uint16_t* val)
{
    dev-&gt;read(dev-&gt;dev_addr,0x43,(uint8_t*)val,6);
    for(int i=0; i&lt;3; i++)
    {
      val = ((val&gt;&gt;8)&amp;0x00FF) | ((val&lt;&lt;8)&amp;0xFF00);
    }
}

int mpu6050_get_accel(mpu6050_dev_st* dev,uint16_t* val)
{
    dev-&gt;read(dev-&gt;dev_addr,0x3B,(uint8_t*)val,6);
    for(int i=0; i&lt;3; i++)
    {
      val = ((val&gt;&gt;8)&amp;0x00FF) | ((val&lt;&lt;8)&amp;0xFF00);
    }
}

int mpu6050_get_temp(mpu6050_dev_st* dev,uint16_t* val)
{
    dev-&gt;read(dev-&gt;dev_addr,0x41,(uint8_t*)val,2);
    val = ((val&gt;&gt;8)&amp;0x00FF) | ((val&lt;&lt;8)&amp;0xFF00);
}
</code></pre>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>mpu6050.h</p>

<pre>
<code class="language-cpp">#ifndef MPU6050_H
#define MPU6050_H

#ifdef __cplusplus
extern "C" {
#endif

#include &lt;stdint.h&gt;

typedef int (*mpu6050_iic_write_pf)(uint8_t dev_addr, uint8_t reg_addr, uint8_t* val, uint32_t len);
typedef int (*mpu6050_iic_read_pf)(uint8_t dev_addr, uint8_t reg_addr, uint8_t* val, uint32_t len);
typedef int (*mpu6050_iic_init_pf)(void);
typedef int (*mpu6050_iic_deinit_pf)(void);
typedef void (*mpu6050_delayms_pf)(uint32_t ms);

typedef struct{
    uint8_t dev_addr;
    mpu6050_iic_write_pf write;
    mpu6050_iic_read_pf read;
    mpu6050_iic_init_pf init;
    mpu6050_iic_deinit_pf deinit;
    mpu6050_delayms_pf delayms;
} mpu6050_dev_st;

typedef struct{
    uint8_t reg;
    uint8_t val;
    uint32_t delay_ms;
} mpu6050_cfg_st;

int mpu6050_init(mpu6050_dev_st* dev);
int mpu6050_deinit(mpu6050_dev_st* dev);
int mpu6050_cfg(mpu6050_dev_st* dev, mpu6050_cfg_st* cfg, uint32_t num);
int mpu6050_get_gyro(mpu6050_dev_st* dev,uint16_t* val);
int mpu6050_get_accel(mpu6050_dev_st* dev,uint16_t* val);
int mpu6050_get_temp(mpu6050_dev_st* dev,uint16_t* val);

#ifdef __cplusplus
}
#endif

#endif
</code></pre>

<p>实现mpu6050_itf.c</p>

<pre>
<code class="language-cpp">#include &lt;stdio.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;unistd.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
//#include &lt;linux/i2c.h&gt;
#include &lt;linux/i2c-dev.h&gt;
#include "mpu6050.h"

/**
* \fn i2c_init
* 初始化,打开设备
* \param dev_path 设备路径,比如"/dev/i2c-0"
* \return 返回打开的设备的句柄,和open返回值一样
*/
int i2c_init(char* dev_path)
{
    return open(dev_path, O_RDWR);
}

/**
* \fn i2c_deinit
* 解除初始化,关闭设备
* \param fd 打开的设备句柄
* \return 和close返回值一样
*/
int i2c_deinit(int fd)
{
    return close(fd);
}

/**
* \fn i2c_write
* 写数据
* \param fd 打开的设备句柄
* \param dev_addr I2C设备地址
* \param reg_addr 寄存器地址
* \param data 待写入数据
* \param len 待写入数据字节数
*
* \return 0成功 其他值失败
*/
int i2c_write(int fd, uint8_t dev_addr, uint8_t reg_addr, uint8_t* data, uint32_t len)
{
    int ret = -1;
    uint8_t* buff = malloc(len+1);
    if(buff == NULL)
    {
      return -1;
    }
    buff = reg_addr;
    memcpy(&amp;buff, data, len);

    /* 构造msg */
    struct i2c_msg msg = {
      .addr = dev_addr,
      .flags = 0,
      .len = len + 1,
      .buf = buff,
    };

    struct i2c_rdwr_ioctl_data rdwr_msg = {
      .msgs = &amp;msg,
      .nmsgs = 1,
    };

    ret = ioctl(fd, I2C_RDWR, &amp;rdwr_msg);

    free(buff);
    return ret;
}

/**
* \fn i2c_read
* 读数据
* \param fd 打开的设备句柄
* \param dev_addr I2C设备地址
* \param reg_addr 寄存器地址
* \param data 存储读出数据
* \param len 待读出数据字节数
*
* \return 0成功 其他值失败
*/
int i2c_read(int fd, uint8_t dev_addr,uint8_t reg_addr, uint8_t* data, uint32_t len)
{
    int ret = -1;

    /* 构造msg */
    struct i2c_msg msg = {
      {
            .addr = dev_addr,   /* 设备地址 */
            .flags = 0,         /* 标志,为0表示写数据 */
            .len = 1,         /* 要写的数据的长度 */
            .buf = &amp;reg_addr,   /* 要写的数据的地址 */
      },
      {
            .addr = dev_addr,   /* 设备地址 */
            .flags = I2C_M_RD,/* 标志,I2C_M_RD表示主机向主机读数据 */
            .len = len,         /* 要读取的数据的长度 */
            .buf = data,      /* 读取的数据存放的地址 */
      },
    };

    struct i2c_rdwr_ioctl_data rdwr_msg = {
      .msgs = msg,
      .nmsgs = 2,
    };

    ret = ioctl(fd, I2C_RDWR, &amp;rdwr_msg);

    return ret;
}

int s_fd = -1;

int mpu6050_iic_write_port(uint8_t dev_addr, uint8_t reg_addr, uint8_t* val, uint32_t len)
{
    i2c_write(s_fd, dev_addr, reg_addr, val, len);
}

int mpu6050_iic_read_port(uint8_t dev_addr, uint8_t reg_addr, uint8_t* val, uint32_t len)
{
    i2c_read(s_fd, dev_addr, reg_addr, val, len);
}

int mpu6050_iic_init_port(void)
{
    s_fd = i2c_init("/dev/i2c-0");
}

int mpu6050_iic_deinit_port(void)
{
    i2c_deinit(s_fd);
}

void mpu6050_delayms_port(uint32_t ms)
{
    usleep(ms*1000);
}

mpu6050_dev_st s_mpu6050_dev =
{
    .dev_addr = 0x68,
    .write = mpu6050_iic_write_port,
    .read = mpu6050_iic_read_port,
    .init = mpu6050_iic_init_port,
    .deinit = mpu6050_iic_deinit_port,
    .delayms = mpu6050_delayms_port,
};

mpu6050_cfg_st s_mpu6050_cfg[] =
{
    {0x6B,0x01,100},
    {0x19,0x04,0},
    {0x1A,0x02,0},
    {0x1B,3&lt;&lt;3,0},
    {0x1C,2&lt;&lt;3,0},
    {0x37,0x32,0},
    {0x38,0x00,0},
    {0x6A,0x00,0},
};

int mpu6050_itf_init(void)
{
    mpu6050_init(&amp;s_mpu6050_dev);
    mpu6050_cfg(&amp;s_mpu6050_dev, s_mpu6050_cfg, sizeof(s_mpu6050_cfg)/sizeof(s_mpu6050_cfg));
}

int mpu6050_itf_deinit(void)
{
    mpu6050_deinit(&amp;s_mpu6050_dev);
}

int mpu6050_itf_get_gyro(uint16_t* val)
{
    mpu6050_get_gyro(&amp;s_mpu6050_dev,val);
}

int mpu6050_itf_get_accel(uint16_t* val)
{
    mpu6050_get_accel(&amp;s_mpu6050_dev,val);
}

int mpu6050_itf_get_temp(uint16_t* val)
{
    mpu6050_get_temp(&amp;s_mpu6050_dev,val);
}

int main(void)
{
    uint16_t gyro;
    uint16_t accel;
    uint16_t temp;
    mpu6050_itf_init();

    int i = 60;
    while(i--)
    {
      mpu6050_itf_get_gyro(gyro);
      printf("gyro:%d,%d,%d\r\n",gyro,gyro,gyro);
      mpu6050_itf_get_accel(accel);
      printf("accel:%d,%d,%d\r\n",accel,accel,accel);
      mpu6050_itf_get_temp(&amp;temp);
      printf("temp:%d\r\n",temp);
      sleep(1);
    }
    mpu6050_itf_init();
}</code></pre>

<p >Mpu6050_itf.h</p>

<pre>
<code class="language-cpp">#ifndef MPU6050_ITF_H
#define MPU6050_ITF_H

#ifdef __cplusplus
extern "C" {
#endif

#include &lt;stdint.h&gt;

int mpu6050_itf_init(void);
int mpu6050_itf_deinit(void);
int mpu6050_itf_get_gyro(uint16_t* val);
int mpu6050_itf_get_accel(uint16_t* val);
int mpu6050_itf_get_temp(uint16_t* val);

#ifdef __cplusplus
}
#endif

#endif
</code></pre>

<p >rz导入到开发板</p>

<p >&nbsp;</p>

<p >编译</p>

<p >gcc mpu6050.c mpu6050_itf.c -o mpu6050</p>

<p >&nbsp;</p>

<p >运行</p>

<p >./mpu6050</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >结果如下</p>

<p > &nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

Jacktang 发表于 2024-7-14 07:26

<p>结果应该是正确的吧</p>

lugl4313820 发表于 2024-7-14 13:15

<p>面向对象的驱动,移植起来非常之方便。</p>

qinyunti 发表于 2024-7-14 16:04

Jacktang 发表于 2024-7-14 07:26
结果应该是正确的吧

<p>这一篇还没换算,下篇文章换算成最终结果了</p>

freebsder 发表于 2024-7-17 11:55

<p>谢谢分享,期待后续!</p>
页: [1]
查看完整版本: 【超小型 Linux 开发套件Quantum Tiny Linux】MPU6050驱动编写