Linux Platform驱动模型全解析:从入门到精通
Linux Platform驱动模型全解析:从入门到精通
1. Platform驱动模型概述
1.1 什么是Platform驱动模型
Platform驱动模型是Linux内核为处理非热插拔设备(通常是SoC集成外设)而设计的一套驱动框架。它通过虚拟的"platform总线"将硬件设备与驱动程序连接起来,实现了硬件描述与驱动实现的分离。
与PCI、USB等标准总线不同,platform总线是一种伪总线(pseudo-bus),用于管理那些没有真正物理总线的设备,如集成在SoC中的各种控制器(I2C、SPI、UART等)。
1.2 为什么需要Platform驱动模型
在嵌入式系统中,许多外设是直接集成在处理器芯片上的,它们:
- 不支持自动检测(非热插拔)
- 需要明确的初始化配置
- 资源(寄存器地址、中断号等)固定不变
传统的驱动开发方式需要将硬件信息硬编码在驱动代码中,导致:
- 驱动与硬件强耦合,移植性差
- 同一驱动需要为不同平台维护多个版本
- 内核编译配置复杂
Platform驱动模型通过分离设备描述和驱动实现解决了这些问题。
1.3 基本组成要素
Platform驱动模型包含三个核心组件:
- Platform总线(bus_type):虚拟总线platform_bus_type,负责匹配设备和驱动
- Platform设备(platform_device):描述硬件资源(寄存器地址、中断号等)
- Platform驱动(platform_driver):实现设备的具体操作逻辑
2. Platform设备详解
2.1 platform_device结构体
struct platform_device {const char *name; // 设备名称,用于匹配驱动int id; // 设备实例IDstruct device dev; // 内嵌的标准device结构体u32 num_resources; // 资源数量struct resource *resource; // 资源数组// ...
};
关键字段说明:
name
:设备名称,与驱动匹配的关键resource
:描述设备占用的硬件资源(内存、中断等)dev.platform_data
:指向设备私有数据的指针
2.2 资源描述:struct resource
struct resource {resource_size_t start; // 资源起始地址resource_size_t end; // 资源结束地址const char *name; // 资源名称(可选)unsigned long flags; // 资源类型标志// ...
};
常用flags类型:
IORESOURCE_MEM
:内存映射IO资源IORESOURCE_IRQ
:中断资源IORESOURCE_DMA
:DMA通道
2.3 注册Platform设备
有三种主要方式注册platform设备:
- 静态注册(传统方式,已不推荐):
struct platform_device my_device = {.name = "my-device",.id = -1,.resource = my_resources,.num_resources = ARRAY_SIZE(my_resources),
};
platform_device_register(&my_device);
- 动态注册:
struct platform_device *pdev;
pdev = platform_device_alloc("my-device", PLATFORM_DEVID_AUTO);
platform_device_add_resources(pdev, res, nres);
platform_device_add_data(pdev, &my_data, sizeof(my_data));
platform_device_add(pdev);
- 设备树方式(现代推荐方式):
my_device: my-device@1000000 {compatible = "vendor,my-device";reg = <0x1000000 0x1000>;interrupts = <0 10 4>;// 其他属性...
};
设备树方式是目前最推荐的方式,它完全将硬件描述与驱动代码分离。
3. Platform驱动详解
3.1 platform_driver结构体
struct platform_driver {int (*probe)(struct platform_device *);int (*remove)(struct platform_device *);void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*resume)(struct platform_device *);struct device_driver driver;const struct platform_device_id *id_table;// ...
};
关键成员说明:
probe
:设备匹配成功后调用的初始化函数remove
:设备移除时调用的清理函数driver
:内嵌的标准driver结构体,包含name、owner等id_table
:支持的设备ID表(用于非设备树匹配)
3.2 驱动注册方式
- 标准注册:
static struct platform_driver my_driver = {.probe = my_probe,.remove = my_remove,.driver = {.name = "my-device",.owner = THIS_MODULE,},
};
module_platform_driver(my_driver);
- 带设备树的注册:
static const struct of_device_id my_of_ids[] = {{ .compatible = "vendor,my-device" },{}
};static struct platform_driver my_driver = {.probe = my_probe,.remove = my_remove,.driver = {.name = "my-device",.of_match_table = my_of_ids,.owner = THIS_MODULE,},
};
- 一次性注册多个驱动:
static struct platform_driver my_drivers[] = {{ ... }, // 驱动1{ ... }, // 驱动2
};platform_register_drivers(my_drivers, ARRAY_SIZE(my_drivers));
3.3 probe和remove函数
probe函数是驱动的核心,通常包含:
- 获取设备资源(内存、中断等)
- 初始化硬件
- 注册字符设备/网络设备等
- 申请所需资源(DMA缓冲区等)
示例probe函数:
static int my_probe(struct platform_device *pdev)
{struct resource *res;void __iomem *base;int irq;// 获取内存资源res = platform_get_resource(pdev, IORESOURCE_MEM, 0);base = devm_ioremap_resource(&pdev->dev, res);if (IS_ERR(base))return PTR_ERR(base);// 获取中断资源irq = platform_get_irq(pdev, 0);if (irq < 0)return irq;// 获取平台特定数据struct my_platform_data *pdata = dev_get_platdata(&pdev->dev);// 初始化硬件...return 0;
}
remove函数负责释放probe中申请的资源:
static int my_remove(struct platform_device *pdev)
{// 释放资源、注销设备等return 0;
}
4. 设备与驱动的匹配机制
Platform总线提供了多种匹配方式,按优先级排序:
-
设备树匹配(最常用):
- 驱动定义
of_match_table
- 设备树节点设置
compatible
属性 - 内核比较
compatible
与of_match_table
- 驱动定义
-
ID表匹配:
- 驱动定义
id_table
- 设备设置
platform_device_id
- 内核比较两者
- 驱动定义
-
名称匹配(传统方式):
- 驱动
driver.name
与设备name
直接比较
- 驱动
匹配成功后,内核会调用驱动的probe
函数。
5. 设备资源管理
5.1 获取设备资源
Platform驱动提供了多种API获取设备资源:
- 内存资源:
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, index);
void __iomem *base = devm_ioremap_resource(&pdev->dev, res);
- 中断资源:
int irq = platform_get_irq(pdev, index);
int irq = platform_get_irq_byname(pdev, "interrupt-name");
- 平台特定数据:
// 从设备树获取
struct device_node *np = pdev->dev.of_node;
of_property_read_u32(np, "property-name", &value);// 从platform_data获取
struct my_platform_data *pdata = dev_get_platdata(&pdev->dev);
5.2 设备资源管理(Devres)
Linux内核提供了"managed"资源管理接口,可以自动释放资源:
- 内存映射:
void __iomem *base = devm_ioremap_resource(&pdev->dev, res);
- 中断申请:
int devm_request_irq(&pdev->dev, irq, handler, flags, name, dev);
- 内存分配:
void *buf = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
使用devm接口可以简化remove函数,因为资源会在设备注销时自动释放。
6. Platform驱动开发实战
6.1 开发流程
-
确定设备信息:
- 寄存器地址范围
- 中断号
- 时钟/复位线
- 其他特定配置
-
选择注册方式:
- 设备树(推荐)
- 传统platform_device方式
-
实现驱动:
- probe/remove函数
- 文件操作接口(字符设备)
- 中断处理
- 电源管理
-
测试与调试:
- 检查/sys/bus/platform/devices
- 使用devm_*简化资源管理
- 动态调试printk
6.2 完整示例:LED控制器驱动
设备树节点:
led-controller@1000000 {compatible = "vendor,simple-led";reg = <0x1000000 0x100>;interrupts = <0 10 4>;clocks = <&clk 5>;clock-names = "led_clk";status = "okay";
};
驱动实现:
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/interrupt.h>struct led_controller {void __iomem *base;int irq;struct clk *clk;
};static irqreturn_t led_irq(int irq, void *dev_id)
{// 中断处理...return IRQ_HANDLED;
}static int led_probe(struct platform_device *pdev)
{struct led_controller *led;struct resource *res;// 分配驱动私有数据结构led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);if (!led)return -ENOMEM;// 获取内存资源并映射res = platform_get_resource(pdev, IORESOURCE_MEM, 0);led->base = devm_ioremap_resource(&pdev->dev, res);if (IS_ERR(led->base))return PTR_ERR(led->base);// 获取中断led->irq = platform_get_irq(pdev, 0);if (led->irq < 0)return led->irq;// 申请中断if (devm_request_irq(&pdev->dev, led->irq, led_irq, 0, "led-controller", led))return -EIO;// 获取时钟led->clk = devm_clk_get(&pdev->dev, "led_clk");if (IS_ERR(led->clk))return PTR_ERR(led->clk);// 初始化硬件...clk_prepare_enable(led->clk);// 保存私有数据platform_set_drvdata(pdev, led);return 0;
}static int led_remove(struct platform_device *pdev)
{struct led_controller *led = platform_get_drvdata(pdev);// 清理硬件...clk_disable_unprepare(led->clk);return 0;
}static const struct of_device_id led_of_match[] = {{ .compatible = "vendor,simple-led" },{},
};
MODULE_DEVICE_TABLE(of, led_of_match);static struct platform_driver led_driver = {.driver = {.name = "simple-led",.of_match_table = led_of_match,},.probe = led_probe,.remove = led_remove,
};
module_platform_driver(led_driver);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Simple LED controller driver");
7. 高级主题与最佳实践
7.1 多设备支持
一个驱动可以支持多个设备,通过以下方式实现:
- 使用id_table:
static const struct platform_device_id my_id_table[] = {{ "device-v1", (kernel_ulong_t)&v1_data },{ "device-v2", (kernel_ulong_t)&v2_data },{},
};
- 设备树兼容列表:
static const struct of_device_id my_of_ids[] = {{ .compatible = "vendor,device-v1", .data = &v1_data },{ .compatible = "vendor,device-v2", .data = &v2_data },{},
};
在probe函数中可以通过of_device_get_match_data()
获取设备特定数据。
7.2 电源管理
Platform驱动支持电源管理操作:
static struct platform_driver my_driver = {// ....suspend = my_suspend,.resume = my_resume,.driver = {.pm = &my_pm_ops,},
};
实现完整的电源管理需要考虑:
- 运行时电源管理(runtime PM)
- 系统挂起/恢复
- 时钟/电源域管理
7.3 调试技巧
- 检查设备是否注册成功:
ls /sys/bus/platform/devices/
- 查看驱动匹配信息:
dmesg | grep platform
- 设备树调试:
dtc -I fs /proc/device-tree
- 动态调试:
#include <linux/dynamic_debug.h>
// 在代码中添加
dev_dbg(&pdev->dev, "Debug message");
然后在用户空间启用调试:
echo 'file driver.c +p' > /sys/kernel/debug/dynamic_debug/control
8. 常见问题与解决方案
8.1 probe函数未被调用
可能原因:
-
设备与驱动未正确匹配
- 检查
compatible
属性是否匹配 - 检查设备树节点状态是否为"okay"
- 检查
-
设备未正确注册
- 检查
/sys/bus/platform/devices
- 确认设备注册代码被执行
- 检查
-
驱动注册失败
- 检查
dmesg
输出 - 确认模块加载成功
- 检查
8.2 资源获取失败
常见错误:
-
内存映射失败
- 检查寄存器地址是否正确
- 确认资源索引正确
-
中断申请失败
- 检查中断号是否正确
- 确认中断未被其他驱动占用
-
时钟获取失败
- 检查时钟名称是否匹配
- 确认时钟在设备树中定义
8.3 设备树与驱动不匹配
调试方法:
- 确认设备树编译进内核
- 检查
/proc/device-tree
确认节点存在 - 使用
of_find_node_by_path()
调试设备树查找
9. 从传统方式迁移到设备树
对于传统platform_device用户,迁移到设备树的步骤:
-
识别硬件信息:
- 寄存器地址、大小
- 中断号、类型
- 时钟、复位线
- 其他特定配置
-
创建设备树节点:
my-device@1000000 {compatible = "vendor,my-device";reg = <0x1000000 0x1000>;interrupts = <0 10 4>;clocks = <&clk 5>;clock-names = "core";reset-gpios = <&gpio 10 1>;vendor,special-flag = <1>;
};
- 修改驱动:
- 添加
of_match_table
- 使用
of_*
API替代硬编码值 - 实现设备树解析逻辑
- 添加
10. 总结与进阶方向
10.1 Platform驱动模型优势
- 硬件与驱动分离:提高代码复用性
- 统一设备管理:通过sysfs提供一致接口
- 支持动态配置:设备树实现硬件灵活配置
- 简化驱动开发:提供丰富的资源管理API
10.2 进阶学习方向
-
深入设备树:
- 设备树绑定文档
- 设备树覆盖(Overlay)机制
- 动态设备树修改
-
复杂驱动开发:
- DMA缓冲区管理
- 中断嵌套与线程化处理
- 多设备并发控制
-
电源管理:
- Runtime PM框架
- 系统挂起/恢复流程
- 时钟门控与电源域
-
用户空间接口:
- sysfs属性文件
- debugfs调试接口
- ioctl控制机制
通过掌握Platform驱动模型,开发者可以构建出稳定、可维护的Linux设备驱动,满足从简单外设到复杂控制器的各种需求。从简单的LED控制到复杂的多媒体处理,Platform驱动模型为嵌入式Linux开发提供了坚实的基础。
相关文章:
Linux Platform驱动模型全解析:从入门到精通
Linux Platform驱动模型全解析:从入门到精通 1. Platform驱动模型概述 1.1 什么是Platform驱动模型 Platform驱动模型是Linux内核为处理非热插拔设备(通常是SoC集成外设)而设计的一套驱动框架。它通过虚拟的"platform总线"将硬件…...
7.Excel:单元格格式
一 案例 1.案例1 2.案例2 3.案例3 二 三种基本数据类型 补充:在没有任何格式的情况下是这样对齐的。 1.文本 默认左对齐,文本不可参与计算。 2.数值 默认右对齐,数值计算精度是15位。 若超出15位,超出部分显示为0。 3.逻辑值 …...
文件传输过滤器绕过:Exe2Hex
Exe2hex是****g0tmilk开发的一款工具,您可以**在这里找到它。该工具将 EXE 文件转录为一系列十六进制字符串**,DEBUG.exe或Powershell可以将其还原为原始 EXE 文件。之后,该脚本会在受害者机器上运行,重建并执行 EXE 文件。这在系统管理员阻止EXE 文件传输或上传的****高级…...
从多类缺陷到高良率跃升|公差分析技术重构动力电池装配精度体系
在新能源汽车产业升级关键期,动力电池装配精度和因装配引起的安全问题已成为制约产能提升的核心瓶颈。某头部电池企业通过 CETOL 6σ 公差分析技术,成功构建了复杂电池系统的精度控制体系。生产实践表明,微观尺度的公差偏差可能引发系统性质量…...
QT开发技术【QT实现桌面右下角消息】
一、效果 ![ 二、弹窗主体部分 noticewidget /* ** File name: NoticeWidget.h ** Author: ** Date: 2025-04-25 ** Brief: 通知栏控件 ** Copyright (C) 1392019713qq.com All rights reserved. */#include "../Include/NoticeWidget.h"…...
【使用层次序列构建二叉树(数据结构C)】
使用层次序列构建二叉树(C语言实现) 在数据结构学习过程中,二叉树的构建方式通常有递归建树(前序/中序)和层次建树(广度优先)两种。本文将介绍一种基于辅助队列实现的层次建树方法,并…...
【基于Qt的QQ音乐播放器开发实战:从0到1打造全功能音乐播放应用】
🌹 作者: 云小逸 🤟 个人主页: 云小逸的主页 🤟 motto: 要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在&…...
蓝桥杯 3. 密码脱落
密码脱落 原题目链接 题目描述 X 星球的考古学家发现了一批古代留下来的密码。 这些密码是由 A、B、C、D 四种植物的种子串成的序列。 仔细分析发现,这些密码串当初应该是前后对称的(即镜像串)。 由于年代久远,其中许多种子…...
数学基础 -- 欧拉恒等式的魅力:让复数旋转起来!
公式推导: e i π − 1 e^{i\pi} -1 eiπ−1 被誉为数学中最美的公式之一,它连接了五个数学中最重要的常数: e i π 1 0 (欧拉恒等式) e^{i\pi} 1 0 \tag{欧拉恒等式} eiπ10(欧拉恒等式) 这不仅是巧合,而是复数与三角函数…...
keil修改字体无效,修改字体为“微软雅黑”方法
在网上下载了微软雅黑字体,微软雅黑参考下载链接 结果在Edit->Configuration中找不到这个字体 这个时候可以在keil的安装目录中找到UV4/global.prop文件 用记事本打开它进行编辑,把字体名字改成微软雅黑 重新打开keil就发现字体成功修改了。 这个…...
LeetCode 每日一题 2845. 统计趣味子数组的数目
2845. 统计趣味子数组的数目 给你一个下标从 0 开始的整数数组 nums ,以及整数 modulo 和整数 k 。 请你找出并统计数组中 趣味子数组 的数目。 如果 子数组 nums[l…r] 满足下述条件,则称其为 趣味子数组 : 在范围 [l, r] 内,设 …...
二进制兼容性分析方法
I. 引言 在软件工程领域,二进制兼容性(Binary Compatibility)是一个核心概念,它指的是一个计算系统能够运行为另一个系统编译的可执行代码(通常是机器码)的能力,而无需重新编译 。这与源代码兼…...
在 WSL 安装 OpenFOAM-12
在 WSL 安装 OpenFOAM-12 参考链接安装教程问题整理1、安装完成后运行测试算例 Alllrun 脚本报错 参考链接 OpenFOAM OpenFoam-v12 OpenFOAM-v12-Ubuntu 安装教程 直接在 OpenFOAM 官网找到 Down -> OpenFOAM v12 选择 DownLoad v12 | Ubuntu -> Read More 具体安装过…...
Linux-06 ubuntu 系统截图软件使用简单记录
文章目录 原委一、Shutter二、Flameshot三、Ksnip 原委 原先使用的 Flameshot 截图软件,在ubuntu 18.04下可以正常使用。 系统升级到22.04 后,安装后的只能截图,不能标注,想着修复下。 以下是个人备忘录记录,如何使用…...
基于python代码的通过爬虫方式实现快手发布视频(2025年4月)
1、将真实的快手创作服务平台的cookie贴到代码目录中kuaishou_cookie.txt文件里,运行python脚本即可; 2、运行之前根据import提示安装一些常见依赖,比如requests等; 3、__NS_sig3.js的源码见快手NS sig3签名算法(2025年1月)_快手sig3算法源码-CSDN博客 4、2025年4月份…...
人工智能与机器学习:Python从零实现逻辑回归模型
🧠 向所有学习者致敬! “学习不是装满一桶水,而是点燃一把火。” —— 叶芝 我的博客主页: https://lizheng.blog.csdn.net 🌐 欢迎点击加入AI人工智能社区! 🚀 让我们一起努力,共创…...
大模型助力嘉兴妇幼:数据分类分级的智能化飞跃
在医疗行业数字化转型进程中,数据已成为驱动服务升级与业务创新的核心要素。作为医疗行业数字化的探索者,嘉兴市妇幼保健院携手美创打造的智能化数据分类分级项目,数据识别率和分类分级率高达99%,分类分级准确率达90%,…...
MyBatisPlus文档
一、MyBatis框架回顾 使用springboot整合Mybatis,实现Mybatis框架的搭建 1、创建示例项目 (1)、创建工程 新建工程 创建空工程 创建模块 创建springboot模块 选择SpringBoot版本 (2)、引入依赖 <dependencies><dependency><groupId>org.springframework.…...
支持Function Call的本地ollama模型对比评测-》开发代理agent
目标是开发支持多个 Function 定义的智能体代理系统 ✅ 第一部分:是否支持多个函数(multi-function calling) 模型名称支持多个函数注册是否支持函数选择(name 匹配)是否能生成结构化参数OpenChat 3.5 / 3.5-0106✅&a…...
Docker拉取镜像代理配置实践与经验分享
Docker拉取镜像代理配置实践与经验分享 一、背景概述 在企业内网环境中,我们部署了多台用于测试与学习的服务器。近期,接到领导安排,需在其中一台服务器上通过Docker安装n8n应用程序。然而在实际操作过程中,遭遇Docker官方镜像库…...
Jinja 的详细介绍和学习方法
Jinja 是一种流行的 模板引擎(Template Engine),主要用于生成动态的文本内容(如 HTML、XML、配置文件等)。它最初是为 Python 的 Web 框架(如 Flask、Django)设计的,但也可以独立使用…...
在 Windows 系统上升级 Node.js
一、查询电脑端已经安装的 Node.js 版本 1、通过【winR】 键,输入 cmd,点击【确定】按钮打开 cmd 窗口 2、命令行界面输入 node -v 查看目前 Node.js 版本 3、命令行界面输入 npm -v 查看目前 npm 版本 二、进入官网地址下载安装包 1、官网地址&#x…...
特斯拉宣布启动自动驾驶网约车测试,无人出租车服务进入最后准备阶段
特斯拉公司于4月24日正式宣布,已在美国得克萨斯州奥斯汀和加利福尼亚州旧金山湾区启动自动驾驶网约车服务的员工内部测试。这项测试将为今年夏季计划推出的完全无人驾驶出租车服务进行最后的验证和准备。 此次测试使用约200辆经过特殊改装的Model 3车型,…...
C++面试复习(7)2025.4.25
1,说一说常用的 Linux 命令(NIUKE) 1,cat 查看文件内容 cat filename2,rm 删除 rm filename:删除文件。 rm -r directory:删除目录及其内容。 rm -f filename:强制删除文件(不询问确认&…...
使用 uv 工具快速创建 MCP 服务(Trae 配置并调用 MCP 服务)
文章目录 下载Traeuv 工具教程参考我的这篇文章创建 uv 项目main.pyTrae 配置 MCP 服务添加 MCP创建智能体 使用智能体调用 MCP 创建 demo 表查询 demo 表结构信息demo 表插入 2 条测试数据查询 demo 表中的数据 下载Trae https://www.trae.com.cn/ uv 工具教程参考我的这篇…...
07 Python 字符串全解析
文章目录 一. 字符串的定义二. 字符串的基本用法1. 访问字符串中的字符2. 字符串切片3. 字符串拼接4. 字符串重复5.字符串比较6.字符串成员运算 三. 字符串的常用方法1. len() 函数2. upper() 和 lower() 方法3. strip() 方法4. replace() 方法5. split() 方法 四. 字符串的进阶…...
IEEE期刊目录重磅更新!共242本期刊被收录!
🔥 🔥 🔥 🔥 【IEEE期刊目录】 2025年2月,IEEE出版社更新了242本期刊目录,其中: • 完全OA期刊36本:SCI有6本,ESCI有15本; • 混合OA期刊183本&…...
微型计算机原理与接口技术第六版第四章课后习题答案-周荷琴,冯焕清-中国科学技术大学出版社
第六版书籍编排的第3章和第4章,仅这两章习题答案跟第四版的答案是相同的,可以参考第四版的答案 原第四版习题答案,蓝奏云: https://wwss.lanzouq.com/iWXOY1kvk3yf 第六版的第四章的习题我没有单独编辑,它是在上面第四…...
反爬策略应对指南:淘宝 API 商品数据采集的 IP 代理与请求伪装技术
一、引言 在电商数据驱动决策的时代,淘宝平台海量的商品数据极具价值。然而,淘宝为保障平台安全和用户体验,构建了严密的反爬体系。当采集淘宝 API 商品数据时,若不采取有效措施,频繁的请求极易触发反爬机制&#x…...
前端技术Ajax入门
1.1 AJAX 概念和 axios 使用 目标 了解 AJAX 概念并掌握 axios 库基本使用 讲解 1. 什么是 AJAX? 使用浏览器的 XMLHttpRequest 对象与服务器通信。在浏览器网页中,通过 AJAX 技术(XHR 对象)发起获取省份列表数据的请求&…...
【沉浸式求职学习day25】【部分网络编程知识分享】【基础概念以及简单代码】
不知道大家一直高强度学习自己是什么样的感觉,反正我现在逐渐变得麻木了,马上又要实习笔试了,每次笔试都要突击,每次突击都意识到自己有太多不会的,主打一个心累,但是又能怎样呢,自己选的路就是…...
聊聊Spring AI Alibaba的YoutubeDocumentReader
序 本文主要研究一下Spring AI Alibaba的YoutubeDocumentReader YoutubeDocumentReader community/document-readers/spring-ai-alibaba-starter-document-reader-youtube/src/main/java/com/alibaba/cloud/ai/reader/youtube/YoutubeDocumentReader.java public class You…...
常用第三方库:flutter_boost混合开发
常用第三方库:flutter_boost混合开发 前言 在移动应用开发中,混合开发是一个非常重要的话题。特别是对于已有原生应用想要引入Flutter的团队来说,如何实现Flutter页面和原生页面的无缝整合就显得尤为关键。本文将深入介绍flutter_boost这个…...
什么是 JSON?学习JSON有什么用?在springboot项目里如何实现JSON的序列化和反序列化?
作为一个学习Javaweb的新手,理解JSON的序列化和反序列化非常重要,因为它在现代Web开发,特别是Spring Boot中无处不在。 什么是 JSON? 首先,我们简单了解一下JSON (JavaScript Object Notation)。 JSON 是一种轻量级的…...
[mysql]数据类型精讲
目录 数据类型精讲: 整数类型 浮点类型 日期和时间类型 文本字符串类型 数据类型精讲: 精度问题:不能损失数据 性能问题:表的设计,范式的讲解. 表设计的时候需要设置字段,我们现在要把字段类型讲完.,细节点一点点给大家拆解. Float和double是有精度的损失的,这边推荐使用…...
WordPress AI插件能自动写高质量文章吗,如何用AI提升网站流量
WordPress AI插件能自动写高质量文章吗? 最近很多站长都在问,用wordpress AI插件真的能写出搜索引擎喜欢的好文章吗?作为一个用过10款AI写作工具的老站长,今天我就来分享真实使用体验,告诉你哪些插件好用、怎么用才能…...
【中级软件设计师】函数调用 —— 传值调用和传地址调用 (附软考真题)
【中级软件设计师】函数调用 —— 传值调用和传地址调用 (附软考真题) 目录 【中级软件设计师】函数调用 —— 传值调用和传地址调用 (附软考真题)一、历年真题二、考点:函数调用 —— 传值调用和传地址调用🔺1、传值调用🔺2、传引用(地址)调…...
ECMAScript 1(ES1):JavaScript 的开端
1. 版本背景与发布 ●发布时间:1997 年 6 月,由 ECMA International 正式发布,标准编号为 ECMA-262。 ●历史意义:ES1 是 JavaScript 的首个标准化版本,结束了 Netscape Navigator 与 Internet Explorer 浏览器间脚本语…...
C++入侵检测与网络攻防之暴力破解
目录 1.nessus扫描任务 2.漏洞信息共享平台 3.nessus扫描结果 4.漏扫报告的查看 5.暴力破解以及hydra的使用 6.crunch命令生成字典 7.其他方式获取字典 8.复习 9.关于暴力破解的防御的讨论 10.pam配置的讲解 11.pam弱密码保护 12.pam锁定账户 13.shadow文件的解析 …...
基于ssm的同城上门维修平台管理系统(源码+数据库)
54基于ssm的同城上门维修平台管理系统:前端jsp、jquery、bootstrap,后端 spring、mybatis,集成订单管理、商品管理、商品类型管理、商品浏览、购物车等功能于一体的系统。 ## 功能介绍 ### 用户 - 基本功能:登录、注册、退出、…...
力扣-hot100(和为k的子数组)
560. 和为 K 的子数组 中等 给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 示例 1: 输入:nums [1,1,1], k 2 输出:2 示例 2: 输入…...
【计算机视觉】CV实战 - 基于YOLOv5的人脸检测与关键点定位系统深度解析
基于YOLOv5的人脸检测与关键点定位系统深度解析 1. 技术背景与项目意义传统方案的局限性YOLOv5多任务方案的优势 2. 核心算法原理网络架构改进关键点回归分支损失函数设计 3. 实战指南:从环境搭建到模型应用环境配置数据准备数据格式要求数据目录结构 模型训练配置文…...
HTML word属性
介绍 CSS word-spacing 属性,用于指定段字之间的空间,例如: p {word-spacing:30px; }word-spacing属性增加或减少字与字之间的空白。 注意: 负值是允许的。 浏览器支持 表格中的数字表示支持该属性的第一个浏览器版本号。 属…...
Java—ThreadLocal底层实现原理
首先,ThreadLocal 本身并不提供存储数据的功能,当我们操作 ThreadLocal 的时候,实际上操作线程对象的一个名为 threadLocals 成员变量。这个成员变量的类型是 ThreadLocal 的一个内部类 ThreadLocalMap,它是真正用来存储数据的容器…...
GTSRB德国交通标志数据集下载以及训练集划分
GTSRB德国交通标志数据集下载以及训练集划分 一、数据集下载二、数据集划分 一、数据集下载 官网地址:附含数据集说明文档点击下载:训练数据集点击下载:测试数据集 二、数据集划分 在模型训练时,将训练数据集分成训练集和验证集&…...
python 实现客户端软件许可证书签名授权 cryptography
目录 1.需求 2.cryptography介绍 3.实际代码 4.结束语 1.需求 采用pyside6开发了一款客户端软件, 为保护核心算法源码, 采用Nuitka打包python代码,这仅仅保护了核心算法代码,不能限制用户使用软件,因此需要软件许可授权签名证书ÿ…...
明远智睿SD2351核心板:以48元撬动AI视觉产业革命的“硬核引擎”
在人工智能浪潮席卷全球的今天,AI视觉作为连接虚拟与现实的“智慧之眼”,正以惊人的速度重塑着产业格局。从智慧城市中的安防监控到自动驾驶汽车的“视觉神经”,从工业产线的缺陷检测到家庭场景的智能管家,AI视觉技术的每一次突破…...
【C语言】全局变量、静态本地变量
在C语言中,变量是存储数据的基本单元。 不同类型的变量有着不同的特性和用途,其中全局变量和本地变量是比较特殊且重要的两类变量。 一、全部变量 1.1 全局变量的作用域和生存期 全局变量是在函数外部定义的变量,其作用域从定义的位置开始&…...
32.768kHz晶振详解:作用、特性及与其他晶振的区别
一、32.768kHz晶振的核心作用 实时时钟(RTC)驱动: 提供精确的1Hz时钟信号,用于计时功能(如电子表、计算机CMOS时钟)。 分频公式: 1Hz 32.768kHz / 2^15(通过15级二分频实现&#x…...
classfinal 修改过源码,支持jdk17 + spring boot 3.2.8
先贴图 使用 classfinal 修改过源码 支持jdk17 spring boot 3.3.0 使用方式: 1、springboot的jar加密 java -jar classfinal-fatjar-1.2.1.jar -file MySpringBoot.jar -libjars my-common.jar -packages cn.com.cmd -pwd 123456 -Y 得到: MySpri…...