【linux】i2c使用分析&源码实战
前言
- 目前不涉及驱动源码
- 原文
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、i2cset 和 i2cget
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。
- 上图中扫描出存在设备地址为 0x1e 和 0x68 的设备。
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:指定寄存器范围,只能扫描从 first 到 last 区域
- 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, ®Addr, 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使用分析&源码实战的更多相关文章
- 【linux】系统调用版串口分析&源码实战
目录 前言 参考 1. 实战分析 1.1 开发步骤 1.1.1 获取串口设备路径 1.1.2 打开设备文件 1.1.3 配置串口 termios 结构体 1. c_iflag 输入模式标志 2. c_ ...
- 【芯片手册开发】Sil9136音频开发详细分析+源码实战
目录 前言 参考 手册使用+实战 配置 Configuring Audio Using I2S 总结实现 前言 默认在开发了视频方面后 这方面的工作本来可以找技术支持拿个例程参考下,很快就可以的写出来 ...
- Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装
原文:Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装 Linux内核分析(一) 从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底 ...
- Linux 内核调度器源码分析 - 初始化
导语 上篇系列文 混部之殇-论云原生资源隔离技术之CPU隔离(一) 介绍了云原生混部场景中CPU资源隔离核心技术:内核调度器,本系列文章<Linux内核调度器源码分析>将从源码的角度剖析内 ...
- Netty4.x 源码实战系列(一): 深入理解ServerBootstrap 与 Bootstrap
转载自:https://www.cnblogs.com/itdriver/p/8149913.html 从Java1.4开始, Java引入了non-blocking IO,简称NIO.NIO与传统s ...
- 转载~Linux 平台下阅读源码的工具
Linux 平台下阅读源码的工具 前言 看源代码是一个程序员必须经历的事情,也是可以提升能力的一个捷径.个人认为: 要完全掌握一个软件的方法只有阅读源码在Windows下有sourceinsight这 ...
- Linux 平台下阅读源码的工具链
原文:http://blog.jobbole.com/101322/ 前言 看源代码是一个程序员必须经历的事情,也是可以提升能力的一个捷径.个人认为: 要完全掌握一个软件的方法只有阅读源码. 在Win ...
- 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 百篇博客分析OpenHarmony源码 | v13.02
百篇博客系列篇.本篇为: v13.xx 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 51.c.h .o 几点说明 kernel_liteos_a_note | 中文注解鸿蒙内核 ...
- Netty4.x 源码实战系列(一): 深入理解ServerBootstrap 与 Bootstrap (1)
从Java1.4开始, Java引入了non-blocking IO,简称NIO.NIO与传统socket最大的不同就是引入了Channel和多路复用selector的概念.传统的socket是基于s ...
随机推荐
- linux上性能调优常用命令及简介
1.综合命令:nmon.top:topas(aix) d :磁盘相关 c:cpu相关 m:内存相关 2.磁盘 2.1 测试顺序写性能dd if=/dev/zero of=/cdr/test.data ...
- CSS中的position属性笔记
一般有5个属性,分别是:static,absolute,relative,fixed,inherit static 自然定位:这个是默认值,没有定位,再设置top,rignt,bottom,left会 ...
- Polyglot Translators: Let's do i18n easier! 一款国际化插件小助手!
在做国际化文本有关的工作时, 是否厌倦了在不同应用或者网页之间频繁地切换进行中文, 繁体, 英文甚至韩文日文的文本翻译工作? 好吧, 我就是受不了频繁在进行文本字符串的转换, 还得跑到百度翻译上面搜索 ...
- 关于Java中泛型、反射和注解的扫盲篇
泛型 泛型概念 泛型是在JDK1.5之后引入的,旨在让我们写出更加通用化,更加灵活的代码.通用化的手段在于让数据类型变得参数化,定义泛型时,对应的数据类型是不确定的,泛型方法被调用时,会指定具体类 ...
- c++11-17 模板核心知识(一)—— 函数模板
1.1 定义函数模板 1.2 使用函数模板 1.3 两阶段翻译 Two-Phase Translation 1.3.1 模板的编译和链接问题 1.4 多模板参数 1.4.1 引入额外模板参数作为返回值 ...
- mysql处理查询请求的步骤
服务端处理客户端的查询请求大致需要三个步骤: 连接管理 客户端连接服务端时,服务端会为其分配一个线程,客户端断开连接不会回收线程(避免频繁创建销毁的性能问题),服务端一直等待客户端发来消息(文本消息) ...
- nginx vhost配置
server { listen 80; server_name crsdemo.my; index index.html index.htm index.php default.html defaul ...
- 4、Django之视图层
一 视图函数 视图函数,简称视图,属于Django的视图层,默认定义在views.py文件中,是用来处理web请求信息以及返回响应信息的函数,所以研究视图函数只需熟练掌握两个对象即可:请求对象(Htt ...
- leetcode 43:construct-binary-tree-from-inorder
题目描述 给出一棵树的中序遍历和后序遍历,请构造这颗二叉树 注意: 保证给出的树中不存在重复的节点 Given inorder and postorder traversal of a tree, c ...
- Python - Git仓库忽略提交规则 & .gitignore配置
Git 忽略文件提交的方法 有三种方法可以实现忽略Git中不想提交的文件. 在Git项目中定义 .gitignore 文件 这种方式通过在项目的某个文件夹下定义 .gitignore 文件,在该文件 ...