I2C子系统与驱动开发:从协议到实战

Linux I2C子系统与触摸屏驱动开发实战:从协议到框架的嵌入式人机交互实现 I2C总线作为一种简单高效的双线制串行通信协议,是嵌入式系统中连接微控制器与各类传感器、执行器的关键技术。其工作原理基于主从架构,通过时钟同步和数据线实现半双工通信,核心价值在于以极少的引脚资源实现多设备组网,极大简化了硬件设计。在Linux内核中,I2C子系统通过适配器、设备和驱动三层模型,将硬件操作抽象为统一接口,使驱动开发者能专注于设备功能逻辑,显著提升代码可移植性和可维护性。这一框架广泛应用于触摸屏、环境传感器、EEPROM等外设驱动开发。本文以FT5x06电容触摸屏为例,深入剖析了在Tiny441 阅读详情

一、顶级架构一句话总结

i2c_adapter(控制器) ← I2C核心层 → i2c_client(设备) ← i2c_driver(驱动)

I2C子系统采用分层架构,将控制器驱动与设备驱动分离,实现高度复用。


二、I2C子系统架构

架构层次

┌─────────────────────────────────────────────────────────┐
│                   I2C子系统架构                          │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   用户空间    /dev/i2c-X 或 sysfs                       │
│       ↓                                                 │
│   I2C设备驱动  i2c_driver (传感器、EEPROM等)             │
│       ↓                                                 │
│   I2C核心层   i2c-core.c (统一抽象层)                   │
│       ↓                                                 │
│   I2C控制器   i2c_adapter (SoC厂商驱动)                 │
│       ↓                                                 │
│   硬件层      I2C寄存器操作                             │
│                                                         │
└─────────────────────────────────────────────────────────┘

核心数据结构

// I2C适配器(控制器)
struct i2c_adapter {
    struct module *owner;
    unsigned int class;
    const struct i2c_algorithm *algo;  // 传输算法
    void *algo_data;
    struct device dev;
    int nr;                            // 总线编号
    char name[48];
};

// I2C算法
struct i2c_algorithm {
    int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
    int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr, unsigned short flags,
                      char read_write, u8 command, int size, union i2c_smbus_data *data);
    u32 (*functionality)(struct i2c_adapter *adap);
};

// I2C客户端(设备)
struct i2c_client {
    unsigned short flags;        // 标志
    unsigned short addr;         // 设备地址
    char name[I2C_NAME_SIZE];    // 设备名称
    struct i2c_adapter *adapter; // 所属适配器
    struct device dev;           // 内嵌device
    int irq;                     // 中断号
};

// I2C驱动
struct i2c_driver {
    unsigned int class;
    int (*probe)(struct i2c_client *client, const struct i2c_device_id *id);
    int (*remove)(struct i2c_client *client);
    struct device_driver driver;
    const struct i2c_device_id *id_table;
    const struct of_device_id *of_match_table;
};

三、I2C消息传输

i2c_msg结构

struct i2c_msg {
    __u16 addr;      // 设备地址
    __u16 flags;     // 消息标志
    __u16 len;       // 数据长度
    __u8 *buf;       // 数据缓冲区
};

// 常用标志
#define I2C_M_RD          0x0001  // 读操作
#define I2C_M_TEN         0x0010  // 10位地址
#define I2C_M_STOP        0x8000  // 发送STOP
#define I2C_M_NOSTART     0x4000  // 不发送START

传输函数

// 原始传输函数
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);

// SMBus传输
s32 i2c_smbus_read_byte(const struct i2c_client *client);
s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value);
s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command);
s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, u8 value);
s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command);
s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, u16 value);
s32 i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, u8 *values);
s32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values);

四、设备树配置

I2C设备树节点

&i2c1 {
    status = "okay";
    clock-frequency = <400000>;  // 400KHz

    // 温度传感器
    temp_sensor: lm75@48 {
        compatible = "national,lm75";
        reg = <0x48>;  // I2C地址
    };

    // EEPROM
    eeprom@50 {
        compatible = "atmel,24c02";
        reg = <0x50>;
        pagesize = <8>;
    };

    // 触摸屏
    touchscreen@38 {
        compatible = "focaltech,ft5x06";
        reg = <0x38>;
        interrupt-parent = <&gpio>;
        interrupts = <17 IRQ_TYPE_EDGE_FALLING>;
        reset-gpios = <&gpio 16 GPIO_ACTIVE_LOW>;
    };
};

五、I2C设备驱动示例

EEPROM驱动

#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>

#define EEPROM_SIZE 256

struct eeprom_data {
    struct i2c_client *client;
    struct mutex lock;
    u8 *buffer;
};

// 读取EEPROM
static int eeprom_read(struct eeprom_data *data, u8 offset, u8 *buf, int len)
{
    struct i2c_client *client = data->client;
    struct i2c_msg msgs[2];
    int ret;

    mutex_lock(&data->lock);

    // 第一条消息:发送要读取的地址
    msgs[0].addr = client->addr;
    msgs[0].flags = 0;
    msgs[0].len = 1;
    msgs[0].buf = &offset;

    // 第二条消息:读取数据
    msgs[1].addr = client->addr;
    msgs[1].flags = I2C_M_RD;
    msgs[1].len = len;
    msgs[1].buf = buf;

    ret = i2c_transfer(client->adapter, msgs, 2);

    mutex_unlock(&data->lock);

    return ret == 2 ? len : ret;
}

// 写入EEPROM
static int eeprom_write(struct eeprom_data *data, u8 offset, const u8 *buf, int len)
{
    struct i2c_client *client = data->client;
    u8 *write_buf;
    int ret;

    write_buf = kmalloc(len + 1, GFP_KERNEL);
    if (!write_buf)
        return -ENOMEM;

    mutex_lock(&data->lock);

    write_buf[0] = offset;
    memcpy(&write_buf[1], buf, len);

    ret = i2c_master_send(client, write_buf, len + 1);

    mutex_unlock(&data->lock);
    kfree(write_buf);

    return ret > 0 ? len : ret;
}

static int eeprom_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    struct eeprom_data *data;

    data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;

    data->client = client;
    mutex_init(&data->lock);

    i2c_set_clientdata(client, data);

    dev_info(&client->dev, "EEPROM probed at 0x%02x\n", client->addr);
    return 0;
}

static int eeprom_remove(struct i2c_client *client)
{
    dev_info(&client->dev, "EEPROM removed\n");
    return 0;
}

static const struct i2c_device_id eeprom_id[] = {
    { "eeprom_24c02", 0 },
    { }
};
MODULE_DEVICE_TABLE(i2c, eeprom_id);

static const struct of_device_id eeprom_of_match[] = {
    { .compatible = "atmel,24c02", },
    { }
};
MODULE_DEVICE_TABLE(of, eeprom_of_match);

static struct i2c_driver eeprom_driver = {
    .probe = eeprom_probe,
    .remove = eeprom_remove,
    .id_table = eeprom_id,
    .driver = {
        .name = "eeprom_24c02",
        .of_match_table = eeprom_of_match,
    },
};
module_i2c_driver(eeprom_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Driver Developer");

六、SMBus操作示例

温度传感器驱动

#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>

#define LM75_TEMP_REG   0x00
#define LM75_CONF_REG   0x01
#define LM75_THYST_REG  0x02
#define LM75_TOS_REG    0x03

struct lm75_data {
    struct i2c_client *client;
    struct mutex lock;
};

// 读取温度(SMBus方式)
static int lm75_read_temp(struct lm75_data *data)
{
    struct i2c_client *client = data->client;
    s32 raw_temp;
    int temp;

    mutex_lock(&data->lock);

    // 使用SMBus读取16位数据
    raw_temp = i2c_smbus_read_word_swapped(client, LM75_TEMP_REG);

    mutex_unlock(&data->lock);

    if (raw_temp < 0)
        return raw_temp;

    // 转换为摄氏度(0.5度精度)
    temp = (raw_temp >> 5) * 125;

    return temp;
}

// 设置过温阈值
static int lm75_set_threshold(struct lm75_data *data, int temp)
{
    struct i2c_client *client = data->client;
    u16 value;
    int ret;

    // 转换为寄存器格式
    value = (temp / 500) << 7;

    mutex_lock(&data->lock);
    ret = i2c_smbus_write_word_swapped(client, LM75_TOS_REG, value);
    mutex_unlock(&data->lock);

    return ret;
}

static int lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    struct lm75_data *data;

    if (!i2c_check_functionality(client->adapter,
                                  I2C_FUNC_SMBUS_BYTE_DATA |
                                  I2C_FUNC_SMBUS_WORD_DATA))
        return -EIO;

    data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;

    data->client = client;
    mutex_init(&data->lock);

    i2c_set_clientdata(client, data);

    dev_info(&client->dev, "LM75 temperature sensor probed\n");
    return 0;
}

static const struct i2c_device_id lm75_id[] = {
    { "lm75", 0 },
    { }
};
MODULE_DEVICE_TABLE(i2c, lm75_id);

static const struct of_device_id lm75_of_match[] = {
    { .compatible = "national,lm75", },
    { }
};
MODULE_DEVICE_TABLE(of, lm75_of_match);

static struct i2c_driver lm75_driver = {
    .probe = lm75_probe,
    .id_table = lm75_id,
    .driver = {
        .name = "lm75",
        .of_match_table = lm75_of_match,
    },
};
module_i2c_driver(lm75_driver);

MODULE_LICENSE("GPL");

七、I2C控制器驱动

简化的控制器驱动框架

static int my_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
    struct my_i2c_dev *dev = i2c_get_adapdata(adap);
    int i, ret;

    for (i = 0; i < num; i++) {
        // 发送START
        my_i2c_start(dev);

        // 发送地址
        ret = my_i2c_send_addr(dev, msgs[i].addr, msgs[i].flags & I2C_M_RD);
        if (ret < 0)
            break;

        // 传输数据
        if (msgs[i].flags & I2C_M_RD)
            ret = my_i2c_read(dev, msgs[i].buf, msgs[i].len);
        else
            ret = my_i2c_write(dev, msgs[i].buf, msgs[i].len);

        if (ret < 0)
            break;
    }

    // 发送STOP
    my_i2c_stop(dev);

    return i;
}

static u32 my_i2c_func(struct i2c_adapter *adap)
{
    return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}

static const struct i2c_algorithm my_i2c_algo = {
    .master_xfer = my_i2c_xfer,
    .functionality = my_i2c_func,
};

static int my_i2c_probe(struct platform_device *pdev)
{
    struct my_i2c_dev *dev;
    struct i2c_adapter *adap;
    int ret;

    dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
    if (!dev)
        return -ENOMEM;

    // 初始化硬件...

    adap = &dev->adapter;
    adap->owner = THIS_MODULE;
    adap->algo = &my_i2c_algo;
    adap->dev.parent = &pdev->dev;
    snprintf(adap->name, sizeof(adap->name), "my_i2c");

    i2c_set_adapdata(adap, dev);

    ret = i2c_add_adapter(adap);
    if (ret)
        return ret;

    platform_set_drvdata(pdev, dev);
    return 0;
}

static int my_i2c_remove(struct platform_device *pdev)
{
    struct my_i2c_dev *dev = platform_get_drvdata(pdev);
    i2c_del_adapter(&dev->adapter);
    return 0;
}

八、调试技巧

查看I2C总线

# 查看I2C总线
ls /dev/i2c-*

# 查看I2C设备
i2cdetect -l
i2cdetect -y 1

# 读取寄存器
i2cget -y 1 0x48 0x00

# 写入寄存器
i2cset -y 1 0x48 0x00 0x55

# dump寄存器
i2cdump -y 1 0x48

内核调试

# 查看I2C设备
ls /sys/bus/i2c/devices/

# 查看设备信息
cat /sys/bus/i2c/devices/1-0048/name

# 查看内核日志
dmesg | grep -i i2c

九、终极总结

I2C子系统 = 分层架构的典范

  • 核心概念:adapter(控制器)、client(设备)、driver(驱动)
  • 传输方式:i2c_transfer(原始)、SMBus(简化)
  • 设备树:通过reg属性指定I2C地址
  • 调试工具:i2cdetect、i2cget、i2cset

掌握I2C子系统,就掌握了总线类驱动的开发模式!

Linux多点触控驱动开发实战:以FT5436为例详解I2C、输入子系统与Type B协议 在嵌入式Linux系统开发中,输入设备驱动是连接硬件与用户交互的关键桥梁。其核心原理在于通过中断机制感知硬件状态变化,并遵循特定的输入事件协议,将物理信号转换为操作系统可识别的标准事件。这一技术价值在于为触摸屏、键盘、传感器等提供了统一的软件抽象层,极大简化了应用开发。在多点触控这一典型应用场景中,Linux内核定义了Type A和Type B两套协议来管理多个触控点。本文以敦泰FT5436触控芯片为例,深入剖析一个完整的工业级驱动实现。驱动通过I2C总线与主控通信,在设备探测(Probe)阶段完成硬件参数 阅读详情

相关推荐

【Linux 驱动开发】Linux Input 子系统与 I²C 驱动全景解析(键盘 / 触摸屏 / 鼠标)

本文全面解析Linux内核中的I²C子系统框架及其协议实现,重点介绍I²C驱动开发流程。文章首先回顾Input子系统三层架构(硬件适配层、协议/驱动层、核心仲裁层),随后详细阐述I²C子系统的三层次结构(i2c-driver层、i2c-core层、i2c-adapter层),并配以STM32MP1平台示例。第二部分深入讲解I²C协议规范,包括读/写操作时序、信号类型(开始/结束/响应)以及双向传输实现原理,通过开漏电路示意图说明多设备共享总线的机制。

猫猫的小茶馆 1083

第14章 Linux I2C子系统与设备驱动开发全面解析

Linux I2C子系统与设备驱动开发全面解析。

小宝哥Code的专栏 351

OpenBMC内核驱动调试与优化实战:基于Yocto的PMBUS驱动开发进阶指南

本文深入探讨了OpenBMC内核驱动调试与优化实战,重点介绍了基于Yocto的PMBUS驱动开发进阶技巧。从基础开发环境搭建到高级调试方法,详细解析了PMBUS协议实现、Yocto集成优化以及性能调优策略,帮助开发者解决实际项目中的电源管理总线驱动开发难题。

weixin_29168813的博客 281

深入解析I2C总线:从协议基础到Linux驱动实践

本文深入解析I2C总线协议,从基础原理、工作时序到多主机仲裁机制,结合STM32硬件实践和AP3216传感器开发案例,详细讲解Linux I2C子系统架构、设备树配置及驱动开发,提供调试技巧与性能优化方案,帮助开发者掌握I2C通信技术。

happy2的博客 618

ARM Linux驱动开发

先在设备树中建立设备节点,并给定compatible;编写驱动代码,代码中实现platform_driver结构体中的probe remove 函数并设置driver结构体中的name:驱动名称以及设备树匹配表:of_match_table。在驱动的入口函数中需要使用 platform_driver_register 注册;在驱动卸载函数中需要调用 platform_driver_unregister 进行卸载。仍然按照字符设备的驱动开发模式,使用 pinctl 和 gpio 子系统设置设备信息。

m0_62467238的博客 354

基于i2c子系统的驱动分析

和i2c有关的代码都在源码drivers/i2c目录下。内核提供了两种i2c的实现方法: 第一种叫i2c_dev,对应drivers/i2c/i2c-dev.c,这种方法仅仅封装了soc的i2c控制器操作,并向应用层提供操作接口。其本质是为应用层提供了一个库,驱动功能由应用层实现,不是主流的做法 第二种是驱动层实现所有驱动功能,是比较主流的做法

XiaoBaWu的博客 4665

deepin-community/kernel I2C总线:传感器与芯片通信

你是否曾经好奇过,智能手机如何感知环境温度?智能家居设备如何检测运动?工业设备如何监控压力变化?这一切的背后,都离不开一个关键的通信协议——I2C(Inter-Integrated Circuit)总线。在deepin-community/kernel项目中,I2C子系统扮演着连接传感器与主控芯片的桥梁角色,为现代嵌入式系统提供了高效、可靠的通信解决方案。 通过本文,你将深入了解: - I2C...

gitblog_00599的博客 1165

I2C子系统

串行、半双工总线,主要用于低速、近距离的芯片之间的通信。

HRad7282的博客 1323

linux内核I2C子系统详解

I2C子系统

weixin_42031299的博客 9690

【linux iic子系统】i2c设备与驱动匹配过程(三)

本文讲解基于linux4.18内核。 重要 根据前面内容我们可以知道i2c子系统有几个重要的东西: I2C总线:i2c总线主要就是维护着两个链表——驱动、设备。i2c驱动注册时候,通过i2c_driver结构体内部driver成员挂载到总线上。i2c设备注册时候,通过i2c_client结构体内部device成员挂载到总线上。所以总线作用就是i2c设备和I2C驱动的匹配和删除等。值得注意的是,i2c适配器也是挂在总线上(它的作用会在《i2c设备添加方法》章节里说明)! I2C驱动:使用i.

zz2633105的博客 4452

鸿蒙OpenHarmony【平台驱动开发之I2C】 子系统

I2C(Inter Integrated Circuit)总线是由Philips公司开发的一种简单、双向二线制同步串行总线。由于其硬件连接简单、成本低廉,因此被广泛应用于各种短距离通信的场景。

zxc95279527q的博客 1229

I2C子系统框架入门—i2c驱动示例

在这个流程中,驱动程序(即你的代码)负责发起I²C命令请求,而实际的数据传输和命令执行由I²C控制器完成。I²C控制器是硬件层面的存在,它通过I²C总线执行读写操作,将驱动程序的请求发送到物理设备上。

weixin_46999174的博客 1752

ARM9嵌入式Linux I2C接口开发实战指南

ARM9处理器是一款广泛应用于嵌入式系统的处理器,它支持多种外设接口,其中就包括I2C接口。I2C接口是许多电子设备中常见的一种串行通信协议,它允许多个从设备连接到同一个主设备上。在ARM9处理器中,I2C接口通过其内部的I2C控制器来实现。接下来,我们将探讨ARM9处理器的I2C控制器特性和Linux内核中的I2C子系统架构。i2cdetect:用于探测连接到I2C总线上的所有设备,并列出它们的地址。i2cget:用于从I2C设备的某个寄存器中读取数据。i2cset。

weixin_33557333的博客 1142

【入门到实战】OpenHarmony子系统平台驱动开发:I2C

I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。

Androidbye的博客 931

EMC测试案例分析——晶振对辐射发射的影响

本文分析了某产品350MHz辐射发射超标问题,发现源头是50MHz晶振的7次谐波通过连接器泄漏。主要原因是:1)防水非导电垫圈形成屏蔽缝隙;2)晶振下方地平面不完整且信号线穿过;3)晶振离接口过近。改进措施包括:完善晶振下方地平面、增大晶振与接口距离、使用导电密封圈等。最终辐射降低10dB以上达标。文章总结了晶振EMC设计要点:保持地平面完整、远离接口、外壳接地、合理布局滤波电路等,并强调防水与屏蔽的协调统一。

u012526819的博客 668

最新 抖音 X-Gorgon 0408 和8408 设备注册协议

抖音app先是检测了你的手机cpu架构,是x86还是armeabi,通过cpu架构的不同来调用so内不同的xg方法,所以导致现在最新版抖音app的xg算法有0408和8408两种。两种都是最新版,因为我发现当我使用oppo手机安装最新版抖音抓包的xg是8408,而当我用小米或者华为安装最新版抖音,抓包以后发现xg是0408。抖音IOS XG84 设备注册激活协议代码片段。...

Q44804487的博客 1万+

Linux I2C驱动开发:从协议到子系统的深度解析

本文深度解析Linux I2C驱动开发,从I2C协议基础、硬件时序到Linux I2C子系统架构,涵盖适配器驱动层与设备驱动层的实现。通过对比设备树与非设备树开发模式,提供实战编写指南和调试技巧,帮助开发者掌握I2C驱动开发核心,解决常见通信问题并优化性能。

2w3e4r5t6y的博客 1010

持续集成介绍及Jenkins自动化测试部署

学习持续集成及jenkins的自动化测试部署

ouihsiad的博客 4575

[驱动之路(二)——I2C子系统] 学习总结,万字长篇,一文彻底搞懂I2C子系统(含通用I2C设备驱动和控制器驱动框架解析)

本文系统介绍了I2C总线协议及其在Linux内核中的实现框架。主要内容包括:1. I2C协议基础:双线通信机制、主从架构、传输时序等核心特性;2. Linux I2C子系统关键结构体:i2c_adapter、i2c_client、i2c_driver等;3. 驱动架构分析:详细剖析了通用i2c-dev接口和专用设备驱动两种访问路径;4. 总线-设备-驱动模型:深入讲解匹配机制和设备创建方式;5. 开发框架:提供完整的I2C设备驱动和控制器驱动实现模板。文章从硬件原理到软件实现,全面覆盖了I2C技术在嵌入式L

qq_63718344的博客 2127

别再只盯着YOLOv8了!手把手带你用PaddleDetection的PP-YOLOE+搞定你的第一个检测项目

本文介绍了PP-YOLOE+在目标检测领域的优势与应用实践,对比YOLOv8展示其在精度、速度和部署便利性上的突破。通过详细的代码示例和实战教程,帮助开发者快速上手PaddleDetection工具链,实现产业级目标检测项目,提升开发效率。

weixin_42701915的博客 184

HHD Device Monitoring Studio:破解版在串口调试中的实战应用

本文详细介绍了HHD Device Monitoring Studio破解版在串口调试中的实战应用,包括安装指南、串口监控功能解析、Modbus RTU协议分析案例以及自定义协议解析技巧。通过具体操作步骤和性能优化建议,帮助开发者高效完成端口监控和调试任务,提升工作效率。

weixin_29268331的博客 937

I2C 子系统与驱动开发入门

在 RK3588 等瑞芯微平台及各类嵌入式 Linux 系统中,I2C 是最常见的低速通信总线。无论是温湿度传感器、陀螺仪、电源管理芯片 (PMIC),还是触控 IC、显示接口转换芯片,绝大多数外设都依赖 I2C 进行控制。 本文将从零开始,构建一个完整的 I2C 设备驱动,掌握从设备树描述到驱动代码实现的全流程,并介绍工业级驱动开发常用的 regmap 框架。

专注Linux内核驱动开发15年+,致力于让天下没有难写的驱动。 785

达摩院高清人像美肤模型ABPN的深入解析及编程实现

本文深入解析了达摩院高清人像美肤模型ABPN的原理,并提供了相应的源代码实现。ABPN模型通过自适应的反投影网络,有效地实现了人像图像的美肤处理。通过进一步的研究和优化,ABPN模型有望在人像美肤领域发挥更大的作用。低频特征提取器用于提取输入图像的低频信息,而反投影网络则负责将低频信息与原始图像结合,生成美肤后的输出图像。通过将输入图像送入ABPN模型,即可得到经过美肤处理后的输出图像。通过对输入图像进行美肤处理,可以有效地去除皮肤上的瑕疵和噪点,提升图像质量和美感。

TechPulseZ的博客 711

「Linux驱动开发」--- I2C子系统

实际I2C设备连接时,主要是由两个东西I2C设备:所连接的外设I2C适配器:SOC上的一个硬件,用于进行I2C协议的解析和生成,总之,I2C设备必须连接到I2C适配器上面而在Linux的I2C的设备驱动模型中,一共涉及到以下几个概念I2C总线(i2c_bus):管理挂载在I2C总线下的设备和驱动维护I2C驱动和I2C设备两个链表,管理I2C驱动和I2C设备的匹配、删除等;i2c适配器驱动(i2c_adapter的driver):不需要我们去编写的驱动「芯片厂商已经写好了」,这。

m0_60616918的博客 1241

wxComboBox类的使用方法及示例代码

其中,parent表示该控件的父窗口,ID_COMBOBOX是该控件的ID,用于在事件处理函数中区分不同的控件,"默认选项"是下拉列表框的默认选项,options是wxArrayString类型的数组,用于存储下拉列表框中的选项,style可以指定wxComboBox的样式。wxComboBox是wxWidgets中的一个常用控件,它可以被用来显示一组在下拉列表框中的选项,并允许用户从中选择一个选项。上述就是wxComboBox类的基本使用方法,使用这个控件可以方便地实现下拉列表框的功能。

学习使你进步。 712

ThingsBoard教程(十九):规则节点概览介绍

在ThingsBoard的CE V2.5.6版本中,一共有这几种类型在每一种类都有包含了多个节点,每一种类型的节点都有不同的颜色表示本篇文章做一个简单的概括,后续的文章会详细讲解每一个种类的节点如何使用,每一个节点的使用。一共有10个,使用黄色表示 过滤器节点用于消息过滤和路由。一共有9个,使用绿色 属性节点用于更新传入消息的元数据。一共三个,使用蓝色 转换节点用于更改传入消息字段,如发起者、消息类型、有效负载和元数据。一共21个,使用红色标识 动作节点根据传入的消息执行各种动作。一共9个,使用黄色表示,

知无涯 1万+
上一篇: 中断处理与并发控制:Linux驱动开发的核心难题破解
下一篇: 内核定时器与延迟工作:时间管理的艺术
LinuxRos
博客等级 码龄5年 11粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值