前言

  • 目前不涉及驱动源码
  • 原文

1. 设备检查命令

1.1 查看I2C驱动

  • 命令:ls /sys/bus/i2c/devices 用于查看系统上存在的 I2C 总线

1.2 i2c-tools

  • i2c-tools,安装 i2c-tools 方便调试 i2c设备

1.2.1 I2C-detect安装

  • 使用命令:sudo apt install i2c-tools -y 安装 i2c-tools
  • 安装后可以使用命令:i2cdetect、i2cdump、i2cseti2cget

1.2.2 i2cdetect 命令

  • i2cdetect

    • 用于扫描 I2C 总线上的设备
  • 语法
    • i2cdetect [-y] [-a] [-q|-r] i2cbus [first last]
    • 参数
      • y:关闭交互模式,使用该参数时,不会提示警告信息。
      • a:扫描总线上的所有设备
      • q:使用SMBus的“quick write”命令进行检测,不建议使用该参数
      • r:使用SMBus的“receive byte”命令进行检测,不建议使用该参数
      • i2cbus:指定i2c总线的编号
      • first、last:扫描的地址范围
    • 返回值
      • '-':表示该地址被检测,但是没有芯片应答
      • 'UU':表示该地址当前由内核驱动程序使用
      • '**':** 表示以16进制表示的设备地址编号,如“68”
  • 例子:
    • i2cdetect -a 0

      • i2cdetect:i2cdetect命令
      • -a:总线上所有设备
      • 0:标号为 0 的 I2C,即是 I2C 1。
    • 上图中扫描出存在设备地址为 0x1e0x68 的设备。
    • i2cdetect -F i2cbus:查询 i2c 总线的功能,参数 i2cbus 表示 i2c 总线(看上
    • i2cdetect -V:打印软件的版本号
    • i2cdetect -l:检测当前系统有几组 i2c 总线

1.2.3 i2cget 命令

  • i2cget

    • 用于读取 I2C 设备的某个寄存器的值
  • 语法
    • i2cget [-f] [-y] i2cbus chip-address [data-address [mode]]
    • 参数
      • f:强制访问
      • y:关闭交互模式,使用该参数时,不会提示警告信息
      • i2cbus:指定 I2C 总线的编号
      • chip-address:I2C 设备地址
      • data-address:I2C 寄存器地址
      • mode:指定读取的大小, 可以是b, w, s或i,分别对应了字节,字,SMBus块, I2C块

1.2.4 i2cset 命令

  • i2cset

    • 写入指定 I2C 设备的某个寄存器的值
  • 语法
    • i2cset [-f] [-y] [-m mask] [-r] i2cbus chip-address data-address [value] … [mode]
    • 参数
      • f:强制访问
      • y:关闭交互模式,使用该参数时,不会提示警告信息
      • m
      • r:写入后立即回读寄存器值,并将结果与写入的值进行比较
      • i2cbus:指定 I2C 总线的编号
      • chip-address:I2C 设备地址
      • data-address:I2C 寄存器地址
      • value:要写入的值
      • mode:指定读取的大小, 可以是b, w, s或i,分别对应了字节,字,SMBus块, I2C块

1.2.5 i2cdump 命令

  • i2cdump

    • 读取指定设备的全部寄存器的值
  • 语法
    • i2cdump [-f] [-r first-last] [-y] i2cbus address [mode [bank [bankreg]]]
    • 参数
      • r:指定寄存器范围,只能扫描从 firstlast 区域
      • f:强制访问设备
      • y:关闭人机交互模式
      • i2cbus:指定 I2C 总线的编号
      • address:指定设备地址
      • mode:指定读取的大小, 可以是b, w, s或i,分别对应了字节,字,SMBus块, I2C块
  • 例子
    • i2cdump -V:打印软件的版本号

2. 源码实战

  • 采用MPU6050设备进行实验
  • 步骤:
    • 先编写基础的 I2C 基础函数
    • 编写 MPU6050 初始化函数和关闭设备文件函数
    • 编写获取 MPU6050 数据函数
    • 编写业务函数

2.1 编写 bsp_mpu6050.h 文件

  • 编写好 MPU6050 需要的宏
  • extern 外部函数
/** @file         bsp_mpu6050.h
 *  @brief        简要说明
 *  @details      详细说明
 *  @author       lzm
 *  @date         2020-11-28 19:22:20
 *  @version      v1.0
 *  @copyright    Copyright By lizhuming, All Rights Reserved
 *
 **********************************************************
 *  @LOG 修改日志:
 **********************************************************
*/
#ifndef _BSP_MPU6050_H_ 
#define _BSP_MPU6050_H_
/* 宏 */
#define SMPLRT_DIV                                  0x19
#define CONFIG                                      0x1A
#define GYRO_CONFIG                                 0x1B
#define ACCEL_CONFIG                                0x1C
#define ACCEL_XOUT_H                                0x3B
#define ACCEL_XOUT_L                                0x3C
#define ACCEL_YOUT_H                                0x3D
#define ACCEL_YOUT_L                                0x3f
#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 WHO_AM_I                                    0x75
#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
/* 类型转换 */
typedef unsigned char uint8_t;
/* 函数 */
uint8_t mpu6050_init(char * i2cDev);
void    mpu6050_close(void);
short   getData(unsigned char regAddr);
#endif /* #define _BSP_MPU6050_H_ */

2.2 编写 bsp_mpu6050.c 文件

  • bsp_mpu6050.c
  • 编写 I2C 读写函数
  • 编写 MPU6050 设备初始化函数及关闭文件函数
  • 编写获取 MPU6050 设备寄存器数据函数

/** @file         bsp_mpu6050.c
 *  @brief        简要说明
 *  @details      详细说明
 *  @author       lzm
 *  @date         2020-11-28 19:20:20
 *  @version      v1.0
 *  @copyright    Copyright By lizhuming, All Rights Reserved
 *
 **********************************************************
 *  @LOG 修改日志:
 **********************************************************
*/
/* 头文件 */
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/select.h>
#include<sys/time.h>
#include "bsp_mpu6050.h"
/* 设备句柄 */
int i2cFd; // i2c设备句柄
/**
  * @brief  i2c 写
  * @param  fd:i2c设备句柄
  * @param  regAddr:寄存器地址
  * @param  val:需要写入的值
  * @retval 0:写入成功
  * @retval -1:写入失败
  * @author lzm
  */
static uint8_t i2c_write(int fd, uint8_t regAddr, uint8_t val)
{
    int cnt; // 写入失败后,重复写入的次数
    uint8_t data[2]; // data[0]为寄存器地址,data[1]为需要写入的值
    data[0] = regAddr;
    data[1] = val;
    for(cnt=5; cnt>0; cnt--)
    {
        if(write(fd, data, 2) == 2)
            return 0; // 写入成功
    }
    return -1; // 写入失败
}
/**
  * @brief  i2c 读
  * @param  fd:i2c设备句柄
  * @param  regAddr:寄存器地址
  * @param  val:读取到数据保存的地方
  * @retval 0:读取成功
  * @retval -1:读取失败
  * @author lzm
  */
static uint8_t i2c_read(int fd, uint8_t regAddr, uint8_t * val)
{
    int cnt; // 读取失败后,重新读取的次数
    for(cnt=5; cnt>0; cnt--)
    {
        if(write(fd, &regAddr, 1) == 1)
        {
            if(read(fd, val, 1) == 1)
                return 0;
        }
    }
    return -1;
}
/**
  * @brief  mpu6050初始化
  * @param  i2cDev
  * @retval 1:初始化成功
  * @retval 0:初始化失败
  * @author lzm
  */
uint8_t mpu6050_init(char * i2cDev)
{
    i2cFd = open(i2cDev, O_RDWR); // 打开i2c设备文件
    if(i2cFd < 0)
    {
        printf("Can't open %s!\n", i2cDev);
        exit(1);
    }
    printf("Open %s success!", i2cDev);
    if(ioctl(i2cFd, I2C_SLAVE, Address) < 0)
    {
        printf("fail to set i2c device slave address!");
        close(i2cFd); // 关闭i2c设备文件
        return -1;
    }
    printf("set slave address to 0x%x success!", Address);
    i2c_write(i2cFd, PWR_MGMT_1, 0X00);
    i2c_write(i2cFd, SMPLRT_DIV, 0X07);
    i2c_write(i2cFd, CONFIG, 0X06);
    i2c_write(i2cFd, ACCEL_CONFIG, 0X01);
    return 1;
}
/**
  * @brief  关闭设备文件
  * @param  
  * @retval 
  * @author lzm
  */
void mpu6050_close(void)
{
    close(i2cFd);
}
/**
  * @brief  获取数据
  * @param  regAddr:寄存器地址
  * @retval 获取到的数据
  * @author lzm
  */
short getData(unsigned char regAddr)
{
    char chH; // 高字节
    char chL; // 低字节
    i2c_read(i2cFd, regAddr, &chH);
    usleep(1000);
    i2c_read(i2cFd, regAddr, &chL);
    return ((chH << 8) + chL);
}

2.3 编写 main.c 文件

  • 编写业务函数

/** @file         main.c
 *  @brief        简要说明
 *  @details      详细说明
 *  @author       lzm
 *  @date         2020-11-28 19:18:20
 *  @version      v1.0
 *  @copyright    Copyright By lizhuming, All Rights Reserved
 *
 **********************************************************
 *  @LOG 修改日志:
 **********************************************************
*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/select.h>
#include<sys/time.h>
#include "mpu6050/bsp_mpu6050.h"
int main(int argc, char * argv[])
{
    /* 程序开始标语 */
    printf("This is a mpu6050 test!\n");
    /* 初始化 MCPU6050 */
    mpu6050_init("/dev/i2c-0");
    sleep(1);
    /* mpu6050 应用测试 */
    while(1)
    {
        printf("get mpu6050 data!\n");
        usleep(1000 * 100);
        printf("ACCE_X:%6d\n ", getData(ACCEL_XOUT_H));
        usleep(1000 * 100);
        printf("ACCE_Y:%6d\n ", getData(ACCEL_YOUT_H));
        usleep(1000 * 100);
        printf("ACCE_Z:%6d\n ", getData(ACCEL_ZOUT_H));
        usleep(1000 * 100);
        printf("GYRO_X:%6d\n ", getData(GYRO_XOUT_H));
        usleep(1000 * 100);
        printf("GYRO_Y:%6d\n ", getData(GYRO_YOUT_H));
        usleep(1000 * 100);
        printf("GYRO_Z:%6d\n\n ", getData(GYRO_ZOUT_H));
        sleep(1);
    }
    /* 退出 mpu6050 */
    mpu6050_close();
}

相关链接

【linux】i2c使用分析&源码实战的更多相关文章

  1. 【linux】系统调用版串口分析&源码实战

    目录 前言 参考 1. 实战分析 1.1 开发步骤 1.1.1 获取串口设备路径 1.1.2 打开设备文件 1.1.3 配置串口 termios 结构体 1. c_iflag 输入模式标志 2. c_ ...

  2. 【芯片手册开发】Sil9136音频开发详细分析+源码实战

    目录 前言 参考 手册使用+实战 配置 Configuring Audio Using I2S 总结实现 前言 默认在开发了视频方面后 这方面的工作本来可以找技术支持拿个例程参考下,很快就可以的写出来 ...

  3. Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装

    原文:Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装 Linux内核分析(一) 从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底 ...

  4. Linux 内核调度器源码分析 - 初始化

    导语 上篇系列文 混部之殇-论云原生资源隔离技术之CPU隔离(一) 介绍了云原生混部场景中CPU资源隔离核心技术:内核调度器,本系列文章<Linux内核调度器源码分析>将从源码的角度剖析内 ...

  5. Netty4.x 源码实战系列(一): 深入理解ServerBootstrap 与 Bootstrap

    转载自:https://www.cnblogs.com/itdriver/p/8149913.html 从Java1.4开始, Java引入了non-blocking IO,简称NIO.NIO与传统s ...

  6. 转载~Linux 平台下阅读源码的工具

    Linux 平台下阅读源码的工具 前言 看源代码是一个程序员必须经历的事情,也是可以提升能力的一个捷径.个人认为: 要完全掌握一个软件的方法只有阅读源码在Windows下有sourceinsight这 ...

  7. Linux 平台下阅读源码的工具链

    原文:http://blog.jobbole.com/101322/ 前言 看源代码是一个程序员必须经历的事情,也是可以提升能力的一个捷径.个人认为: 要完全掌握一个软件的方法只有阅读源码. 在Win ...

  8. 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 百篇博客分析OpenHarmony源码 | v13.02

    百篇博客系列篇.本篇为: v13.xx 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 51.c.h .o 几点说明 kernel_liteos_a_note | 中文注解鸿蒙内核 ...

  9. Netty4.x 源码实战系列(一): 深入理解ServerBootstrap 与 Bootstrap (1)

    从Java1.4开始, Java引入了non-blocking IO,简称NIO.NIO与传统socket最大的不同就是引入了Channel和多路复用selector的概念.传统的socket是基于s ...

随机推荐

  1. vue-cli中使用swiper

    1.当前项目配置 cnpm install swiper vue-awesome-swiper --save 或指定版本下载 cnpm install swiper@5.4.5 vue-awesome ...

  2. Redis常用命令(2)——String

    APPEND 格式:APPEND key value 作用:在key的键值后追加value,如果key不存在,则创建key,并存入value. 返回值:追加value后的字符串长度. 示例: 192. ...

  3. 初始化vue项目

    1.创建vue项目命令 vue init webpack deaxios # 使用脚手架创建项目 deaxios(项目名,随便取得) cd deaxios # 进入项目 npm install axi ...

  4. Java内存区域(运行时数据区域)详解、JDK1.8与JDK1.7的区别

    2.1 概述 对Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每个对象的new操作去写配对的delete/free 代码,不容易出现内存泄露和内存溢出的问题.不过,仍然需要Java虚 ...

  5. Linux 系统编程 学习:02-进程间通信1:Unix IPC(1)管道

    Linux 系统编程 学习:02-进程间通信1:Unix IPC(1)管道 背景 上一讲我们介绍了创建子进程的方式.我们都知道,创建子进程是为了与父进程协作(或者是为了执行新的程序,参考 Linux ...

  6. python机器学习之支持向量机SVM

    支持向量机SVM(Support Vector Machine) 关注公众号"轻松学编程"了解更多. [关键词]支持向量,最大几何间隔,拉格朗日乘子法 一.支持向量机的原理 Sup ...

  7. 修改redo log 的大小

    alert日志中含有大量警告信息:"Thread 1 cannot allocate new log, sequence 320xx Checkpoint not complete" ...

  8. Centos8防火墙设置

    1.centos中firewalld与iptables centos7以前的版本默认使用iptables服务进行管理防火墙规则.centos7以及其以上版本默认使用firewalld服务管理防火墙.所 ...

  9. 【应用程序见解 Application Insights】Application Insights 使用 Application Maps 构建请求链路视图

    Applicaotn  Insigths 使用 Application Maps 构建请求链路视图 构建系统时,请求的逻辑操作大多数情况下都需要在不同的服务,或接口中完成整个请求链路.一个请求可以经历 ...

  10. 剑指offer之顺序打印数组

    算法的要求为: 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打 ...