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

Linux系统中驱动入门设备树DTS(经典)

      

设备树DTS:device tree source),字面意思就是一块电路板上设备如上图中CPU、DDR、I2C、GPIO、SPI等,按照树形结构描绘成的一棵树。按照策略功能分离的思路,就是驱动代码(功能)和设备树DTS配置文件(策略)分开来进行设计,这样针对不同的电路板,Linux驱动代码就不用动了,只需要改改DTS就可以,DTS中的配置会决定哪些驱动去运行。

    Linux相关知识在嵌入式领域中很重要,要学习可以找一个能运行Linux代码的环境,最好有一个开发板,也可以用qemuubuntu上运行。

1. 设备树起源

    在Linux 2.6中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx中,如果外设发生相应的变化,那么驱动代码就需要改动。

    2011年,Linux之父Linus Torvalds发现这个问题后,就通过邮件向ARM-Linux开发社区发了一封邮件,不禁的发出了一句“This whole ARM thing is a f*cking pain in the ass”。之后,ARM社区就引入了PowerPC等架构已经采用的设备树(Flattened Device Tree)机制,将板级信息内容都从Linux内核中分离开来,用一个专属的文件格式来描述,即现在的.dts文件

    从 3.x 版本之后开始支持使用设备树,这样做的意义重大,可以实现驱动代码与设备的硬件信息相互的隔离,减少了代码中的耦合性。通过设备树对硬件信息的抽象,驱动代码只要负责处理逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,开发者只需要修改设备树文件信息,不需要改写驱动代码。

    设备树由一系列被命名的节点(Node)和属性(Property)组成,而节点本身可包含子节点。在设备树中,可描述的信息包括:

  • CPU的数量和类别。

  • 内存基地址和大小。

  • 总线和桥。

  • 外设连接。

  • 中断控制器和中断使用情况。

  • GPIO控制器和GPIO使用情况。

  • 时钟控制器和时钟使用情况。

    基本上就是画一棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。

2. 基本概念介绍

图片

2.1 dts

    dts(device tree source设备树源文件)文件是一种ASCII文本格式的设备树描述文件,此文件适合人类阅读,主要是给用户看的。

    硬件的相应信息都会写在.dts为后缀的文件中,每一款硬件可以单独写一份xxxx.dts,一般在Linux源码中存在大量的dts文件,对于 arm 架构可以在arch/arm/boot/dts找到相应的dts,另外mips则在arch/mips/boot/dts,powerpc在arch/powerpc/boot/dts。

对于imx6ull开发板

arch/arm/boot/dts/100ask_imx6ull_qemu.dts

dts中一般会包一个公共部分的dtsi文件,如下:

#include "imx6ull.dtsi"

2.2 dtsi

    值得一提的是,对于一些相同的dts配置可以抽象到dtsi文件中,然后类似于 C 语言的方式可以include到dts文件中,对于imx6ull开发板arch/arm/boot/dts/imx6ull.dtsi

    对于同一个节点的设置情况,dts中的配置会覆盖dtsi中的配置。具体如下图所示;

图片

2.3 dtc

    dtc编译dts的工具,可以在Ubuntu系统上通过指令apt-get install device-tree-compiler安装dtc工具,不过在内核源码scripts/dtc路径下已经包含了dtc工具;

2.4 dtb

    dtb(Device Tree Blob),dts经过dtc编译之后会得到dtb文件,dtb通过Bootloader引导程序加载到内核。所以Bootloader需要支持设备树才行;Kernel 也需要加入设备树的支持;

dtb文件布局如下:

图片

从上图可以看出,DTB文件主要包含四部分内容:

  1. struct ftdheader:用来表明各个分部的偏移地址,整个文件的大小,版本号等;

  2. memory reservation block:在设备树中使用/memreserve/ 定义的保留内存信息;

  3. structure block:保存节点的信息,节点的结构;

  4. strings block:保存属性的名字,单独作为字符串保存;

    dtb文件代码级别的解析可以参考:

https://cloud.tencent.com/developer/article/1887823

(1) dtb 文件的结构图如下:

图片

 (2) 设备节点的结构图如下:

图片

2.5 DTB加载及解析过程

U-Boot处理如下:

图片

3. DTS基本框架

    下图是一个设备树文件的基本架构;大概看了一下有点类似于XML文件,简单概括一下有这几个部分;

图片

一个例子:

1 个双核ARM Cortex-A932 位处理器;ARM 本地总线上的内存映射区域分布有

两个串口(分别位于0x101F1000和0x101F2000)

GPIO控制器(位于0x101F3000)

SPI控制器(位于0x10170000)

中断控制器(位于0x10140000)

外部总线桥上连接的设备如下:

SMC SMC91111以太网(位于0x10100000)

I2C控制器(位于0x10160000)

64MB NOR Flash(位于0x30000000)

外部总线桥上连接的 I2C 控制器所对应的 I2C 总线上又连接了Maxim DS1338实时钟(I2C 地址为0x58)具体如下图所示;

图片

一个移植网卡的例子:

    比如dm9000网卡,就需要首先将示例信息挂接到我们的板级设备树上,并根据芯片手册和电路原理图将相应的属性进行配置,再配置相应的驱动。需要注意的是,dm9000的地址线一般是接在片选线上的,所以设备树中就应该归属与相应片选线节点,我这里用的exynos4412,接在了bank1,所以是"<0x50000000 0x2 0x50000004 0x2>"

最终的配置结果是:

图片

然后make menuconfig勾选相应的选项将dm9000的驱动编译进内核。

[*] Networking support  --->        Networking options  --->                <*> Packet socket                <*>Unix domain sockets                 [*] TCP/IP networking                [*]   IP: kernel level autoconfigurationDevice Drivers  --->        [*] Network device support  --->                [*]   Ethernet driver support (NEW)  --->                        <*>   DM9000 supportFile systems  --->        [*] Network File Systems (NEW)  --->                <*>   NFS client support                [*]     NFS client support for NFS version 3                [*]       NFS client support for the NFSv3 ACL protocol extension                [*]   Root file system on NFS

执行make uImage;make dtbs,tftp下载,成功加载nfs根文件系统并进入系统,表示网卡移植成功

详细语法参考:https://www.cnblogs.com/xiaojiang1025/p/6131381.html

4. 修改DTS试验

4.1 dts修改

    修改设备树文件

arch/arm/boot/dts/100ask_imx6ull_qemu.dts,添加一个我们自己的模块dts_tree1:

图片

    修改完成后执行make dtbs 重新编译设备树文件,编译完成后arch/arm/boot/dts/100ask_imx6ull_qemu.dtb,将其下载到芯片中。

或者用qemu运行的时候,修改参考指向这个新的dtb文件。

查看设备树节点进入内核,执行

ls  /proc/device-tree/

我们会发现刚刚创建的设备树节已经存在了

图片

图片

    跟我们在dts里面修改的一样,这里变成了一个个的文件形式。文件的名字是属性的名字,内容是值。

具体看看节点的内容,执行

图片

4.2 内核中添加驱动模块

参考:Linux驱动实践:带你一步一步编译内核驱动程序 - IOT物联网小镇 - 博客园

在/drivers文件夹下创建dts_test文件夹,然后创建Kconfig文件

Bash
 config  DTS_TEST
         tristate "dts test"
         default y
         help
             This is the dts test

创建Makefile文件

JavaScript
 obj-$(CONFIG_DTS_TEST) += dts_test.o

在drivers文件夹下的Kconfig和Makefile文件中分别添加

C
 source  "drivers/dts_test/Kconfig"
 obj-$(CONFIG_DTS_TEST)                += dts_test/

创建dts_test.c文件

C++
 #include  <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
 #include <linux/errno.h>
 #include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/gpio_keys.h>
 #include <linux/of_irq.h>
 #include <linux/gpio.h>
 #include <linux/property.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/slab.h>
 #include <linux/device.h>
 
 #define DRIVER_NAME "imx6ul,dts-tree"
 
 
 static int devtree_probe(struct platform_device * pdev)
 {
     struct fwnode_handle *child;
     const char *p1,*p2[3];
     u32 p3[2],value;
     u8 testmac[6];
     int i=0;
 
     printk(KERN_INFO  "\n**********devtree_probe******************\n");
 
      device_property_read_string(&pdev->dev,"test-string",&p1);
     printk("devtree_probe  node  test-string is: %s\n",p1);
 
      device_property_read_string_array(&pdev->dev,  "test-strings", p2, 3);
     printk("devtree_probe node  test-strings is: %s%s%s\n",p2[0],p2[1],p2[2]);
 
      device_property_read_u32(&pdev->dev,"test-u32",&value);
     printk("devtree_probe node  test-u32 is: <%d>\n",value);
 
      device_property_read_u32_array(&pdev->dev,  "test-u32s", p3, 2);
     printk("devtree_probe node  test-u32s is: <%d>,<%d>\n",p3[0],p3[1]);
 
      device_property_read_string(&pdev->dev,"compatible",&p1);
     printk("devtree_probe node  compatible is: %s\n",p1);
 
      device_property_read_string(&pdev->dev,"status",&p1);
     printk("devtree_probe  node  status is: %s\n",p1);
 
     printk(" \n * devtree_probe  child node \n");
 
      device_for_each_child_node(&pdev->dev, child){
 
         printk("*************childnode%d*************\n",i++);     
          fwnode_property_read_string(child,"test-string",&p1);
         printk("childnode  test-string is: %s\n",p1);
 
          fwnode_property_read_string_array(child,"test-strings",p2,3);
         printk("childnode  test-strings is:  %s%s%s\n",p2[0],p2[1],p2[2]);
 
          fwnode_property_read_u32_array(child,"test-u32",&value,1);
         printk("childnode test-u32  is: <%d>\n",value);
 
          fwnode_property_read_u32_array(child,"test-u32s",p3,2);
         printk("childnode  test-u32s is:  <%d>,<%d>\n",p3[0],p3[1]);
 
          fwnode_property_read_u8_array(child,"test-u8s",testmac,6);
         printk("childnode  test-u32s is:  [%x,%x,%x,%x,%x,%x]\n",testmac[0],testmac[1],testmac[2],testmac[3],testmac[4],testmac[5]); 
 
     }
 
     return 0;
 }
 static int devtree_remove(struct platform_device * pdev)
 {
     printk(KERN_INFO  "devtree_remove\n");
 
     return 0;
 }
 
 static const struct of_device_id of_devtree_dt_match[] = {
     {.compatible = DRIVER_NAME},
     {},
 };
 
 MODULE_DEVICE_TABLE(of,of_devtree_dt_match);
 
 static struct platform_driver devtree_test_driver = {
     .probe  = devtree_probe,
     .remove = devtree_remove,
     .driver = {
         .name = DRIVER_NAME,
         .owner = THIS_MODULE,
         .of_match_table = of_devtree_dt_match,
         },
 };
 
 
 static int devtree_test_init(void)
 {
     int num=0,i=0,value;
     const char *p1;
     struct device_node  *node1,*childnode1;
     u32 p2[2];
     u8 testmac[6];
    
     pr_warn(KERN_INFO  "^^^^^^^^^^^^^^^^^^^devtree_test_init^^^^^^^^^^^ \n");
     printk(KERN_INFO  "^^^^^^^^^^^^^^^^^^^devtree_test_init^^^^^^^^^^^ \n");
     printk("\n*************devtree  init start ***************\n");
 
     node1 =  of_find_node_by_path("/dts-tree1");
     if(node1 == NULL){
         printk("of_find_node_by_path  failed\n");
         return -ENODEV;
     }
     else{
          printk("of_find_node_by_path dts-tree1 ok\n");
     }
     //read string
     of_property_read_string(node1,  "test-string", &p1);
     printk("dts-tree1 node  :test-string is: %s\n",p1);
     //read strings
     num =  of_property_count_strings(node1, "test-strings");
     printk("dts-tree1 node  test-strings num is: %d\n",num);
     for(i=0;i<num;i++){
          of_property_read_string_index(node1,"test-strings",i,&p1);
         printk("%s",p1);
     }
     //read string  "compatible"
     of_property_read_string(node1,  "compatible", &p1);
     printk("dts-tree1 node  compatible is: %s\n",p1);
 
     //read string "status"
     of_property_read_string(node1,  "status", &p1);
     printk("dts-tree1 node   status is: %s\n",p1);
 
     //read u32 "test-u32"
      of_property_read_u32(node1,"test-u32",&value);
     printk("dts-tree1 node  test-u32 is: <%d>\n",value);
 
     //read  u32s test-u32s
     of_property_read_u32_array(node1,  "test-u32s", p2, 2);
     printk("dts-tree1 node  test-u32s is:  <%d>,<%d>\n",p2[0],p2[1]);
 
     //read u8s test-u8s
     of_property_read_u8_array(node1,  "test-u8s", testmac, 6);
     printk("dts-tree1 node  test-u8s is:  <%x>,<%x>,<%x>,<%x>,<%x>,<%x>\n",testmac[0],testmac[1],testmac[2],testmac[3],testmac[4],testmac[5]);
 
     //get "dts_child_node1"  device node 
     childnode1 =  of_get_child_by_name(node1,"dts_child_node1");
     if(childnode1 == NULL){
          printk("of_get_child_by_name failed\n");
         return -ENODEV;
     }
     printk("of_get_child_by_name  dts_child_node1 ok\n");
     of_property_read_string(childnode1,  "test-string", &p1);
     printk("dts_child_node1 node  test-string is: %s\n",p1);
 
 
     return  platform_driver_register(&devtree_test_driver);
 }
 
 static void devtree_test_exit(void)
 {
     printk(KERN_INFO  "\ndevtree_test_exit\n");
      platform_driver_unregister(&devtree_test_driver);
 }
 
 module_init(devtree_test_init);
 module_exit(devtree_test_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("zheng");

Kconfig中是y,这样系编译运行后,会直接看到打印:

图片

4.3 常用OF API

    linux 内核中和设备树相关的函数内核关于设备树的驱动都放在/drivers/of下,用户可以使用这里面的函数对设备树进行操作。

图片

后记:

    入门系列还是比较适合公众号,一些零碎的拓展知识面学习。总感觉这种查询式的学习不利于系统的掌握一项技能,可以这么说:高手都不是这么学习的。答案估计是实际的工作经验+看书。系统深入的学习技术首先科班出身很重要,例如计算机专业四大专业课,然后就是对计算机经典书籍的阅读。

    在工作中可能遇到问题了,查点资料,感觉可能也就学了点奇巧淫技,这里需要把经验性的知识理论性的知识区分开,这就是科学技术的区别,经验性的知识没有师傅带就完蛋了,可以多寻求帮助,但是理论性的东西就需要看书,愿大家能沉下心来找点经典大部头书“读上那么一读,确实挺不错的”

相关文章:

Linux系统中驱动入门设备树DTS(经典)

设备树&#xff08;DTS:device tree source&#xff09;&#xff0c;字面意思就是一块电路板上设备如上图中CPU、DDR、I2C、GPIO、SPI等&#xff0c;按照树形结构描绘成的一棵树。按照策略和功能分离的思路&#xff0c;就是驱动代码&#xff08;功能&#xff09;和设备树DTS配置…...

关系型数据库与非关系型数据库类比

关系型数据库和非关系型数据库都有多种不同类型&#xff0c;每种类型都针对不同的数据存储需求和使用场景。以下是一些常见的关系型数据库和非关系型数据库类型&#xff1a; 关系型数据库类型&#xff1a; MySQL&#xff1a; 一种开源的关系型数据库管理系统&#xff0c;用于处…...

Ubuntu入门03——Ubuntu用户操作

1.Ubuntu如何进入root用户 进入ROOT用户的指令&#xff1a; Linux用su命令来切换用户&#xff1a; su root执行命令后&#xff0c;会提示你输入密码&#xff0c;而Ubuntu是没有设置root初始密码的。 若su命令不能切换root&#xff0c;提示su: Authentication failure&#x…...

输出图元(四)8-1 图元、屏幕坐标、指定二维世界坐标系统

用于图形应用的通用软件包称为计算机图形应用编程接口(CCAPI)它提供可以在C等程序设计语言中用来创建图形的函数库。如第3 章所指出的&#xff0c;函数库可以分成几种类型。创建图形时最先要做的一件事就是要描述显示场景的组成部分。图形的组成部分可以是树木和地形家具和墙壁…...

机器学习---决策树的划分依据(熵、信息增益、信息增益率、基尼值和基尼指数)

1. 熵 物理学上&#xff0c;熵 Entropy 是“混乱”程度的量度。 系统越有序&#xff0c;熵值越低&#xff1b;系统越混乱或者分散&#xff0c;熵值越⾼。 1948年⾹农提出了信息熵&#xff08;Entropy&#xff09;的概念。 从信息的完整性上进⾏的描述&#xff1a;当系统的有序…...

java解析json

1. 解析根节点为“{}”的json {"id": 1525490,"name": "有缘网" }代码&#xff1a; String jsonString "{\"id\":1525490\",\"name\":\"有缘网\"}";JSONObject jsonObject JSONObject.…...

PAT 1163 Dijkstra Sequence

个人学习记录&#xff0c;代码难免不尽人意。 Dijkstra’s algorithm is one of the very famous greedy algorithms. It is used for solving the single source shortest path problem which gives the shortest paths from one particular source vertex to all the other v…...

嵌入式学习之进程

1.进程间通信概述 UNIX系统IPC是各种进程通信方式的统称。 2.管道通信原理 特点&#xff1a; 1.它是半双工的&#xff08;即数据只能在一个方向上流动&#xff09;&#xff0c;具有固定的读端和写端。 2.它只能用于具有亲缘关系的进程之间通信&#xff08;也是父子进程或者…...

C#-单例模式

文章目录 单例模式的概述为什么会有单例模式如何创建单例模式1、首先要保证&#xff0c;该对象 有且仅有一个2、其次&#xff0c;需要让外部能够获取到这个对象 示例通过 属性 获取单例 单例模式的概述 总结来说&#xff1a; 单例 就是只有 一个实例对象。 模式 说的是设计模式…...

WSNs 安全技术

WSNs 多用于军事&#xff0c;特殊现场的警戒保护、商业区域的安防&#xff0c;作为任务型网 络&#xff0c;不仅要进行数据传输&#xff0c;而且要进行数据采集和融合&#xff0c;任务的协同控制等&#xff0c;如何 保证任务执行的机密性&#xff0c;数据产生的可靠性数据融合…...

H5如何做页面下拉刷新和上拉加载

这里以vant为例 结构 <van-pull-refreshv-model"isLoading"success-text"刷新成功"refresh"onRefresh"><van-liststyle"height:100%"v-model"loading":finished"finished"finished-text"没有更多了…...

Camunda 7.x 系列【42】事件子流程

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 2.7.9 本系列Camunda 版本 7.19.0 源码地址:https://gitee.com/pearl-organization/camunda-study-demo 文章目录 1. 概述2. 案例演示2.1 流程模型2.2 测试1. 概述 事件子流程是由事件触发的子流程,可存在…...

JVM类的加载过程

加载过程 JVM的类的加载过程分为五个阶段&#xff1a;加载、验证、准备、解析、初始化。 加载   加载阶段就是将编译好的的class文件通过字节流的方式从硬盘或者通过网络加载到JVM虚拟机当中来。&#xff08;我们平时在Idea中书写的代码就是放在磁盘中的&#xff0c;也可以通…...

Jmeter如何设置中文版

第一步&#xff1a;找到 apache-jmeter-5.4.3\bin目录下的 jmeter.properties 第二步:打开 三&#xff0c;ctrf 输入languageen&#xff0c;注释掉&#xff0c;增加以行修改如下 四&#xff0c;ctrs 保存修改内容&#xff0c;重新打开jmeter就可以了...

flutter自定义按钮-文本按钮

目录 前言 需求 实现 前言 最近闲着无聊学习了flutter的一下知识&#xff0c;发现flutter和安卓之间&#xff0c;页面开发的方式还是有较大的差异的&#xff0c;众所周知&#xff0c;android的页面开发都是写在xml文件中的&#xff0c;而flutter直接写在代码里&#xff08;da…...

无涯教程-Android - CheckBox函数

CheckBox是可以由用户切换的on/off开关。为用户提供一组互不排斥的可选选项时,应使用复选框。 CheckBox 复选框属性 以下是与CheckBox控件相关的重要属性。您可以查看Android官方文档以获取属性的完整列表以及可以在运行时更改这些属性的相关方法。 继承自 android.widget.T…...

[Go版]算法通关村第十五关青铜——用4KB内存寻找重复元素

目录 题目&#xff1a;用4KB内存寻找重复元素思路分析&#xff1a;使用位存储如何存储这32000个整数&#xff1f;每个整数对应在位图中的存储状态举例如何判断是重复的&#xff1f;具体的步骤 复杂度&#xff1a;时间复杂度 O ( n ) O(n) O(n)、空间复杂度 O ( 1 ) O(1) O(1)Go…...

OJ练习第159题——消灭怪物的最大数量

消灭怪物的最大数量 力扣链接&#xff1a;1921. 消灭怪物的最大数量 题目描述 你正在玩一款电子游戏&#xff0c;在游戏中你需要保护城市免受怪物侵袭。给你一个 下标从 0 开始 且长度为 n 的整数数组 dist &#xff0c;其中 dist[i] 是第 i 个怪物与城市的 初始距离&#…...

Prometheus-Rules(规则)

文章目录 一、介绍二、配置 Prometheus 使用规则文件三、 规则文件语法规则文件语法全局Recording rules(记录规则)2 Alerting rules(警报规则)3 模板化如何使用四、检查规则文件语法五、发送警报通知一、介绍 Prometheus规则是一种逻辑表达式,可用于定义有关监控数据的逻…...

打卡智能中国(六):村里出了“飞行员”

提起返乡青年&#xff0c;你的第一印象是什么&#xff1f;失败、躺平、卷不动了&#xff1f; 我们在浙江、福建、青海等地&#xff0c;参观一些农业智能化项目时&#xff0c;陪同参观的“飞手”&#xff0c;高兴地跟我们分享自己的心路历程&#xff1a; 在家门口做农业无人机操…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...