【Linux 设备模型框架 kobject 和 kset】
Linux 设备模型框架 kobject 和 kset
- 一、Linux 设备模型概述
- 二、kobject 与 kset 的核心概念
- 1. kobject
- 2. kset
- 3. 关键数据结构
- 三、kobject 与 kset 的实现源码
- 四、源码解析与使用说明
- 1. kset 的创建与初始化
- 2. kobject 的创建与属性
- 3. sysfs 属性操作
- 4. 用户空间访问示例
- 五、kobject 与 kset 的高级应用
- 1. 设备层次结构组织
- 2. 热插拔支持
- 3. 电源管理集成
- 六、总线注册与驱动开发
- 1. 注册自定义总线
- 2. 总线注册过程解析
- 3. 在自定义总线下注册驱动
- 4. 在自定义总线下注册设备
- 5. 总线、设备与驱动的匹配机制
- 6. 查看总线相关信息
- 七、总线注册与 kobject/kset 的关系
在 Linux 内核中,设备模型是连接硬件和软件的桥梁。理解 kobject 和 kset 这两个核心概念,对于开发高质量的内核驱动至关重要。本文将深入解析这两个概念,并通过实例代码展示如何在内核模块中使用它们。
一、Linux 设备模型概述
Linux 设备模型的核心目标是:
提供统一的设备管理机制
实现设备与驱动的分离
支持热插拔和电源管理
通过 sysfs 文件系统向用户空间暴露设备层次结构
而这一切的基础,就是kobject和kset。
二、kobject 与 kset 的核心概念
1. kobject
内核中最基本的对象结构
提供引用计数、父子关系和生命周期管理
是所有设备模型对象的基础
对应 sysfs 中的一个目录
2. kset
kobject 的集合,用于组织 kobject
本身也是一个 kobject
提供对象分组和过滤机制
对应 sysfs 中的一个子目录树
3. 关键数据结构
// include/linux/kobject.h
struct kobject {const char *name; // 对象名称struct list_head entry; // 链表节点struct kobject *parent; // 父对象struct kset *kset; // 所属ksetstruct kobj_type *ktype; // 对象类型struct sysfs_dirent *sd; // sysfs目录项struct kref kref; // 引用计数unsigned int state_initialized:1; // 初始化状态标志...
};
// kset定义
struct kset {struct list_head list; // 包含的kobject链表spinlock_t list_lock; // 链表锁struct kobject kobj; // 嵌入的kobjectconst struct kset_uevent_ops *uevent_ops; // uevent操作...
};
三、kobject 与 kset 的实现源码
下面通过一个完整的内核模块示例,展示如何使用 kobject 和 kset 创建自定义设备模型:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/string.h>
#include <linux/slab.h>/* 模块参数 */
static int my_param = 42;
module_param(my_param, int, 0644);
MODULE_PARM_DESC(my_param, "A sample parameter");/* 设备私有数据结构 */
struct my_device {struct kobject kobj; // 嵌入的kobjectint value; // 设备值struct mutex lock; // 并发控制锁
};static struct my_device *my_dev;/* kobject属性操作函数 */
static ssize_t value_show(struct kobject *kobj, struct kobj_attribute *attr,char *buf)
{struct my_device *dev = container_of(kobj, struct my_device, kobj);mutex_lock(&dev->lock);ssize_t ret = sprintf(buf, "%d\n", dev->value);mutex_unlock(&dev->lock);return ret;
}static ssize_t value_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t count)
{struct my_device *dev = container_of(kobj, struct my_device, kobj);int ret;long val;mutex_lock(&dev->lock);ret = kstrtol(buf, 10, &val);if (ret) {mutex_unlock(&dev->lock);return ret;}dev->value = val;mutex_unlock(&dev->lock);return count;
}/* 定义kobject属性 */
static struct kobj_attribute value_attr =__ATTR(value, 0664, value_show, value_store);/* 定义参数属性 */
static ssize_t param_show(struct kobject *kobj, struct kobj_attribute *attr,char *buf)
{return sprintf(buf, "%d\n", my_param);
}static ssize_t param_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t count)
{return kstrtoint(buf, 10, &my_param);
}static struct kobj_attribute param_attr =__ATTR(param, 0664, param_show, param_store);/* kobject释放函数 */
static void my_kobj_release(struct kobject *kobj)
{struct my_device *dev = container_of(kobj, struct my_device, kobj);pr_info("My device kobject released\n");kfree(dev);
}/* 不使用groups,改用手动创建属性 */
static struct kobj_type my_ktype = {.release = my_kobj_release,.sysfs_ops = &kobj_sysfs_ops,
};/* 创建kset */
static struct kset *my_kset;/* kset的uevent操作 */
static int my_uevent_filter(struct kset *kset, struct kobject *kobj)
{pr_info("Uevent filter called for %s\n", kobject_name(kobj));return 1; // 允许发送uevent
}static const char *my_uevent_name(struct kset *kset, struct kobject *kobj)
{return kobject_name(kobj);
}static int my_uevent(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env)
{pr_info("Uevent generated for %s\n", kobject_name(kobj));return 0;
}static struct kset_uevent_ops my_uevent_ops = {.filter = my_uevent_filter,.name = my_uevent_name,.uevent = my_uevent,
};/* 模块初始化 */
static int __init my_module_init(void)
{int ret;/* 创建kset */my_kset = kset_create_and_add("my_kset", &my_uevent_ops, kernel_kobj);if (!my_kset) {pr_err("Failed to create kset\n");return -ENOMEM;}/* 分配并初始化设备结构 */my_dev = kzalloc(sizeof(*my_dev), GFP_KERNEL);if (!my_dev) {pr_err("Failed to allocate device\n");kset_unregister(my_kset);return -ENOMEM;}/* 初始化kobject */kobject_init(&my_dev->kobj, &my_ktype);/* 设置kobject的父对象为my_kset */my_dev->kobj.kset = my_kset;/* 设置kobject名称 */ret = kobject_add(&my_dev->kobj, NULL, "my_device");if (ret) {pr_err("Failed to add kobject\n");kfree(my_dev);kset_unregister(my_kset);return ret;}/* 手动创建属性文件 */ret = sysfs_create_file(&my_dev->kobj, &value_attr.attr);if (ret) {pr_err("Failed to create value attribute\n");goto err_attr;}ret = sysfs_create_file(&my_dev->kobj, ¶m_attr.attr);if (ret) {pr_err("Failed to create param attribute\n");goto err_param;}/* 初始化设备值 */my_dev->value = 0;mutex_init(&my_dev->lock);pr_info("My module initialized\n");return 0;err_param:sysfs_remove_file(&my_dev->kobj, &value_attr.attr);
err_attr:kobject_put(&my_dev->kobj);kset_unregister(my_kset);return ret;
}/* 模块退出 */
static void __exit my_module_exit(void)
{/* 手动移除属性文件 */sysfs_remove_file(&my_dev->kobj, &value_attr.attr);sysfs_remove_file(&my_dev->kobj, ¶m_attr.attr);/* 释放kobject */kobject_put(&my_dev->kobj);/* 释放kset */kset_unregister(my_kset);pr_info("My module exited\n");
}module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("cmy");
MODULE_DESCRIPTION("kobject and kset example");
四、源码解析与使用说明
1. kset 的创建与初始化
my_kset = kset_create_and_add("my_kset", &my_uevent_ops, kernel_kobj);
创建一个名为 “my_kset” 的 kset
父对象设置为kernel_kobj,对应 sysfs 中的/sys/kernel目录
注册 uevent 回调函数,处理热插拔事件
2. kobject 的创建与属性
kobject_init(&my_dev->kobj, &my_ktype);
ret = kobject_add(&my_dev->kobj, NULL, "my_device");
创建一个名为 “my_device” 的 kobject,作为 my_kset 的子对象
通过__ATTR宏定义两个属性:value和param
属性对应 sysfs 中的文件,可通过读写操作与内核交互
3. sysfs 属性操作
static ssize_t value_show(struct kobject *kobj, ...)
static ssize_t value_store(struct kobject *kobj, ...)
value_show():处理用户读取value属性的请求
value_store():处理用户写入value属性的请求
通过container_of宏从 kobject 获取设备私有数据
4. 用户空间访问示例
五、kobject 与 kset 的高级应用
1. 设备层次结构组织
可以创建多层 kset 和 kobject,构建复杂的设备树
例如:总线→设备→功能部件
2. 热插拔支持
通过 uevent 机制通知用户空间设备变化
支持动态加载和卸载驱动
3. 电源管理集成
通过 kobject 属性暴露设备电源状态
实现设备的挂起和恢复
六、总线注册与驱动开发
1. 注册自定义总线
在 Linux 设备模型中,总线(Bus)是连接设备(Device)和驱动(Driver)的核心组件,负责管理两者的匹配与通信。以下是注册自定义总线的完整实现:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/device.h>/* 总线匹配函数 */
static int my_bus_match(struct device *dev, struct device_driver *drv)
{pr_info("My bus match: dev=%s, drv=%s\n", dev_name(dev), drv->name);/* 匹配逻辑示例:检查设备和驱动的名称 */if (strncmp(dev_name(dev), drv->name, strlen(drv->name)) == 0)return 1;return 0;
}/* uevent事件处理 */
static int my_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{add_uevent_var(env, "MY_BUS_EVENT=1");return 0;
}/* 驱动探测函数 */
static int my_bus_probe(struct device *dev)
{pr_info("My bus probe: device %s detected\n", dev_name(dev));return 0;
}/* 驱动移除函数 */
static int my_bus_remove(struct device *dev)
{pr_info("My bus remove: device %s removed\n", dev_name(dev));return 0;
}/* 驱动关闭函数 */
static void my_bus_shutdown(struct device *dev)
{pr_info("My bus shutdown: device %s shutdown\n", dev_name(dev));
}/* 自定义总线类型 */
struct bus_type my_bus_type = {.name = "my_bus", // 总线名称.dev_groups = NULL, // 设备属性组.match = my_bus_match, // 设备与驱动匹配函数.uevent = my_bus_uevent, // uevent事件处理.probe = my_bus_probe, // 驱动探测函数.remove = my_bus_remove, // 驱动移除函数.shutdown = my_bus_shutdown, // 驱动关闭函数
};/* 导出总线结构体,使其可被其他模块使用 */
EXPORT_SYMBOL_GPL(my_bus_type);/* 模块初始化 */
static int __init my_bus_init(void)
{int ret;/* 注册自定义总线 */ret = bus_register(&my_bus_type);if (ret) {pr_err("Failed to register my_bus\n");return ret;}pr_info("My bus registered successfully\n");return 0;
}/* 模块退出 */
static void __exit my_bus_exit(void)
{/* 注销总线 */bus_unregister(&my_bus_type);pr_info("My bus unregistered\n");
}module_init(my_bus_init);
module_exit(my_bus_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("cmy");
MODULE_DESCRIPTION("My bus driver example");
2. 总线注册过程解析
总线注册的核心步骤如下:
定义总线结构体:
struct bus_type my_bus_type = {.name = "my_bus",.match = my_bus_match,.probe = my_bus_probe,.remove = my_bus_remove,.shutdown = my_bus_shutdown,.uevent = my_bus_uevent,
};
name:总线名称,用于标识总线
match:关键函数,决定设备与驱动是否匹配
probe:驱动探测函数,设备匹配后调用
remove:驱动移除时调用
uevent:总线相关 uevent 事件处理
注册总线到内核:
ret = bus_register(&my_bus_type);
该函数会:
创建总线对应的 kset 和 kobject
在 sysfs 中生成/sys/bus/my_bus目录
注册总线的 uevent 处理机制
注销总线:
bus_unregister(&my_bus_type);
清理总线相关的所有资源,包括 sysfs 节点和注册的回调函数。
3. 在自定义总线下注册驱动
以下是在已注册的总线下开发并注册驱动的示例:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>/* 自定义总线类型(假设已注册) */
extern struct bus_type my_bus_type;/* 驱动探测函数 */
static int my_driver_probe(struct device *dev)
{pr_info("My driver probed: device %s\n", dev_name(dev));return 0;
}/* 驱动移除函数 */
static int my_driver_remove(struct device *dev)
{pr_info("My driver removed: device %s\n", dev_name(dev));return 0;
}/* 驱动结构体 */
static struct device_driver my_driver = {.name = "my_device", // 驱动名称.bus = &my_bus_type, // 关联的总线.probe = my_driver_probe,// 探测函数.remove = my_driver_remove,// 移除函数.shutdown = NULL,.suspend = NULL,.resume = NULL,
};/* 模块初始化 */
static int __init my_driver_init(void)
{int ret;/* 在自定义总线下注册驱动 */ret = driver_register(&my_driver);if (ret) {pr_err("Failed to register my_driver\n");return ret;}pr_info("My driver registered on my_bus\n");return 0;
}/* 模块退出 */
static void __exit my_driver_exit(void)
{/* 注销驱动 */driver_unregister(&my_driver);pr_info("My driver unregistered my_driver.bus = %x\n", my_driver.bus);
}module_init(my_driver_init);
module_exit(my_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("cmy");
MODULE_DESCRIPTION("My driver example");
4. 在自定义总线下注册设备
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>/* 自定义总线类型(假设已注册) */
extern struct bus_type my_bus_type;/* 设备释放函数 */
static void my_device_release(struct device *dev)
{pr_info("My device released\n");
}/* 设备结构体 */
static struct device my_device = {.init_name = "my_device", // 设备初始名称.bus = &my_bus_type, // 关联的总线.parent = NULL, // 父设备.release = my_device_release, // 释放函数
};/* 模块初始化 */
static int __init my_device_init(void)
{int ret;/* 在自定义总线下注册设备 */ret = device_register(&my_device);if (ret) {pr_err("Failed to register my_device\n");return ret;}pr_info("My device registered on my_bus\n");return 0;
}/* 模块退出 */
static void __exit my_device_exit(void)
{/* 注销设备 */device_unregister(&my_device);pr_info("My device unregistered\n");
}module_init(my_device_init);
module_exit(my_device_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("cmy");
MODULE_DESCRIPTION("My device example");
5. 总线、设备与驱动的匹配机制
当设备和驱动都注册到同一总线后,总线的match函数会被调用,典型匹配流程:
设备注册时:总线会遍历所有已注册的驱动,调用match函数检查是否匹配
驱动注册时:总线会遍历所有已注册的设备,调用match函数检查是否匹配
匹配成功后:自动调用驱动的probe函数初始化设备
/* 总线匹配函数 */
static int my_bus_match(struct device *dev, struct device_driver *drv)
{pr_info("My bus match: dev=%s, drv=%s\n", dev_name(dev), drv->name);/* 匹配逻辑示例:检查设备和驱动的名称 */if (strncmp(dev_name(dev), drv->name, strlen(drv->name)) == 0)return 1;return 0;
}
6. 查看总线相关信息
sysfs 中的总线目录:
ls /sys/bus/my_bus/
查看已注册的设备和驱动:
# 设备列表
ls /sys/bus/my_bus/devices/# 驱动列表
ls /sys/bus/my_bus/drivers/
七、总线注册与 kobject/kset 的关系
每个总线对应一个 kset,位于/sys/bus/[bus name]
总线的 kset 包含两个子 kset:devices和drivers
设备和驱动注册时,会自动添加到总线的对应 kset 中
总线的 uevent 机制基于 kobject 的 uevent 扩展实现
通过总线机制,Linux 设备模型实现了设备与驱动的分离管理,使得驱动可以动态加载并自动匹配对应的设备,这是热插拔功能的核心基础。
相关文章:
【Linux 设备模型框架 kobject 和 kset】
Linux 设备模型框架 kobject 和 kset 一、Linux 设备模型概述二、kobject 与 kset 的核心概念1. kobject2. kset3. 关键数据结构 三、kobject 与 kset 的实现源码四、源码解析与使用说明1. kset 的创建与初始化2. kobject 的创建与属性3. sysfs 属性操作4. 用户空间访问示例 五…...
leetcode.2014 重复k次的最长子序列
题目描述 解题思路 这一题本来在想怎么样做才能获得通用解,因为乍一看总感觉遍历的时间代价会非常高。直到后面看到提示: 提示里面专门包含了一个n < k * 8,这太反常了。后面仔细一想,有道理,最后答案的字符个数一定…...
机器学习3——参数估计之极大似然估计
参数估计 问题背景: P ( ω i ∣ x ) p ( x ∣ ω i ) P ( ω i ) p ( x ) p ( x ) ∑ j 1 c p ( x ∣ ω j ) P ( ω j ) \begin{aligned} & P\left(\omega_i \mid \mathbf{x}\right)\frac{p\left(\mathbf{x} \mid \omega_i\right) P\left(\omega_i\right)…...
利用python实现NBA数据可视化
大家好,今天我们利用python爬取NBA球星每年的比赛数据并进行可视化展示。主要用到三个模块:xpath、matplotlib。其中xpth负责爬取网站上的信息。Matplotlib是Python开发人员常用的Python绘图库,可以用来绘制各种2D图形,具有绘图质…...
杭州西湖断桥不断:3D扫描还原‘残雪‘视觉骗局
“断桥残雪”是西湖十景之一,所谓“视觉骗局”指的是在特定条件下,从远处看断桥仿佛断开的奇妙视觉效果。利用3D扫描技术还原这一效果可按以下步骤进行: 数据采集 3D扫描断桥:使用高精度的3D激光扫描仪对断桥及其周边环境进行全面…...
Dubbo服务调用超时问题解决方案
Dubbo服务调用超时问题解决方案 Dubbo服务调用超时通常由网络延迟、服务端性能瓶颈、配置不当或资源竞争引发。以下解决方案基于根本原因分类,优先采用高可信度实践: 🔍 一、排查问题根源 网络诊断 使用 ping、telnet 检查服务提供者网络连…...
视觉疲劳检测如何优化智能驾驶的险情管理
视觉分析疲劳检测在智能驾驶中的应用研究 一、背景与需求 近年来,智能驾驶领域因疲劳驾驶引发的交通事故频发,如2025年某品牌智能汽车因驾驶员疲劳导致高速追尾事件,暴露了现有技术对复杂场景的适应不足。传统疲劳检测依赖单一生理信号或车…...
C++ 第三阶段 并发与异步 - 第二节:异步任务(std::async)
目录 一、std::async 概述 1. std::async 的定义 二、std::async 的基本用法 1. 基本语法 (1) 函数调用 (2) Lambda 表达式 三、执行策略详解 1. std::launch::async 2. std::launch::deferred 3. 默认策略(std::launch::any) 四、std::futur…...
OpenCV图像添加水印
一、前言 在数字图像处理中,为图片添加水印是一项常见且重要的技术。无论是版权保护、品牌宣传还是防止未经授权的使用,水印都能发挥重要作用。OpenCV作为一款强大的计算机视觉库,提供了丰富的功能来实现各种水印效果。本教程将详细介绍如何…...
Linux信号机制:从入门到精通
嘿,小伙伴们!今天我要和大家聊一个Linux系统中非常有趣又重要的话题——信号机制。别担心,虽然信号听起来有点高深,但我会用最通俗易懂的语言,配合清晰的图表,带你彻底搞懂这个概念! 什么是信号…...
EXCEL数据报表
客单价成交金额*成交客户数 —— 提取年份 YEAR() 视图-窗口-新建窗口,就能将excel的一个子表格单拎出来成为独立窗口,方便对比查看 数据报表的单元格尽量都用公式来填补,链接到源表上去。这样当源表有新数据更新进来后,报表也…...
openGL学习(VAO和VBO)
理论 VBO void prepare() {//创建一个VBO,但是还没有分配显存GLuint vbo 0;GL_CALL( glGenBuffers(1, &vbo));cout << "vbo " << vbo << endl;//销毁一个VBOGL_CALL(glDeleteBuffers(1, &vbo));cout << "delete vbo "…...
【请关注】制造企业机械加工数据脱敏解决方案
制造企业机械加工数据脱敏解决方案 一、方案概述 在制造企业尤其是机械加工领域,数字化转型带来了生产效率的大幅提升,大量生产数据、设备运行数据、供应链数据以及客户订单数据等成为企业发展的关键驱动力。然而,这些数据中包含众多敏感信息,如客户定制产品的设计图纸(…...
2025.6.27总结
最近工作又开始内耗了,一位同事的转岗直接让我破防了,明明他工作干得很不错,会得又多,性格又好,我还经常请教他业务上的问题。我和他的关系并不算太好,但他加入其他部门,竟然让我有些不舍&#…...
Python打卡:Day38
知识点回顾: Dataset类的__getitem__和__len__方法(本质是python的特殊方法)Dataloader类minist手写数据集的了解 浙大疏锦行...
Ubuntu18.04/Mysql 5.7 建立主备模式Mysql集群
一、数据库的安装 详见https://www.jianshu.com/p/5073177eedf2 本文实验环境为阿里云的两台ubuntu18.04服务器: master ip: 172.26.138.7 slave ip: 172.26.0.209 二、修改Master的配置(# 的行是我后增加的部分): 编辑 /etc/mysql/mysql.conf.d/mysqld.…...
Linux journal 日志大小限制与管理详解
文章目录 Linux journal 日志大小限制与管理详解journal 日志的默认存储位置journal 日志大小限制配置查看当前日志占用情况手动清理日志文件按大小清理日志按时间清理日志按文件数清理日志 journald 日志机制原理简析(适当加点原理)日志筛选与导出技巧&…...
Linux基本指令篇 —— tac指令
tac 是 Linux 系统中一个非常实用的文本处理命令,它是 cat 命令的反向操作(名称也是 "cat" 的反写)。tac 是一个简单但功能强大的工具,特别适合需要反向处理文本数据的场景: 目录 一、基本功能 二、基本语法…...
【Yonghong 企业日常问题08 】永洪BI的Apache Tomcat版本升级指南
文章目录 前言操作步骤登录验证 前言 某公司业务永洪BI系统使用tomcat 9.0.97版本,接到总公司漏洞扫描整改要求需要将tomcat版本升级到9.0.97以上。 目标:tomcat 9.0.97》 9.0.98 1、下载tomcat所需要的版本 地址:https://tomcat.apache.org/download-…...
动手学Python:从零开始构建一个“文字冒险游戏”
动手学Python:从零开始构建一个“文字冒险游戏” 大家好,我是你的技术向导。今天,我们不聊高深的框架,也不谈复杂的算法,我们来做一点“复古”又极具趣味性的事情——用Python亲手打造一个属于自己的文字冒险游戏&…...
【C/C++】C++26新特性前瞻:全面解析未来编程
展望未来:C26 新特性全面解析 随着 C 标准每三年一次的迭代节奏,C26(预计于 2026 年底正式发布)正在逐步成型。相比 C20 的革命性更新和 C23 的“修补增强”,C26 继续推进现代 C 的理念——更安全、更高效、更模块化&…...
Linux系统日志与守护进程开发实战指南
Linux系统日志与守护进程开发实战指南 系统日志与守护进程 ├── 系统日志syslog │ ├── 日志路径: /var/log/syslog │ └── 核心API │ ├── openlog │ ├── syslog │ └── closelog └── 守护进程daemon└── 创建步骤├── um…...
兰洋科技上合组织论坛发表专题分享,全球液冷布局引领绿色算力未来
2025年6月17-19日,中国—上海合作组织数字技术合作发展论坛在新疆克拉玛依市举办。作为第四次上海合作组织成员国信息通信技术发展部门负责人会议的配套会议,论坛以“数字化转型助力可持续发展,数字包容促进上合共同繁荣”为主题,…...
桌面小屏幕实战课程:DesktopScreen 11 SPI 水墨屏
飞书文档https://x509p6c8to.feishu.cn/docx/doxcnlzpIgj3gosCZufBTCZxlMb SPI说明 SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上占用…...
小知识点五、无刷电机闭环控制(电流)
0 前言 该部分只用于自学使用,作为笔记方便后续自查。 资料参考:http://dengfoc.com 硬件:2208云台电机MT6701磁编码器 1 电流控制理论 1.1 待解决的问题 简单回顾一下在之前的学习中,我们通过 U q U_q Uq和电角度 θ \the…...
Java 编程之备忘录模式
前言 有时候,我们真希望人生能有“CtrlZ”。在日常生活中,我们经常使用“撤销”功能,例如在写 Word、画图、写代码时一不小心操作失误,就希望能回到之前的状态。这种**“状态快照 恢复”**机制,在设计模式中就叫做&a…...
SQL SERVER存储过程
什么是存储过程 SQL 存储过程(Stored Procedure)是一个在数据库中预编译并存储的一组 SQL 语句。它们可以包含查询、插入、更新、删除等数据库操作,甚至包括控制流语句(如条件判断、循环等)。存储过程可以通过调用来执…...
Vue样式绑定与条件渲染详
一、Vue样式绑定 在Vue中,我们可以通过多种方式动态地绑定样式,让界面根据数据状态变化而自动更新样式。 1. class样式绑定 (1) 字符串写法 适用场景:样式的类名不确定,需要动态指定 <template><div><!-- 绑定…...
python基于协同过滤的动漫推荐系统
目录 技术栈介绍具体实现截图系统设计研究方法:设计步骤设计流程核心代码部分展示研究方法详细视频演示试验方案论文大纲源码获取/详细视频演示 技术栈介绍 Django-SpringBoot-php-Node.js-flask 本课题的研究方法和研究步骤基本合理,难度适中…...
光场操控新突破!3D 光学信息处理迎来通用 PSF 工程时代--《自然》子刊:无需复杂算法,这一技术让 3D 光学成像实现 “即拍即得”念日
导语 在光学成像领域,如何突破分辨率与成像速度的瓶颈,一直是科研人员探索的焦点。近日,加州大学洛杉矶分校(UCLA)的研究团队在《Light: Science & Applications》发表论文,提出了一种通用点扩散函数&a…...
ubuntu20.04如何给appImage创建快捷方式
ubuntu20.04如何给appImage创建快捷方式 1. 确保AppImage是可执行的 chmod x /path/to/your/appimage2. 创建.desktop文件 在~/.local/share/applications/目录下创建一个新的 .desktop 文件: vi ~/.local/share/applications/your-appname.desktop添加以下内容…...
网络安全之SQL RCE漏洞
引言 堡垒机(Bastion Host),也称为跳板机或运维安全审计系统,是一种用于管理和控制对内部网络资源访问的安全设备。它的主要作用是作为运维人员访问内部服务器和网络设备的唯一入口,通过集中化的身份认证、权限管理和…...
DeepSeek网页版随机点名器
用DeepSeek帮我们生成了一个基于html5的随机点名器,效果非常棒,如果需要加入名字,请在代码中按照对应的格式添加即可。 提示词prompt 帮我生成一个随机点名的HTML5页面 生成真实一点的名字数据 点击随机按钮开始随机选择 要有闪动的效果 &…...
Elasticsearch索引字段的类型
在 Elasticsearch 中,索引字段的类型(即 Mapping 中的字段类型)对搜索和存储性能影响很大。下面是各种常用数据类型的用途及推荐使用场景总结: 1. keyword 类型(精确匹配) 适合数据: 不需要分词…...
大模型在慢性病毒性肝炎预测及诊疗方案制定中的应用研究
目录 一、引言 1.1 研究背景与意义 1.2 研究目的与创新点 二、慢性病毒性肝炎概述 2.1 疾病定义与分类 2.2 发病机制与病理特征 2.3 流行病学现状 三、数据收集与预处理 3.1 数据来源 3.2 数据清洗 3.3 特征工程 四、大模型选择与构建 4.1 模型选择依据 4.2 模型…...
DAY 43 复习日
浙大疏锦行https://blog.csdn.net/weixin_45655710 第一步:寻找并准备图像数据集 在Kaggle等平台上,你可以找到大量用于图像分类任务的数据集,例如英特尔图像分类数据集 (Intel Image Classification) 或手写数字识别数据集 (Digit Recogni…...
SQL学习笔记3
SQL常用函数 1、字符串函数 函数调用的语法:select 函数(参数); 常用的字符串函数有: 拼接字符串,将几个字符串拼到一起:concat (s1,s2,……); select concat(你好,hello); update mytable set wherefo concat(中…...
JVM调优实战 Day 7:JVM线程分析与死锁排查
【JVM调优实战 Day 7】JVM线程分析与死锁排查 文章标签 jvm调优, 线程分析, 死锁排查, JVM监控, Java性能优化, JVM参数配置 文章简述 在Java应用的高并发场景中,线程管理与死锁问题往往是性能瓶颈的根源。本文作为“JVM调优实战”系列的第7天,深入解析…...
Android-Layout Inspector使用手册
Layout Inspector Android Layout Inspector 是 Android Studio 中用于调试应用布局的工具 启动方法: 通过下载Layout Inspector插件,在 “View - Tool Windows - Layout Inspector” 或 “Tools - Layout Inspector” 启动。 主要界面区域:…...
【51单片机5毫秒定时器】2022-6-1
缘由单片机的代码,求大家来帮帮我-编程语言-CSDN问答 #include "REG52.h" unsigned char code smgduan[]{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0,64}; //共阴0~F消隐减号 unsigned char Js0, miao0;//中断…...
Flutter 多平台项目开发指南
Flutter 多平台项目开发指南 本指南将帮助你从 0 到 1 创建并适配一个支持 Android / iOS / Web / Windows / macOS / Linux 的 Flutter 多平台项目。 ✅ 一、创建支持多平台的 Flutter 项目 flutter create my_multi_platform_app cd my_multi_platform_app默认会生成支持以…...
Mac电脑如何搭建基于java后端的开发的各种工具服务
1. 确认Mac的CPU架构 首先,确认您的Mac是使用Intel还是Apple Silicon(如M1芯片)架构: uname -m如果返回x86_64,表示是Intel架构。如果返回arm64,表示是Apple Silicon架构。 2.安装IDEA Download Intelli…...
深入解析前端 Meta 标签:HTML 的隐形守护者与功能大师
在构建现代网页时,我们常常关注炫目的视觉效果、复杂的交互逻辑或强大的框架,却容易忽略那些深藏于 <head> 之中、看似不起眼的 <meta> 标签。这些标签如同网页的隐形守护者,无声地承担着定义文档元数据、指导浏览器行为、优化搜…...
CRON表达式编辑器与定时任务实现技术文档
1. 前端CRON表达式编辑器组件 CronExpressionEditor.vue组件是系统中用于创建和编辑CRON表达式的核心UI组件,它提供了直观的界面来生成复杂的定时任务表达式。 1.1 组件结构与状态管理 // 核心状态变量 const second ref<string>(0); const minute ref&…...
45. 跳跃游戏 II
给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - 1] 的最…...
《解锁AudioSet:开启音频分析的无限可能》
音频新时代的 “密钥”:AudioSet 登场 在科技飞速发展的今天,音频作为信息传播与交互的关键媒介,早已渗透到现代科技的各个角落。从智能手机中的语音助手,让我们通过简单的语音指令就能查询信息、发送消息,到智能家居系…...
环境太多?不好管理怎么办?TakMll 工具帮你快速切换和管理多语言、多版本情况下的版本切换。
本篇文章主要介绍一款环境管理工具,即TakMll,通过简单的入口命令 “tkm” 即可快速的管理多种语言下、多种版本的环境切换,诸如快速切换PHP、同时存在java、mave等不同版本。 作者:任聪聪 日期:2025年6月26日 TakMll 特…...
spring-ai 1.0.0 (1)模型调用能力
听说1.0是一个非常好用的版本,最后还是扛不住听说的压力,为了落实自己悬浮心理,自己还是着手实践一下了。 第一步pom集成: 参考spring-projects/spring-ai | DeepWiki维基以及官方文档入门 :: Spring AI …...
如何在 Manjaro Linux 上启用 AUR 仓库来安装软件包
Manjaro 是基于 Arch 的系统,是了解和学习 Arch Linux 命令的绝佳方式。它自带所有流行的桌面环境界面,无论是 XFCE 还是 Gnome 的爱好者,都可以在 Manjaro 中直接使用。 Manjaro 或 Arch Linux 的默认软件包管理器是 Pacman,我们…...
简单使用python
本文章没有深入探讨python,只说语法格式,合适于有其他编程语言的基础、并想快速使用python的人查看。 一、print() 用于打印信息,括号中可以是数学运算表达式或者字符串(或者说是文字)。 print(hello!) 1.1、转义字…...