Linux IIC 驱动实验

一、引言

        随着嵌入式系统的快速发展,IIC(Inter-Integrated Circuit)总线已经成为一种常见的通信协议,广泛应用于各种嵌入式设备中。在Linux操作系统中,IIC总线驱动程序是实现设备间通信的关键。本文将介绍一个基于Linux的IIC总线驱动实验,包括硬件分析驱动代码应用代码以及注释

二、硬件分析

        在本实验中,我们以一个典型的嵌入式设备为例,介绍IIC总线的硬件组成和特点。该设备包括一个处理器、一个IIC总线控制器和一个IIC总线从设备。处理器采用ARM架构,IIC总线控制器采用常见的Maxim 5768芯片,IIC总线从设备为DS18B20温度传感器

        IIC总线是一种二线制串行总线,它通过两条线(SDA和SCL)实现数据的传输和控制。IIC总线支持多设备通信,每个设备都有一个唯一的地址在IIC总线上,主设备控制数据的传输,从设备被寻址并响应主设备的请求。

三、驱动代码

#include <linux/module.h>  
#include <linux/i2c.h>  
#include <linux/err.h>  #define DRIVER_NAME "i2c-example"  // IIC总线控制器地址  
#define SLAVE_ADDR 0x51  // DS18B20温度传感器地址  
#define DS18B20_ADDR 0x20  // 设备信息结构体定义  
struct device_info {  int id; // 设备ID  struct i2c_adapter *adapter; // IIC适配器指针  struct i2c_client *client; // IIC客户端指针  
};  // 设备信息数组,每个元素包含设备ID、适配器指针和客户端指针  
static struct device_info devices[] = {  {DS18B20_ADDR, NULL, NULL}, // DS18B20温度传感器设备信息  
};  // 初始化函数  
static int __init i2c_driver_init(void) {  int i, ret;  char *msg;  struct i2c_board_info board_info;  struct device_info *dev_info;  struct i2c_client *client;  struct i2c_adapter *adapter;  int board_num = sizeof(devices) / sizeof(devices[0]); // 获取设备信息数组长度  for (i = 0; i < board_num; i++) { // 遍历设备信息数组中的每个元素,进行初始化操作  dev_info = &devices[i]; // 获取当前设备的设备信息结构体变量指针  msg = dev_info->adapter->name; // 获取当前适配器的名称  pr_info("Initialized device %s on adapter %s\n", dev_info->id, msg); // 打印初始化信息到日志文件中,包括当前设备的ID和适配器的名称
// 根据设备信息中的地址,向IIC总线控制器申请一个从设备节点  ret = i2c_new_client_device(dev_info->adapter, &board_info);  if (ret < 0) {  pr_err("Failed to create new client device\n"); // 如果申请失败,打印错误信息到日志文件中  return ret;  }  client = i2c_verify_client(&board_info); // 验证从设备节点是否申请成功  if (!client) {  pr_err("Failed to verify client\n"); // 如果验证失败,打印错误信息到日志文件中  return -EINVAL;  }  dev_info->client = client; // 将从设备节点指针赋值给设备信息结构体中的客户端指针  adapter = client->adapter; // 获取当前从设备的适配器指针  if (!adapter) {  pr_err("Failed to get adapter\n"); // 如果获取适配器指针失败,打印错误信息到日志文件中  return -EINVAL;  }  dev_info->adapter = adapter; // 将适配器指针赋值给设备信息结构体中的适配器指针  }  return 0;  
}
// 读写函数  
static int i2c_read(struct device_info *dev_info, void *buf, size_t count)  
{  struct i2c_msg msg;  int ret;  msg.addr = dev_info->client->addr; // IIC从设备地址  msg.flags = I2C_M_RD; // 读取模式  msg.len = count; // 读取数据长度  msg.buf = buf; // 数据缓冲区  ret = i2c_transfer(dev_info->adapter, &msg, 1); // 发送IIC消息并获取返回值  if (ret < 0) {  perror("Failed to read data from device"); // 如果读取失败,打印错误信息到标准错误输出流中  return -1;  }  return 0;  
}  static int i2c_write(struct device_info *dev_info, void *buf, size_t count)  
{  struct i2c_msg msg;  int ret;  msg.addr = dev_info->client->addr; // IIC从设备地址  msg.flags = 0; // 写入模式  msg.len = count; // 写入数据长度  msg.buf = buf; // 数据缓冲区  ret = i2c_transfer(dev_info->adapter, &msg, 1); // 发送IIC消息并获取返回值  if (ret < 0) {  perror("Failed to write data to device"); // 如果写入失败,打印错误信息到标准错误输出流中  return -1;  }  return 0;  
}
// 退出函数  
static void __exit i2c_driver_exit(void) {  int i;  struct device_info *dev_info;  int board_num = sizeof(devices) / sizeof(devices[0]); // 获取设备信息数组长度  for (i = 0; i < board_num; i++) { // 遍历设备信息数组中的每个元素,进行退出操作  dev_info = &devices[i]; // 获取当前设备的设备信息结构体变量指针  if (dev_info->client) { // 如果当前设备已经初始化过,则删除该设备节点  i2c_unregister_device(dev_info->client);  dev_info->client = NULL;  }  if (dev_info->adapter) { // 如果当前适配器已经申请过,则释放该适配器资源  i2c_del_adapter(dev_info->adapter);  dev_info->adapter = NULL;  }  }  pr_info("Driver exit\n"); // 打印退出信息到日志文件中  
}

        驱动代码包括初始化函数读写函数退出函数。在初始化函数中,根据设备信息中的地址向IIC总线控制器申请一个从设备节点,并将从设备节点和适配器指针赋值给设备信息结构体中的客户端指针和适配器指针。在读写函数中,通过构造IIC消息并调用i2c_transfer函数来发送IIC消息并获取返回值,实现数据的读取和写入。在退出函数中,删除设备节点并释放适配器资源。

四、应用代码

        

#include <stdio.h>  
#include <stdlib.h>  
#include <stdint.h>  
#include <unistd.h>  
#include <fcntl.h>  
#include <sys/ioctl.h>  
#include <linux/i2c-dev.h>  #define TEMPERATURE_REGISTER 0x05 // DS18B20温度传感器温度寄存器地址  int main(void) {  int i2c_fd; // IIC文件描述符  char buf[2]; // 数据缓冲区  int ret; // 返回值  // 打开IIC总线适配器  i2c_fd = open("/dev/i2c-1", O_RDWR);  if (i2c_fd < 0) {  perror("Failed to open i2c bus");  exit(1);  }  // 设置IIC总线适配器从设备地址  ret = ioctl(i2c_fd, I2C_SLAVE, DS18B20_ADDR);  if (ret < 0) {  perror("Failed to set i2c address");  exit(1);  }  // 读取温度数据  ret = i2c_read(DS18B20_ADDR, buf, 2);  if (ret < 0) {  perror("Failed to read temperature data");  exit(1);  }  printf("Temperature: %d.%d degrees Celsius\n", buf[0], buf[1]);  // 关闭IIC总线适配器  close(i2c_fd);  return 0;  
}

        首先通过调用open函数打开IIC总线适配器的设备文件,然后通过ioctl函数设置从设备地址。接下来,调用i2c_read函数从DS18B20温度传感器读取温度数据,并最终输出串口。最后,通过调用close函数关闭IIC总线适配器设备文件

五、实验结果与分析

        通过上述实验代码,我们能够实现通过IIC总线读取DS18B20温度传感器的温度数据。在实验过程中,我们需要注意以下几点:

  1. 确认IIC总线适配器是否正常工作,可以通过替换IIC总线适配器或使用其他设备进行测试来验证。
  2. 确认DS18B20温度传感器是否正常工作,可以通过替换传感器或使用其他已知工作的传感器进行测试来验证。
  3. 检查应用代码中从设备地址设置是否正确,可以通过修改从设备地址并观察是否能够正确读取传感器数据进行验证。
  4. 检查应用代码中数据读取是否正确,可以通过观察串口输出数据或使用其他工具进行验证。

        通过实验结果的分析,我们可以得出以下结论:

  1. 实验代码能够正确读取DS18B20温度传感器的温度数据。
  2. IIC总线适配器和DS18B20温度传感器能够正常工作,并且从设备地址设置正确。
  3. 应用代码中数据读取和串口输出部分正确无误。

        综上所述,该实验取得了成功,实现了通过IIC总线读取DS18B20温度传感器的温度数据并输出到串口的功能。同时,实验结果也证明了IIC总线适配器和DS18B20温度传感器的正常工作,以及应用代码的正确性。

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

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

相关文章

计数排序+桶排序 详讲(思路+图解+代码详解)

文章目录 计数排序和桶排序一、计数排序概念&#xff1a;写法一&#xff1a;写法二&#xff1a; 二、桶排序概念代码 计数排序和桶排序 一、计数排序 时间复杂度&#xff1a;空间复杂度&#xff1a;稳定性&#xff1a;稳定 概念&#xff1a; 非基于比较的排序 计数排序又称为…

PACS系统源码,WORKLIST数字化工作流程,影像数字化存储,电子报告书写、胶片打印

PACS系统源码 可与医院HIS、LIS无缝连接 PACS系统以实现医学影像数字化存储、诊断为核心任务&#xff0c;从医学影像设备&#xff08;如CT、CR、DR、MR、DSA、RF等&#xff09;获取影像&#xff0c;集中存储、综合管理医学影像及病人相关信息&#xff0c;建立数字化工作流程。 …

文章系列2:Unraveling the functional dark matter through global metagenomics

这篇文章发布于2023年10月nature。通讯作者是来自于 DOE Joint Genome Institute, Lawrence Berkeley National Laboratory, Berkeley, CA, USA. 背景介绍&目标 作者首先背景介绍了两种主流宏基因组分析方法&#xff0c;包括reads-based reference mapping&#xff08;eg…

Reactive.Net绑定Subscribe调用wpf控件报错

使用.ObserveOnDispatcher()解决&#xff0c;nuget安装ReactiveUI.WPF 参考 winforms - Rx Example not working - Stack Overflow

openssl+ SM2 + linux 签名开发实例(C++)

文章目录 一、SM2 签名理论基础二、SM2签名开发实例 一、SM2 签名理论基础 SM2是中国国家密码管理局发布的椭圆曲线密码算法标准&#xff0c;用于数字签名、密钥交换和公钥加密等安全通信场景。以下是SM2签名的理论基础相关知识点&#xff1a; 椭圆曲线密码学&#xff08;Elli…

为gnustep项目移植到wsl的过程

仔细研读/usr/share/GNUStep/Makefiles下的很多makefile文件的一些变量定义 然后开始整理代码&#xff0c;各个文件存放到自定义的文件夹&#xff0c;方便管理 修改GNUMakefile, 这里要研读很多Makefile 文件的变量定义&#xff0c;修正自己的赋值 一个尝试例子: https://gi…

VMware虚拟机的安装教程

安装VMware虚拟机的步骤如下&#xff1a; 首先&#xff0c;你需要从VMware官方网站&#xff08;https://www.vmware.com&#xff09;下载VMware虚拟机软件安装程序。 一旦下载完成&#xff0c;双击运行安装程序。 在安装程序启动后&#xff0c;你将看到一个欢迎界面。点击"…

chromium114添加新的语言国际化支持

一、需求说明 需要chromium114支持新语言体系,例如藏语,蒙古语,苗语等 二、操作步骤 1. build/config/locales.gni修改 在all_chrome_locales变量中添加新的语种标识,如下图。 2. 添加编译文件,告诉浏览器在编译时需要加载和输出那些文件 尝试编译出现错误一提示。需要…

Python Turtle Graphics 绘制I Love You字符

1.1引言&#xff1a; Python的turtle模块是一个非常有趣且强大的工具&#xff0c;它允许我们以一个可视化和互动的方式学习编程。通过调用各种命令&#xff0c;我们可以引导turtle画出一个指定的图形。在本博客中&#xff0c;我们将使用turtle模块来绘制一个复杂的图形。 1.2实…

读像火箭科学家一样思考笔记05_思想实验

1. 思想实验室 1.1. 思想实验至少可以追溯到古希腊时期 1.1.1. 从那时起&#xff0c;它们就跨越各个学科&#xff0c;在哲学、物理学、生物学、经济学等领域取得重大突破 1.1.2. 它们为火箭提供动力&#xff0c;推翻政府&#xff0c;发展进化生物学&#xff0c;解开宇宙的奥…

优秀智慧园区案例 - 三亚市崖州湾科技城智慧园区,先进智慧园区建设方案经验

一、项目背景 三亚崖州湾科技城作为海南自贸港建设的重点园区&#xff0c;是重点推进的海南自贸港先导项目之一。崖州湾科技城全力抢抓有利时机&#xff0c;进一步拓宽发展思路&#xff0c;持续深化体制机制创新&#xff0c;牢牢把握“打造产学研城深度融合的聚集地”这一核心…

问题:vue2+elementui,tabs切换显示表格并设置表格选中行高亮失败

错误示范&#xff1a; 1.直接setCurrentRow失败&#xff08;this.currentRow是之前保存的表格当前选中行的数据&#xff09; this.$refs.table.setCurrentRow(this.currentRow);2.以为是表格没生成就执行了setCurrentRow导致设置不成功&#xff0c;所以使用了this.$nextTick&…

同为科技(TOWE)桌面PDU插排:一款可以DIY定制的“超级插座”

当今社会&#xff0c;各种电子产品和家用电器已成为人们日常生活中不可或缺的一部分&#xff0c;在带给人们便利的同时&#xff0c;也使得电力使用变得更加频繁和重要。然而&#xff0c;当前市面上很多普通插座由于功能单一、材质粗劣、插口数量受限、充电速度过慢、插头间互相…

人机交互——机器人形态

1.聊天机器人 2.任务型机器人 3.面向FAQ的问答机器人 4.面向KB的问答机器人

seismicunix基础-声波波动方程推导

seismicunix基础-声波波动方程推导 接触波动方程的研究人员都绕不开这个公式&#xff0c;这是在一维状态下波动方程 但是对于这个方程是怎样来的很少有人能说清楚&#xff0c;其中涉及到牛顿第二运动定律&#xff0c;物体的加速度与受到的力有关。 假设一维弦是大量紧密连接的质…

服务器64GB内存、8核CPU的MySQL 8配置参数

服务器64GB内存、8核CPU的MySQL 8配置参数可以按照以下步骤进行调优&#xff1a; 调整缓冲区相关参数&#xff1a; 增加innodb_buffer_pool_size的值&#xff0c;将其设置为4GB或更大&#xff0c;以加速频繁读取的操作。 – 2147483648 增加key_buffer_size的值&#xff0c;将…

ES6 的 class 类和Typescript 的 class 类的区别

前言 为什么要理解ES6的类和TS类的区别&#xff1a; 都是面向对象的开发它们看着很像但是它们不一样学习明白了&#xff0c;避免混用 ES6 类是 JavaScript 中基于原型的面向对象编程的语法糖&#xff0c;而 TypeScript 类在此基础上增加了强类型检查和其他面向对象编程的特性…

智能座舱架构与芯片- (9) 音频篇 上

一、音频总线 音频是智能座舱的核心功能&#xff0c;涵盖车载音响、语音识别、e-Call、消噪及回声消除等应用&#xff0c;随着汽车智能网联化的发展&#xff0c;对音频的开发要求也越来越高。传统的车载音频系统采用模拟并行音频信号传输方式&#xff0c;难以在功能增加与整车…

solr 查询以特殊符号拼接Id成的字段

查询tags字段中包含一个或者多个属性id的数据 查询tags中包含&#xff1a;1或者33的数据 注意&#xff1a;tags分词后

Linux socket编程(5):三次握手和四次挥手分析和SIGPIPE信号的处理

在我之前写的Wireshark抓包&#xff1a;理解TCP三次握手和四次挥手过程中&#xff0c;通过抓包分析了TCP传输的三次握手和四次挥手的过程。在这一节中&#xff0c;将分析在Linux中的三次握手和四次挥手的状态和过程&#xff0c;另外还有一个在我们编程过程中值得注意的SIGPIPE信…