当前位置: 首页 > news >正文

consumer 角度讲一下i2c外设

往期内容

I2C子系统专栏:

  1. I2C(IIC)协议讲解-CSDN博客
  2. SMBus 协议详解-CSDN博客
  3. I2C相关结构体讲解:i2c_adapter、i2c_algorithm、i2c_msg-CSDN博客
  4. 内核提供的通用I2C设备驱动I2c-dev.c分析:注册篇
  5. 内核提供的通用I2C设备驱动I2C-dev.c分析:file_ops篇
  6. 设备驱动与设备树匹配机制详解
  7. 编写一个通用的i2c设备驱动框架
  8. 编写一个通用的i2c控制器驱动框架

总线和设备树专栏:

  1. 总线和设备树_憧憬一下的博客-CSDN博客
  2. 设备树与 Linux 内核设备驱动模型的整合-CSDN博客

前言

在上一章节(编写一个通用的i2c控制器驱动框架)讲了i2c_adapter。这里再继之前的文章( 编写一个通用的i2c设备驱动框架)进行补充,讲一下l2c_cleint的设备形态等

1. 两种设备形态

img

可以看出是有两种你描述的这两种设备形态反映了设备通过不同的总线进行交互的差异,并且在设备树(DTS)和驱动程序的编写上有不同的表现。根据设备的主要功能和数据传输方式,它们在 Linux 设备模型中的位置不同,从而影响了 DTS 文件中的结构和驱动程序的设计。我们来分析这两种设备形态。

形态 1: I2C-only 设备(图左侧):

  • 特点:这类设备和 CPU 之间的所有数据交互都是通过 I2C 总线完成的,没有其他传输方式。
  • DTS 描述:设备直接作为 I2C 控制器的子节点存在。在 DTS 中,设备的定义紧随其所在的 I2C 总线节点之后。例如 PMIC,它是 I2C 总线上的一个设备,因此直接在 I2C 节点的子节点中定义。
&i2c1 {clock-frequency = <100000>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c1>;status = "okay";pmic: pf0100@08 {compatible = "fsl,pfuze100";reg = <0x08>;...};
};
  • 驱动模型:I2C 核心负责处理设备的创建和注册。驱动程序是以 I2C slave 设备的方式来实现,I2C 驱动框架通过 i2c_driver 结构和 i2c_device_id 来与设备匹配。设备的 proberemove 等函数由 I2C 核心进行管理。
static const struct i2c_device_id pmic_i2c_ids[] = {{ "pfuze100", 0 },{ /* sentinel */ }
};static struct i2c_driver pmic_driver = {.driver = {.name = "pfuze100",.of_match_table = pmic_of_match,},.probe = pmic_probe,.remove = pmic_remove,.id_table = pmic_i2c_ids,
};

I2C 是主数据交互总线,设备完全依赖 I2C,所有操作通过 I2C 完成。

驱动注册流程通过 I2C 子系统的 i2c_driver 完成,设备由 I2C 核心管理。


形态 2: 复合设备(I2C 作为辅助接口,图右侧):

  • 特点:这类设备通过多种方式与 CPU 交互,例如,主要的数据传输(如音视频数据)通过 TDMS 接口,而配置信息或控制信息通过 I2C(DDC)接口。这类设备的核心功能决定了它们的主要位置在其他总线(如平台总线 platform bus)上,而 I2C 只是作为一个辅助接口。
  • DTS 描述:HDMI 设备作为 platform device 定义,并且通过 ddc-i2c-bus 属性引用 I2C 总线,用于 DDC(Display Data Channel)接口的 I2C 通信。
&hdmi {ddc-i2c-bus = <&i2c2>;status = "okay";
};
  • 驱动模型:在这种情况下,HDMI 控制器是主要设备,注册为 platform_device。I2C 通信是 HDMI 控制器的一部分,用来处理 EDID 等信息读取。在驱动程序中,I2C 总线是通过 DTS 中的 ddc-i2c-bus 属性传递给 HDMI 驱动的,驱动程序会通过 of_find_i2c_adapter_by_node() 获取并绑定 I2C 控制器。
struct i2c_adapter *ddc;
struct device_node *ddc_node;ddc_node = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
if (!ddc_node) {dev_err(dev, "failed to find ddc-i2c-bus node\n");return -ENODEV;
}ddc = of_find_i2c_adapter_by_node(ddc_node);
of_node_put(ddc_node);
if (!ddc)return -EPROBE_DEFER;/* Use ddc for I2C transactions */

I2C 是辅助总线,用于少量数据交互(如 EDID、配置信息传输),主要功能通过其他总线(如 TDMS)完成。

驱动以 platform_device 形式注册,I2C 仅作为其中一个通信接口,I2C 控制器通过设备树中的引用绑定。

2. 驱动编写

根据上面所说的形态去编写设备不同的i2c_driver

形态1: 完全依赖I2C的设备(如PMIC)

  1. 确定I2C adapter
    根据设备硬件连接的实际情况,确定该设备所从属的I2C controller,即I2C adapter(在I2C framework中,I2C controller通常被称为I2C adapter)。例如,PMIC设备可能连接在 i2c1 总线上。
  2. 在DTS中添加设备描述
    在设备树的I2C adapter节点中,添加I2C从设备的描述。这个从设备的定义格式与普通的platform device一致,例如:
&i2c1 {pmic: pfuze100@08 {compatible = "fsl,pfuze100";reg = <0x08>;// 其他字段...};
};
  1. compatible 字段的使用
    DTS 中的 compatible 字段用于设备驱动的匹配和 probe。I2C驱动会根据 compatible 字段匹配到合适的驱动程序,例如 "compatible = "fsl,pfuze100";"
  2. 编写I2C设备的驱动程序

示例:

static const struct of_device_id pmic_of_match[] = {{ .compatible = "fsl,pfuze100", },{ /* sentinel */ }
};static struct i2c_driver pmic_driver = {.driver = {.name = "pfuze100",.of_match_table = pmic_of_match,},.probe = pmic_probe,.remove = pmic_remove,
};
static int __init i2c_driver_XXX_init(void)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return i2c_add_driver(&i2c_XXX_driver);
}
module_init(i2c_driver_XXX_init);
    • 定义并注册 i2c_driver:编写一个 struct i2c_driver 结构体,并使用 i2c_add_driver将其注册到I2C core中。
    • 匹配设备:在 i2c_driver 结构体中,定义 of_match_table,使其可以通过 compatible 字段进行匹配。
    • 实现 probe 回调:编写 probe 函数,用于设备初始化。
  1. I2C core处理设备注册
    当I2C adapter注册时,I2C framework的核心代码会自动为其下的所有I2C从设备创建 struct i2c_client 结构体,并根据设备树中的 compatible 字段,匹配合适的 i2c_driver,然后调用驱动程序的 probe 函数。
  2. probe
    当设备被I2C framework匹配到时,调用此函数进行设备初始化。主要负责获取设备资源(如设备地址、I2C Adapter),设置硬件寄存器,或者初始化其他系统资源(如注册字符设备)。
static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{// 打印日志确认 probe 触发printk(KERN_INFO "ap3216c i2c device probe.\n");// 设置I2C client指针ap3216c_client = client;// 执行设备初始化:如设置初始寄存器值i2c_smbus_write_byte_data(client, 0x00, 0x03);  // 设置某些寄存器// 注册字符设备或其他资源major = register_chrdev(0, "ap3216c", &ap3216c_ops);ap3216c_class = class_create(THIS_MODULE, "ap3216c_class");device_create(ap3216c_class, NULL, MKDEV(major, 0), NULL, "ap3216c");return 0;
}

在注册的ap3216c_ops中,有关read和write的函数,使用到I2C数据有关的接口就有两类:

  • 一类是以i2c client为参数,进行简单的数据收发。该方法只可以通过标准方式,发送或者接收一定数量的数据。
  • 另一类是以i2c adapter和i2c msg为参数,可以更为灵活的read或者write数据,包括i2c_transfer。使用该方法可以以struct i2c_msg为参数,一次读取、或者写入、或者读取加写入,一定数量的数据。
  • 具体的函数去看\Linux-4.9.88\include\linux\i2c.h

形态2: 复合型设备(如HDMI)

  1. 确定I2C adapter
    根据设备硬件的连接方式,找到设备使用的I2C adapter。例如,HDMI 设备可以使用 i2c2 作为其 DDC 通道。
  2. 将设备作为平台设备描述
    将设备作为平台设备(platform device)进行描述。其 DTS 节点并不是直接位于I2C adapter下,而是位于根目录。例如:
&hdmi {ddc-i2c-bus = <&i2c2>;status = "okay";
};
  1. 获取I2C adapter的引用
    在DTS描述中使用 ddc-i2c-bus 属性引用I2C adapter节点。该属性通过 of_parse_phandle 来解析,并在驱动中获取相应的I2C adapter的指针。
  2. probe 函数中获取I2C adapter
    在平台设备的 probe 函数中,通过 of_parse_phandle 来获取I2C adapter节点,并通过 of_find_i2c_adapter_by_node() 获取对应的 struct i2c_adapter 指针。如下代码示例:
struct i2c_adapter *ddc;
struct device_node *ddc_node;ddc_node = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
if (!ddc_node) {dev_err(dev, "failed to find ddc-i2c-bus node\n");return -ENODEV;
}ddc = of_find_i2c_adapter_by_node(ddc_node);
of_node_put(ddc_node);
if (!ddc)return -EPROBE_DEFER;
  1. 使用 i2c_transfer 进行读写操作
    获取I2C adapter之后,便可以使用 i2c_transfer() 接口来进行I2C读写操作。例如,通过DDC接口读取EDID信息时:
struct i2c_msg msgs[] = {{.addr = ddc_addr,.flags = I2C_M_RD,.len = 128,.buf = edid_buf,},
};ret = i2c_transfer(ddc, msgs, 1);  // 读取EDID数据

3. i2c_client

i2c设备中用i2c_client结构体来指代:

/*** struct i2c_client - represent an I2C slave device* @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;*	I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking* @addr: Address used on the I2C bus connected to the parent adapter.* @name: Indicates the type of the device, usually a chip name that's*	generic enough to hide second-sourcing and compatible revisions.* @adapter: manages the bus segment hosting this I2C device* @dev: Driver model device node for the slave.* @irq: indicates the IRQ generated by this device (if any)* @detected: member of an i2c_driver.clients list or i2c-core's*	userspace_devices list* @slave_cb: Callback when I2C slave mode of an adapter is used. The adapter*	calls it to pass on slave events to the slave driver.** An i2c_client identifies a single device (i.e. chip) connected to an* i2c bus. The behaviour exposed to Linux is defined by the driver* managing the device.*/
struct i2c_client {unsigned short flags;		/* div., see below		*/unsigned short addr;		/* chip address - NOTE: 7bit	*//* addresses are stored in the	*//* _LOWER_ 7 bits		*/char name[I2C_NAME_SIZE];struct i2c_adapter *adapter;	/* the adapter we sit on	*/struct device dev;		/* the device structure		*/int irq;			/* irq issued by device		*/struct list_head detected;
#if IS_ENABLED(CONFIG_I2C_SLAVE)i2c_slave_cb_t slave_cb;	/* callback for slave mode	*/
#endif
};

flags:

  • 表示I2C设备的标志位。可以包含以下选项:

    • I2C_CLIENT_TEN:表示设备使用的是十位地址(而不是常见的七位地址)。
    • I2C_CLIENT_PEC:表示设备使用SMBus包错误校验(Packet Error Checking,PEC),这是一种错误检测机制。

addr:

  • I2C设备的地址。地址位于I2C总线上的低7位或低10位(如果 flags 指示设备使用十位地址的话)。

name:

  • 一个字符数组,表示设备的名称,通常是设备的芯片名称或类型。名称尽可能保持通用,以适应同一设备的不同版本或兼容的设备。

adapter:

  • 指向设备所在的I2C总线适配器(i2c_adapter)的指针。每个I2C设备都挂载在一个I2C适配器上,适配器管理与设备的通信。

dev:

  • Linux驱动模型中的设备节点(struct device),用于表示I2C从设备。这是Linux设备模型的标准数据结构,提供了与设备类、驱动程序以及电源管理等相关的接口。

irq:

  • 表示设备所使用的中断号(如果该设备可以生成中断)。不使用中断的设备此字段可能为0或无效值。

detected:

  • 用于链表结构中的节点。在内核中,这个字段用于将该设备连接到 i2c_driver.clients 列表或 i2c-coreuserspace_devices 列表中。

slave_cb:

  • 仅在启用了 I2C Slave 模式(即 CONFIG_I2C_SLAVE 选项启用时)时有效。
  • 这是用于适配器从模式的回调函数指针。当I2C适配器处于从模式时,适配器调用这个回调函数,将从模式的事件传递给从设备的驱动程序。

i2c_client一般是在register adapter的时候,解析adapter的child node自行创建的,这个在对上一章节中对i2c_add_adapte函数进行分析的时候有提到过

相关文章:

consumer 角度讲一下i2c外设

往期内容 I2C子系统专栏&#xff1a; I2C&#xff08;IIC&#xff09;协议讲解-CSDN博客SMBus 协议详解-CSDN博客I2C相关结构体讲解:i2c_adapter、i2c_algorithm、i2c_msg-CSDN博客内核提供的通用I2C设备驱动I2c-dev.c分析&#xff1a;注册篇内核提供的通用I2C设备驱动I2C-dev.…...

面试经典150题刷题记录

数组部分 1. 合并两个有序的子数组 —— 倒序双指针避免覆盖 88. 合并两个有序数组 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使…...

【HarmonyOS NEXT】实现保存base64图片到图库

上篇文章介绍了HarmonyOS NEXT如何保存base64文件到download目录下&#xff0c;本次介绍如何保存base64图片到图库&#xff0c;网络图片保存方式大同小异&#xff0c;先下载图片&#xff0c;然后再保存 phAccessHelper.showAssetsCreationDialog参考官方文档’ ohos.file.pho…...

开题答辩最怕被问什么?教你用ChatGPT轻松准备,稳拿高分!

AIPaperGPT&#xff0c;论文写作神器~ https://www.aipapergpt.com/ 开题答辩是学位论文写作过程中的重要环节&#xff0c;能帮助导师评估你的研究计划是否可行&#xff0c;并对后续写作起到指导作用。很多同学在面对导师提问时会感到紧张&#xff0c;因此提前准备好常见问题的…...

Unity3D功耗和发热分析与优化详解

前言 Unity3D作为广泛使用的游戏开发引擎&#xff0c;在游戏开发过程中&#xff0c;功耗和发热问题一直是开发者需要重点关注的问题。功耗和发热不仅影响用户体验&#xff0c;还可能对设备的硬件寿命造成一定影响。本文将从技术角度详细分析Unity3D游戏在移动设备上的功耗和发…...

深度学习中的掩码介绍

在深度学习中,**掩码(Mask)**通常用于屏蔽掉某些特定部分的数据,以确保模型在训练或推理时不处理无效或无关的输入。掩码的使用场景主要包括处理变长序列、生成模型中的自回归任务、处理填充数据等。掩码可以是二值矩阵(1 表示有效数据,0 表示屏蔽数据),在注意力机制中…...

rust高级进阶总结

文章目录 前言1. Rust生命周期进阶一、不太聪明的生命周期检查&#xff08;一&#xff09;例子1&#xff08;二&#xff09;例子2 二、无界生命周期三、生命周期约束&#xff08;HRTB&#xff09;&#xff08;一&#xff09;语法及含义&#xff08;二&#xff09;综合例子 四、…...

整理—计算机网络

目录 网络OSI模型和TCP/IP模型 应用层有哪些协议 HTTP报文有哪些部分 HTTP常用的状态码 Http 502和 504 的区别 HTTP层请求的类型有哪些&#xff1f; GET和POST的使用场景&#xff0c;有哪些区别&#xff1f; HTTP的长连接 HTTP默认的端口是什么&#xff1f; HTTP1.1怎…...

分布式数据库环境(HBase分布式数据库)的搭建与配置

分布式数据库环境&#xff08;HBase分布式数据库&#xff09;的搭建与配置 1. VMWare安装CentOS7.9.20091.1 下载 CentOS7.9.2009 映像文件1.2启动 VMware WorkstationPro&#xff0c;点击“创建新的虚拟机”1.3在新建虚拟机向导界面选择“典型&#xff08;推荐&#xff09;”1…...

100个JavaWeb(JDBC, Servlet, JSP)毕业设计选题

100个JavaWeb(JDBC, Servlet, JSP)毕业设计选题 教育行业 学生信息管理系统在线考试系统课程管理与选课系统教师评价管理系统图书馆管理系统学生成绩查询系统校园论坛作业提交与批改系统学生考勤管理系统教学资源共享平台 企业管理 员工管理系统考勤打卡系统办公用品申请管…...

05 go语言(golang) - 常量和条件语句

常量 在Go语言中&#xff0c;常量是使用 const 关键字定义的&#xff0c;并且一旦被赋值后&#xff0c;它们的值在程序运行期间不能改变。常量可以是字符、字符串、布尔或数值类型。 基本特性 不可修改&#xff1a;一旦一个常量被定义&#xff0c;它的值就不能被更新。编译时…...

【设计模式】深入理解Python中的适配器模式(Adapter Pattern)

深入理解Python中的适配器模式&#xff08;Adapter Pattern&#xff09; 在软件开发中&#xff0c;常常会遇到需要让不兼容的类或接口协同工作的问题。适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;通过提供一个包装器对象&#xff0c;…...

RuoYi-Vue若依框架-后端设置不登陆访问(白名单)

找到SecurityConfig类 确认自己的需求 /*** anyRequest | 匹配所有请求路径* access | SpringEl表达式结果为true时可以访问* anonymous | 匿名可以访问* denyAll | 用户不能访问* fullyAuthenticated | 用户完全认证可…...

C语言初阶小练习2(三子棋小游戏的实现代码)

这是C语言小游戏三子棋的代码实现 test.c文件是用来测试的部分 game.h文件是用来声明我们说写出的函数 game.c文件是用来编写我们的功能实现函数部分 1.test.c #define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" void menu() {printf("***************…...

金融行业合同管理如何利用AI技术进行风险预警?

2024年以来&#xff0c;金融行业的发展主线被锚定&#xff0c;强调了防风险的基调&#xff0c;尤其是系统性风险的防范。金融工作的重点在于实现六个强大&#xff1a;强大的货币、强大的中央银行、强大的金融机构、强大的国际金融中心、强大的金融监管、强大的金融人才队伍。这…...

世界数字农业盛宴与技术探索,25年3月聚焦世界灌溉科技大会

由中国农业节水和农村供水技术协会、中国农垦节水农业产业技术联盟、北京物联网智能技术应用协会、振威国际会展集团主办的“世界灌溉科技大会”、“第11届北京国际数字农业与灌溉技术博览会”&#xff0c;定于2025年3月31日至4月2日在北京国家会议中心举办。 作为世界三大灌溉…...

二百六十九、Kettle——ClickHouse清洗ODS层原始数据增量导入到DWD层表中

一、目的 清洗ClickHouse的ODS层原始数据&#xff0c;增量导入到DWD层表中 二、实施步骤 2.1 newtime select( select create_time from hurys_jw.dwd_statistics order by create_time desc limit 1) as create_time 2.2 替换NULL值 2.3 clickhouse输入 2.4 字段选择 2.5 …...

Maya---骨骼绑定

调节骨骼大小 回车键确认骨骼 FK子集跟父集走 IK子集不跟父集走 前视图中按shift键添加骨骼 清零、删除历史记录&#xff0c;创建新的物体...

携手并进,智驭教育!和鲸科技与智谱 AI 签署“101 数智领航计划”战略合作协议

近日&#xff0c;上海和今信息科技有限公司&#xff08;以下简称“和鲸科技”&#xff09;与北京智谱华章科技有限公司&#xff08;以下简称“智谱 AI”&#xff09;签署“101 数智领航计划”战略合作协议。双方将携手营造智能化学科教育与科研环境&#xff0c;提供多种大模型工…...

牛客周赛63

https://ac.nowcoder.com/acm/contest/91592 好数 简单的判断两位数&#xff0c;且十位等于个位 #include <bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define int long long using namespace std; using ll long long; using pii …...

git restore恢复删除文件

新版本 在 Git 2.23 版本之后&#xff0c;Git 引入了一个新的命令 git restore&#xff0c;用于简化文件恢复操作。可以用 git restore 来恢复误删除的文件。下面是详细的使用方法&#xff1a; 1. 恢复工作区中删除的文件&#xff08;未提交&#xff09; 如果文件已被删除&a…...

MacOS13虚拟机VMware Workstation Pro 16安装

资源 安装unlocker 安装虚拟机 低版本的还没有MacOS13选项&#xff0c;这也是我安装低版本虚拟机踩过的坑 找个教程安装就可以了 省略…自己去找找教程… 过程中我使用桥接是不行的&#xff0c;没有网络&#xff0c;后面重新下一步一步的选择默认的网络重装后就好了&am…...

docker 数据管理,数据持久化详解 一

docker镜像是分层设计的&#xff0c;镜像出只读&#xff0c;通过镜像启动的容器添加一层可读写的文件系统&#xff0c;用户写入的数据表都保存在这层中。 容器的数据分层目录 LowerDir&#xff1a;image 镜像层&#xff0c;即镜像本身&#xff0c;制度 UpperDir&#xff1a;容…...

【ios】使用TestFlight将app分发给测试人员(超详细)

我的环境&#xff1a; macos系统是Ventura 13.0 xcode是14.2&#xff08;后面发现至少需要15版本的xcode才能上传app&#xff09; 证书生成 可以通过xcode生成Distribution类型的证书&#xff0c;如果你已经有的话那就忽略&#xff0c;这个证书也是备案时所需的。 我是已…...

证件照小程序源码,前后端稳定运行

演示&#xff1a;证寸照制作 运行环境: Linux Nginx PHP >5.6 MySQL>5.6 安装步骤: 1.下载源码上传至你的服务器宝塔面板 2.直接添加站点选择源码目录&#xff0c;新建数据库 3.设置代码执行目录为/web 4.在浏览器中输入你的域名&#xff0c;会提示安装&#xff0c;填写…...

java白嫖同事的从身份证里面提取省市区地址详细信息的工具类代码

/*** author sunpeiyang* date 2024/10/21 16:35*/ Slf4j public class MiTaAddressExtractor {/*** 获取详细地址** param fullAddress 身份证完整地址*/public static String getDetailedAddress(String fullAddress) {String[] addressArrays spliceDetailedAddress(fullAd…...

计算机网络基本架构示例2

一、企业内部网络架构 在一个中型企业中&#xff0c;通常会有以下的网络架构&#xff1a; - 核心层&#xff1a;由高性能的核心交换机组成&#xff0c;负责快速转发大量数据。例如采用具有高带宽和冗余功能的三层交换机&#xff0c;确保整个网络的稳定运行。它连接着各个部门的…...

无人机之室内定位技术篇

无人机的室内定位技术是实现无人机在室内环境中精准导航和定位的关键技术。由于室内环境复杂&#xff0c;卫星导航系统&#xff08;如GPS&#xff09;无法提供有效的信号&#xff0c;因此需要依赖其他室内定位技术。 一、主要技术类型 基于视觉的定位技术 原理&#xff1a;利…...

在ubuntu20.04中输入不存在shell命令时,报错ModuleNotFoundError的解决方案

这个问题出现过好几次&#xff0c;每次都比较困扰&#xff0c;以下的解决方案比较适合&#xff1a; 当我输入ubuntu无法识别的命令的时候&#xff0c;正常来说应该提示类似于 command not found 之类的字眼&#xff0c;但是系统确报了如下错误&#xff1a; Traceback (most r…...

互联网语言 互联网开发 互联网架构

JAVA和PHP是两种广泛应用于互联网开发的编程语言&#xff0c;它们在多个维度上展现出显著的不同。 JAVA是一种面向对象的编程语言&#xff0c;以其严谨、高效的特性而著称。JAVA的语法结构复杂且规范&#xff0c;强调封装、继承和多态等面向对象原则&#xff0c;适合构建大型企…...