Linux应用编程 - i2c-dev操作I2C

        嵌入式Linux操作I2C设备,我们一般会在内核态编写I2C驱动程序。另外还能在用户空间编写I2C程序,下面介绍相关代码的实现。

        i2c-dev框架在内核中封装了I2C通信所需要的所有通信细节,I2C适配器会在/dev目录下创建字符设备,例如:/dev/i2c-0,通过系统调用操作/dev/i2c-0就可以实现与I2C设备通信。

    

一、I2C适配器操作函数

        下面介绍如何在用户空间打开I2C适配器,并使用I2C适配器读写I2C设备。

1、打开I2C适配器

         调用open系统调用打开/dev/i2c-n文件

/* 打开字符设备 */
s32 hal_i2c_open(u32 u32I2cIdx, s32 *ps32Fd)
{s32 s32Fd          = 0;s8    s8Fname[128]  = {0,};sprintf((char *)s8Fname, "/dev/i2c-%u", u32I2cIdx);s32Fd = open((char *)s8Fname, 0);if (0 >= s32Fd){LOG_WARN("i2c open %s s32Fd=%d,retry it\n",s8Fname,s32Fd);s32Fd = open((char *)s8Fname, 0);if (0 >= s32Fd){LOG_ERR("Open %s error, s32Fd %d,u32I2cIdx:0x%X!\n",s8Fname, s32Fd,u32I2cIdx);return -1;}}*ps32Fd  = s32Fd;return 0;
}/* 关闭字符设备 */
s32 hal_i2c_close(s32 s32Fd)
{if(0 >= s32Fd){LOG_ERR("failed !\n");return -1;}close(s32Fd);return 0;
}

2、I2C适配器读写

        通过ioctl去读写I2C适配器从而与I2C设备通信

/*
*****************************************************************************************
*	函 数 名: hal_i2c_read
*	功能说明: I2C读
*	形    参: s32Fd       : I2C节点
*           u16DevAddr  : 设备地址
*           u16RegAddr  : 寄存器地址
*           u16RegLen   : 寄存器长度
*           pu8Buf      : 读取数据buf
*           u16DataLen  : 需要读取数据长度
*	返 回 值: 返回0:OK
*            其他: ERROR
*****************************************************************************************
*/
s32 hal_i2c_read(s32 s32Fd, u16 u16DevAddr, u16 u16RegAddr,u16 u16RegLen, u8 *pu8Buf, u16 u16DataLen)
{u8  u8Buf[2]  = {0,};struct i2c_rdwr_ioctl_data rdwr = {0};struct i2c_msg msg[2] = {0};if(I2C_DEVICE_REG_LEN_2BIT == u16RegLen){  u8Buf[0] = (u16RegAddr >> 8) & 0xff;u8Buf[1] = u16RegAddr & 0xff;}else{                       //8位寄存器u8Buf[0] = u16RegAddr & 0xff;}msg[0].addr  = u16DevAddr; //设备地址msg[0].flags = 0;msg[0].len   = u16RegLen;msg[0].buf   = u8Buf;  //存放寄存器的地址msg[1].addr = u16DevAddr;msg[1].flags = 0;msg[1].flags |= I2C_M_RD;msg[1].len = u16DataLen;  //需要读取的数据长度msg[1].buf = pu8Buf;//存放返回数据的地址rdwr.msgs = &msg[0];rdwr.nmsgs = 2;if(ioctl(s32Fd, I2C_RDWR, &rdwr) != 2){LOG_ERR("CMD_I2C_READ error! \n");goto Error;}return 0;Error:return -1;
}/*
*****************************************************************************************
*	函 数 名: hal_i2c_write
*	功能说明: I2C写
*	形    参: s32Fd       : I2C节点
*           u16DevAddr  : 设备地址
*           u16RegAddr  : 寄存器地址
*           u16RegLen   : 寄存器长度
*           pu8Buf      : 写入数据buf
*           len         : 需要写入数据长度
*	返 回 值: 返回0:OK
*            其他: ERROR
*****************************************************************************************
*/
s32 hal_i2c_write(s32 s32Fd, u16 u16DevAddr, u16 u16RegAddr,u16 u16RegLen, u8 *pu8Buf, u16 len)
{u8 *pu8SendBuff = NULL;struct i2c_rdwr_ioctl_data rdwr = {0,};struct i2c_msg messages = {0,};if(I2C_DEVICE_REG_LEN_2BIT == u16RegLen){pu8SendBuff = (u8 *)malloc(len + I2C_DEVICE_REG_LEN_2BIT);  //需要传递的buffer中,头2个字节是寄存器地址pu8SendBuff[0] = (u16RegAddr >> 8) & 0xff;   //保存寄存器地址值pu8SendBuff[1] = u16RegAddr & 0xff;}else{pu8SendBuff = (u8 *)malloc(len + I2C_DEVICE_REG_LEN_1BIT);pu8SendBuff[0] = u16RegAddr & 0xff;   //保存寄存器地址值}if (NULL == pu8SendBuff){LOG_ERR("malloc failed!\n");return -1;}if (NULL != pu8Buf){if(I2C_DEVICE_REG_LEN_2BIT == u16RegLen)memcpy(&pu8SendBuff[I2C_DEVICE_REG_LEN_2BIT], pu8Buf, len);    //寄存器地址长度为2,需要从pu8SendBuff[2]开始存放需要写的buffer数据elsememcpy(&pu8SendBuff[I2C_DEVICE_REG_LEN_1BIT], pu8Buf, len);}messages.addr = u16DevAddr;  //设备地址messages.flags = 0;messages.buf = pu8SendBuff; if(I2C_DEVICE_REG_LEN_2BIT == u16RegLen)messages.len = len + I2C_DEVICE_REG_LEN_2BIT;elsemessages.len = len + I2C_DEVICE_REG_LEN_1BIT;rdwr.msgs = &messages;rdwr.nmsgs = 1;if(0 >= ioctl(s32Fd, I2C_RDWR, (unsigned long)&rdwr)){perror("error:");LOG_ERR("I2C send failed!\n");goto Error;}free(pu8SendBuff);return 0;Error:free(pu8SendBuff);return -1;
}

二、实例

        ap3216C是一款三合一环境传感器,它内部集成了:数字环境光传感器(Ambilent Light Aensors,ALS)、距离传感器(Proximity Sense,PS)和一个红外LED(Infrared Radiation LED,IR LED),该芯片通过IIC接口连接ARM板,设备地址为0x1E

下图为主要的几个寄存器:

首先,我们可以用i2cdetect工具去探测I2C1上的ap3216c芯片,看硬件通路是否正常

$ i2cdetect -r -y 0

1、读ap3216c芯片的数据

代码下载链接:https://download.csdn.net/download/hinewcc/89438732

从I2C适配器接口操作ap3216c的代码如下:

/* 打开/dev/i2c-0 */
static s32 ap3216c_i2c_open(u32 _u32I2cIdx, s32 *_ps32Fd)
{hal_i2c_open(_u32I2cIdx, _ps32Fd);return 0;
}/* I2C写单个寄存器 */
static s32 ap3216c_write_reg(s32 _s32Fd, u8 _u8Reg, u8 _u8Data)
{HAL_DEV_I2C_INFO_S stData = {0};stData.u16DevAddr   = AP3216C_ADDR; 	//设备地址stData.u16RegAddr   = _u8Reg;        	//寄存器地址stData.u16RegLen    = AP3216C_REG_W; 	//寄存器地址长度return hal_i2c_write(_s32Fd, stData.u16DevAddr, stData.u16RegAddr, stData.u16RegLen, &_u8Data, 1);
}/* I2C读单个寄存器 */
static s32 ap3216c_read_reg(s32 _s32Fd, u8 _u8Reg, u8 *_pData)
{HAL_DEV_I2C_INFO_S stData = {0};u8 data = 0;stData.u16DevAddr   = AP3216C_ADDR; //设备地址stData.u16RegAddr   = _u8Reg;        //寄存器地址stData.u16RegLen    = AP3216C_REG_W; //寄存器地址长度return hal_i2c_read(_s32Fd, stData.u16DevAddr, stData.u16RegAddr, stData.u16RegLen, _pData, 1);
}/* 关闭i2c */
static s32 ap3216c_i2c_close(s32 _s32Fd)
{hal_i2c_close(_s32Fd);return 0;
}

最终,ap3216c适配层会提供如下接口给应用层调用

/*
*********************************************************************************************************
*	函 数 名: ap3216c_init
*	功能说明: 初始化
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
int ap3216c_init(void)
{ap3216c_i2c_open(I2C_INDEX, &g_stAp3216c.s32Fd);/* 初始化AP3216C */ap3216c_write_reg(g_stAp3216c.s32Fd, AP3216C_SYSTEMCONG, 0x04);	/* 复位AP3216C */usleep(100000);													/* AP3216C复位最少10ms */ap3216c_write_reg(g_stAp3216c.s32Fd, AP3216C_SYSTEMCONG, 0X03);	/* 开启ALS、PS+IR */return 0;
}/*
*********************************************************************************************************
*	函 数 名: ap3216c_deinit
*	功能说明: 初始化
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
int ap3216c_deinit(void)
{if (g_stAp3216c.s32Fd != NULL) {ap3216c_i2c_close(g_stAp3216c.s32Fd);g_stAp3216c.s32Fd = NULL;}return 0;
}/*
*********************************************************************************************************
*	函 数 名: ap3216c_getdata
*	功能说明: 读数据
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
int ap3216c_getdata(HAL_AP3216C_DATA_T *_pstData)
{u8 u8Buf[6] = {0};int i;unsigned short ir, als, ps;if (g_stAp3216c.s32Fd == NULL) {return -1;}for(i = 0; i < 6; i++) {ap3216c_read_reg(g_stAp3216c.s32Fd, AP3216C_REG_IR_L + i, &u8Buf[i]);	//读单个寄存器}if(u8Buf[0] & 0X80) 	/* IR_OF位为1,则数据无效 */ir = 0;					else 				/* 读取IR传感器的数据 */ir = ((unsigned short)u8Buf[1] << 2) | (u8Buf[0] & 0X03); 			als = ((unsigned short)u8Buf[3] << 8) | u8Buf[2];	/* 读取ALS传感器的数据 */  if(u8Buf[4] & 0x40)	/* IR_OF位为1,则数据无效 */ps = 0;    													else 				/* 读取PS传感器的数据 */ps = ((unsigned short)(u8Buf[5] & 0X3F) << 4) | (u8Buf[4] & 0X0F); _pstData->usIr = ir;_pstData->usAls = als;_pstData->usPs = ps;return 0;
}

main函数while循环中读取ap3216c的数据

int main(int argc, char* argv[])
{HAL_AP3216C_DATA_T stAp3216c;ap3216c_init();							//初始化while(1){ap3216c_getdata(&stAp3216c);		//读数据printf("ir = %d, als = %d, ps = %d\r\n", stAp3216c.usIr, stAp3216c.usAls, stAp3216c.usPs);usleep(200000); /* 200ms */}return 0;
}

2、测试结果

/ # ./test_app
Ap3216c: ir = 0, als = 12, ps = 0
Ap3216c: ir = 3, als = 15, ps = 0
Ap3216c: ir = 4, als = 11, ps = 0
Ap3216c: ir = 3, als = 12, ps = 0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/27842.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kettle从入门到精通 第七十课 ETL之kettle kettle数据校验,脏数据清洗轻松拿捏

场景&#xff1a;输入在指定的错误(错误应涵盖数据类型不匹配的情况)行数内&#xff0c;trans不报错&#xff0c;但通过错误处理步骤捕捉&#xff0c;并记入文件&#xff0c;整个数据管线正常完成直至处理完最后一个输入行。 解决方案&#xff1a;使用步骤【数据检验】进行处理…

C# —— 算数运算符

算术运算符: 用于数值类型进行变量计算的运算符 他的返回结果是数值 赋值运算符 : 先看右侧 再看 左侧 将右侧的数据赋值给左侧的变量 int num 5; string name "老王"; float myHeight 187.5f; 加 先计算 再赋值 // 进行数据的加法…

本周MoonBit新增Wasm1引用计数支持、语法即将添加错误恢复机制

MoonBit更新 【Wasm MVP】Wasm1 后端添加基于 Perceus 算法的引用计数支持 【语法】throw raise try catch 均被保留为关键字 为了即将添加的错误处理机制 【Core】List与sorted_map被移动至core/immut下 List被移动至core/immut/list包中&#xff0c;并被移除内置类型支持 …

快速解决Windows和Linux文件格式转换

来源&#xff1a; “码农不会写诗”公众号 链接&#xff1a;快速解决Windows和Linux文件格式转换 文章目录 01 安装02 使用 NOTE-dos2uninx dos2unix是将Dos(Windows)格式文件转换为Linux格式的命令&#xff1b; unix2dos是将Linux格式文件转换为Dos(Windows)格式的命令。 Dos…

哈希表、递归在二叉树中的应用-1372. 二叉树中的最长交错路径

题目链接及描述 1372. 二叉树中的最长交错路径 - 力扣&#xff08;LeetCode&#xff09; 题目分析 题目所述&#xff0c;计算在二叉树中交替遍历的最大深度【左->右->左】【右->左->右】&#xff0c;例如对于从当前根节点root出发&#xff0c;则此时遍历方向有两个…

今日成果2024-6-7 TrustZone TEE安全SDK开发指南

Rockchip Vendor Storage Application Note.pdf OK 开机下&#xff0c;可以实现Vendor Storage的读写。 0ms时同步RTC时间 OK Rockchip_Developer_Guide_TEE_SDK_CN.pdf 什么是TrustZone 此系统方法意味着可以保护安全内存、加密块、键盘和屏幕等外设&#xff0c;从而可确…

视频剪辑可以赚钱吗 快速学会视频剪辑的方法

由于视频剪辑的需求不断增长&#xff0c;学会视频剪辑成为一项自媒体必备的技能&#xff0c;这个技能可以为个人带来收入和职业发展带来机会。无论是作为自由职业者还是在公司工作&#xff0c;掌握视频剪辑技能都可以为你提供更多的工作机会和竞争优势。这篇文章将讲解视频剪辑…

springboot事务管理的机制是什么

SpringBoot的事务管理机制实质上是基于Spring框架的事务处理机制。其主要目的是确保一系列数据库操作要么全部成功&#xff0c;要么全部失败&#xff08;回滚&#xff09;&#xff0c;从而维护数据的完整性和一致性。 SpringBoot事务管理遵循ACID四大特性&#xff1a; 1、原子…

VBA,VB6 LIKE 运算符有哪些转义符?

在 VB6 中&#xff0c;LIKE 运算符主要使用以下转义符&#xff1a; *&#xff1a;表示匹配任意字符序列&#xff08;包括空字符序列&#xff09;。 ?&#xff1a;表示匹配任意单个字符。 [ ]&#xff1a;用于表示字符范围。例如&#xff0c;[a-z] 表示匹配从小写字母 a 到 z …

前端将Markdown文本转换为富文本显示/编辑,并保存为word文件

参考&#xff1a;https://www.wangeditor.com/ https://blog.csdn.net/weixin_43797577/article/details/138854324 插件&#xff1a; markdown-it traptitech/markdown-it-katex markdown-it-link-attributes highlight.js wangeditor/editor wangeditor/editor-for-vue html…

2.深度学习-线性回归

文章目录 环境配置&#xff08;必看&#xff09;线性回归代码工程运行结果1.对比图2.运行结果 环境配置&#xff08;必看&#xff09; Anaconda-创建虚拟环境的手把手教程相关环境配置看此篇文章&#xff0c;本专栏深度学习相关的版本和配置&#xff0c;均按照此篇文章进行安装…

Carsim高级开发:VS Connect通讯开发指南

文章目录 前言一、VS Connect 概念引入二、VS Connect 通讯框架三、Carsim 工程配置1、车辆模型配置2、procedure配置3、Run Control配置4、受控车辆名称配置 四、VS Connect Server代码1、打开Sln工程2、代码修改 五、VS Connect Client代码1、函数的调用关系2、carsim_variab…

目录深度探索

目录 文件控制块和索引节点 索引节点&#xff08;Inode&#xff09; 结构比较 简单文件目录 目录和文件控制块 线性结构的目录 优点和缺点 使用场景 树形目录 树形目录的基本概念 树形目录的优势 树形目录的具体应用 案例分析&#xff1a;多层次目录结构 无环图目…

MySQL 8.0开始引入了开窗函数,使得SQL语句能够以更复杂的方式操作数据集。

在MySQL中使用ROW_NUMBER()函数时&#xff0c;可以通过一个简单的图表来帮助理解它是如何工作的。以下是对ROW_NUMBER()函数的图解说明&#xff1a; 假设我们有一个名为employees的表&#xff0c;其中包含以下列&#xff1a;employee_id&#xff08;员工ID&#xff09;&#x…

C语言线条样式和填充样式都有哪些? 怎样设置?

一、问题 线条样式和填充样式都有哪些&#xff1f;该怎样设置&#xff1f; 二、解答 在画图前&#xff0c;要先设置线条样式和填充样式&#xff0c;它们直接决定图形的显⽰效果。 1.线条样式 (1) setlinestyle( ) 函数。 void far setlinestyle(int linestyle, unsigned upa…

5G消息 x 文旅 | 一站式智慧文旅解决方案

5G消息 x 文旅 | 一站式智慧文旅解决方案 文旅 x 5G 消息将进一步强化资源整合&#xff0c;满足游客服务需求、企业营销需求、政府管理需求&#xff0c;推进文化旅游项目的智慧化、数字化&#xff0c;增强传播力、竞争力和可持续性。5G 消息的“原生入口”、“超强呈现”、“智…

德克萨斯大学奥斯汀分校自然语言处理硕士课程汉化版(第十周) - 自然语言处理应用

自然语言处理应用 1. 问答系统 1.1. 信息检索1.2. 机器阅读理解1.3. 多跳问答 2. 对话系统3. 机器翻译4. 文本摘要 1. 问答系统 在自然语言处理领域&#xff0c;问答系统(Question Answering&#xff0c;QA)是一个广泛且重要的研究方向&#xff0c;其目的是让计算机根据给定的…

Unity3D TextMeshPro组件使用及优化详解

在Unity3D游戏开发中&#xff0c;文本渲染是一个不可或缺的部分。而TextMeshPro作为Unity的一个插件&#xff0c;提供了更高质量、更灵活的文本渲染功能&#xff0c;为开发者带来了极大的便利。本文将详细介绍TextMeshPro组件的使用技巧以及优化方法&#xff0c;并通过代码实例…

红队攻防渗透技术实战流程:组件安全:JacksonFastJsonXStream

红队攻防渗透实战 1. 组件安全1.1 J2EE-组件Jackson-本地demo&CVE1.1.1 代码执行 (CVE-2020-8840)1.1.2 代码执行(CVE-2020-35728)1.2 J2EE-组件FastJson-本地demo&CVE1.2.1 FastJson <= 1.2.241.2.2 FastJson <= 1.2.471.2.3 FastJson <= 1.2.801.3 J2EE-组…

帕金森病的食疗建议

帕金森病&#xff08;PD&#xff09;是一种慢性、进展性的神经退行性疾病&#xff0c;主要影响中老年人。虽然目前尚无法根治&#xff0c;但及早规范治疗可显著改善症状&#xff0c;提高患者的生活质量。饮食调理作为帕金森病综合治疗的重要组成部分&#xff0c;对于维持患者较…