Linux驱动开发实战(四):设备树点RGB灯
Linux驱动开发实战(四):设备树点RGB灯
文章目录
- Linux驱动开发实战(四):设备树点RGB灯
- 前言
- 一、驱动实现
- 1.1 驱动设计思路
- 1.2 关键数据结构
- 1.3 字符设备操作函数
- 1.4 平台驱动探测函数
- 1.5 匹配表和平台驱动结构体
- 1.6 模块初始化和注销函数
- 二、设备树配置
- 三、从原理图分析设备树配置
- 3.1 引脚与GPIO的对应关系
- 3.2 寄存器地址解析
- 3.3 电路连接分析
- 四、引脚复用机制详解
- 4.1 引脚功能选择过程
- 4.2 为什么要配置PAD属性
- 五、实验
- 5.1 添加设备树
- 5.2 编译设备树
- 5.3 替换设备树
- 5.4 编译驱动文件
- 5.5 加载驱动文件
- 5.6 往设备文件写入值(点灯!!!)
- 总结
前言
在嵌入式Linux开发中,如何将硬件与软件紧密结合是一项基础却重要的技能。本文将详细讲解如何通过驱动程序控制i.MX6平台上的RGB LED,并深入分析从驱动代码、设备树配置到硬件原理图之间的关系
提示:以下是本篇文章正文内容,下面案例可供参考
一、驱动实现
1.1 驱动设计思路
我们使用平台驱动模型结合设备树进行开发,通过配置引脚复用和GPIO控制来实现RGB LED的控制。整体思路是:
- 定义数据结构保存LED控制需要的寄存器地址
- 从设备树获取资源并初始化GPIO
- 实现用户空间接口用于控制LED
1.2 关键数据结构
#define DEV_NAME "rgb_led"
#define DEV_CNT (1)
- DEV_NAME: 定义字符设备的名称为"rgb_led"
- DEV_CNT: 定义要创建的设备数量为1
struct rgb_led_dev {struct device_node *device_node; // 设备节点void __iomem *virtual_CCM_CCGR; // 时钟控制寄存器void __iomem *virtual_IOMUXC_SW_MUX_CTL_PAD; // 引脚复用寄存器void __iomem *virtual_IOMUXC_SW_PAD_CTL_PAD; // 引脚电气特性寄存器void __iomem *virtual_DR; // GPIO数据寄存器void __iomem *virtual_GDIR; // GPIO方向寄存器unsigned int pin_num; // GPIO引脚号
};
1.3 字符设备操作函数
static int led_chr_dev_open(struct inode *inode, struct file *filp)
{printk("\n open form driver \n");return 0;
}
这是字符设备的打开函数,仅打印一条日志信息并返回成功(0)。
static ssize_t led_chr_dev_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{int ret,error;unsigned int register_data = 0;unsigned char receive_data[10];unsigned int write_data;if(cnt>10)cnt =10;error = copy_from_user(receive_data, buf, cnt);if (error < 0){return -1;}ret = kstrtoint(receive_data, 16, &write_data);if (ret) {return -1;}/*设置 GPIO1_04 输出电平*/if (write_data & 0x04){register_data = ioread32(led_red.virtual_DR);register_data &= ~(0x01 << 4);iowrite32(register_data, led_red.virtual_DR); // GPIO1_04引脚输出低电平,红灯亮}else{register_data = ioread32(led_red.virtual_DR);register_data |= (0x01 << 4);iowrite32(register_data, led_red.virtual_DR); // GPIO1_04引脚输出高电平,红灯灭}/*设置 GPIO4_20 输出电平*/if (write_data & 0x02){register_data = ioread32(led_green.virtual_DR);register_data &= ~(0x01 << 20);iowrite32(register_data, led_green.virtual_DR); // GPIO4_20引脚输出低电平,绿灯亮}else{register_data = ioread32(led_green.virtual_DR);register_data |= (0x01 << 20);iowrite32(register_data, led_green.virtual_DR); // GPIO4_20引脚输出高电平,绿灯灭}/*设置 GPIO4_19 输出电平*/if (write_data & 0x01){register_data = ioread32(led_blue.virtual_DR);register_data &= ~(0x01 << 19);iowrite32(register_data, led_blue.virtual_DR); //GPIO4_19引脚输出低电平,蓝灯亮}else{register_data = ioread32(led_blue.virtual_DR);register_data |= (0x01 << 19);iowrite32(register_data, led_blue.virtual_DR); //GPIO4_19引脚输出高电平,蓝灯灭}return cnt;
}
这是字符设备的写函数,主要完成:
- 限制接收数据量最大为10字节
- 使用copy_from_user将用户空间数据复制到内核空间
- 使用kstrtoint将接收到的字符串转换为整数(16进制)
- 根据接收到的值控制三个LED的状态:
- 位0控制蓝灯(值为1时点亮)
- 位1控制绿灯(值为2时点亮)
- 位2控制红灯(值为4时点亮)
- 通过读取当前寄存器值,修改相应位,然后写回寄存器的方式控制GPIO输出
- 注意这些LED是低电平点亮的
开发板终端输出:
static struct file_operations led_chr_dev_fops =
{.owner = THIS_MODULE,.open = led_chr_dev_open,.write = led_chr_dev_write,
};
定义了字符设备的操作函数集,包含了所有者、打开函数和写函数。
1.4 平台驱动探测函数
static int led_probe(struct platform_device *pdv)
{int ret = -1;unsigned int register_data = 0;printk(KERN_ALERT "\t match successed \n");/*获取rgb_led的设备树节点*/rgb_led_device_node = of_find_node_by_path("/rgb_led");if (rgb_led_device_node == NULL){printk(KERN_ERR "\t get rgb_led failed! \n");return -1;}
平台驱动的探测函数开始部分:
- 声明变量用于保存返回值和寄存器数据
- 打印匹配成功信息
- 通过路径"/rgb_led"获取设备树节点,失败则返回错误
接下来分别初始化红、绿、蓝三个LED,以红色LED为例:
/*获取rgb_led节点的红灯子节点*/led_red.device_node = of_find_node_by_name(rgb_led_device_node,"rgb_led_red");if (led_red.device_node == NULL){printk(KERN_ERR "\n get rgb_led_red_device_node failed ! \n");return -1;}/*获取 reg 属性并转化为虚拟地址*/led_red.virtual_CCM_CCGR = of_iomap(led_red.device_node, 0);led_red.virtual_IOMUXC_SW_MUX_CTL_PAD = of_iomap(led_red.device_node, 1);led_red.virtual_IOMUXC_SW_PAD_CTL_PAD = of_iomap(led_red.device_node, 2);led_red.virtual_DR = of_iomap(led_red.device_node, 3);led_red.virtual_GDIR = of_iomap(led_red.device_node, 4);/*初始化红灯*/register_data = ioread32(led_red.virtual_CCM_CCGR);register_data |= (0x03 << 26);iowrite32(register_data, led_red.virtual_CCM_CCGR); //开启时钟register_data = ioread32(led_red.virtual_IOMUXC_SW_MUX_CTL_PAD);register_data &= ~(0xf << 0);register_data |= (0x05 << 0);iowrite32(register_data, led_red.virtual_IOMUXC_SW_MUX_CTL_PAD); //设置复用功能register_data = ioread32(led_red.virtual_IOMUXC_SW_PAD_CTL_PAD);register_data = (0x10B0);iowrite32(register_data, led_red.virtual_IOMUXC_SW_PAD_CTL_PAD); //设置PAD 属性register_data = ioread32(led_red.virtual_GDIR);register_data |= (0x01 << 4);iowrite32(register_data, led_red.virtual_GDIR); //设置GPIO1_04 为输出模式register_data = ioread32(led_red.virtual_DR);register_data |= (0x01 << 4);iowrite32(register_data, led_red.virtual_DR); //设置 GPIO1_04 默认输出高电平
红色LED初始化过程:
1.获取红色LED的设备树节点
2.将设备树中的reg属性映射为虚拟地址(共5个寄存器)
3.初始化GPIO:
- 使能相关时钟
- 设置管脚复用功能(设为GPIO模式)
- 设置管脚物理属性
- 设置GPIO为输出模式
- 设置默认输出高电平(LED熄灭)
绿色和蓝色LED的初始化过程类似,但操作的是不同的GPIO引脚。
最后是注册字符设备的部分:
/*---------------------注册 字符设备部分-----------------*///第一步//采用动态分配的方式,获取设备编号,次设备号为0,//设备名称为rgb-leds,可通过命令cat /proc/devices查看//DEV_CNT为1,当前只申请一个设备编号ret = alloc_chrdev_region(&led_devno, 0, DEV_CNT, DEV_NAME);if (ret < 0){printk("fail to alloc led_devno\n");goto alloc_err;}//第二步//关联字符设备结构体cdev与文件操作结构体file_operationsled_chr_dev.owner = THIS_MODULE;cdev_init(&led_chr_dev, &led_chr_dev_fops);//第三步//添加设备至cdev_map散列表中ret = cdev_add(&led_chr_dev, led_devno, DEV_CNT);if (ret < 0){printk("fail to add cdev\n");goto add_err;}//第四步/*创建类 */class_led = class_create(THIS_MODULE, DEV_NAME);/*创建设备*/device = device_create(class_led, NULL, led_devno, NULL, DEV_NAME);return 0;add_err://添加设备失败时,需要注销设备号unregister_chrdev_region(led_devno, DEV_CNT);printk("\n error! \n");
alloc_err:return -1;
}
字符设备注册过程:
- 使用alloc_chrdev_region动态分配设备号
- 初始化字符设备结构体并关联操作函数
- 添加字符设备到系统中
- 创建设备类和设备节点
- 设置错误处理,如果添加失败则释放设备号.
1.5 匹配表和平台驱动结构体
static const struct of_device_id rgb_led[] = {{.compatible = "fire,rgb_led"},{/* sentinel */}};/*定义平台设备结构体*/
struct platform_driver led_platform_driver = {.probe = led_probe,.driver = {.name = "rgb-leds-platform",.owner = THIS_MODULE,.of_match_table = rgb_led,}};
这部分定义了:
- 设备树匹配表,用于匹配compatible属性为"fire,rgb_led"的设备树节点
- 平台驱动结构体,指定了探测函数、驱动名称、所有者和匹配表
1.6 模块初始化和注销函数
static int __init led_platform_driver_init(void)
{int DriverState;DriverState = platform_driver_register(&led_platform_driver);printk(KERN_ALERT "\tDriverState is %d\n", DriverState);return 0;
}static void __exit led_platform_driver_exit(void)
{/*取消物理地址映射到虚拟地址*/iounmap(led_green.virtual_CCM_CCGR);iounmap(led_green.virtual_IOMUXC_SW_MUX_CTL_PAD);iounmap(led_green.virtual_IOMUXC_SW_PAD_CTL_PAD);iounmap(led_green.virtual_DR);iounmap(led_green.virtual_GDIR);iounmap(led_red.virtual_CCM_CCGR);iounmap(led_red.virtual_IOMUXC_SW_MUX_CTL_PAD);iounmap(led_red.virtual_IOMUXC_SW_PAD_CTL_PAD);iounmap(led_red.virtual_DR);iounmap(led_red.virtual_GDIR);iounmap(led_blue.virtual_CCM_CCGR);iounmap(led_blue.virtual_IOMUXC_SW_MUX_CTL_PAD);iounmap(led_blue.virtual_IOMUXC_SW_PAD_CTL_PAD);iounmap(led_blue.virtual_DR);iounmap(led_blue.virtual_GDIR);/*删除设备*/device_destroy(class_led, led_devno); //清除设备class_destroy(class_led); //清除类cdev_del(&led_chr_dev); //清除设备号unregister_chrdev_region(led_devno, DEV_CNT); //取消注册字符设备/*注销字符设备*/platform_driver_unregister(&led_platform_driver);printk(KERN_ALERT "led_platform_driver exit!\n");
}module_init(led_platform_driver_init);
module_exit(led_platform_driver_exit);MODULE_LICENSE("GPL");
模块初始化和注销函数:
- led_platform_driver_init:注册平台驱动并打印状态
- led_platform_driver_exit:
- 释放所有虚拟地址映射
- 销毁设备和设备类
- 删除字符设备
- 注销平台驱动
- 打印退出信息
- 使用module_init和module_exit宏注册这些函数
- 声明模块许可证为GPL
二、设备树配置
设备树是连接硬件与驱动的桥梁,这部分定义了RGB LED所需的硬件资源:
/*
*CCM_CCGR1 0x020C406C
*IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04 0x020E006C
*IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04 0x020E02F8
*GPIO1_GD 0x0209C000
*GPIO1_GDIR 0x0209C004
*//*
*CCM_CCGR3 0x020C4074
*IOMUXC_SW_MUX_CTL_PAD_CSI_HSYNC 0x020E01E0
*IOMUXC_SW_PAD_CTL_PAD_CSI_HSYNC 0x020E046C
*GPIO4_GD 0x020A8000
*GPIO4_GDIR 0x020A8004
*//*
*CCM_CCGR3 0x020C4074
*IOMUXC_SW_MUX_CTL_PAD_CSI_VSYNC 0x020E01DC
*IOMUXC_SW_PAD_CTL_PAD_CSI_VSYNC 0x020E0468
*GPIO4_GD 0x020A8000
*GPIO4_GDIR 0x020A8004
*//*添加led节点*/rgb_led{#address-cells = <1>;#size-cells = <1>;compatible = "fire,rgb_led";/*红灯节点*/ranges;rgb_led_red@0x020C406C{reg = <0x020C406C 0x000000040x020E006C 0x000000040x020E02F8 0x000000040x0209C000 0x000000040x0209C004 0x00000004>;status = "okay";};/*绿灯节点*/rgb_led_green@0x020C4074{reg = <0x020C4074 0x000000040x020E01E0 0x000000040x020E046C 0x000000040x020A8000 0x000000040x020A8004 0x00000004>;status = "okay";};/*蓝灯节点*/rgb_led_blue@0x020C4074{reg = <0x020C4074 0x000000040x020E01DC 0x000000040x020E0468 0x000000040x020A8000 0x000000040x020A8004 0x00000004>;status = "okay";};};
其中 0x020E01E0 是 IOMUXC_SW_MUX_CTL_PAD_CSI_HSYNC 的寄存器地址。这个寄存器就是用来配置 CSI_HSYNC 引脚功能的复用控制寄存器。同样,0x020E046C 是 IOMUXC_SW_PAD_CTL_PAD_CSI_HSYNC 的寄存器地址,用于设置 CSI_HSYNC 引脚的电气特性。
蓝色 LED 节点也类似,使用 0x020E01DC(IOMUXC_SW_MUX_CTL_PAD_CSI_VSYNC) 和 0x020E0468(IOMUXC_SW_PAD_CTL_PAD_CSI_VSYNC) 来配置 CSI_VSYNC 引脚。
在 i.MX 处理器的设计中,每个引脚都有专用的复用控制寄存器和 PAD 控制寄存器,寄存器的地址是固定的,与引脚一一对应。因此在设备树中,我们只需要提供寄存器地址,而不需要显式地声明引脚名称,驱动程序通过访问对应地址的寄存器就能控制特定的引脚。
这就是为什么在设备树中看不到 “CSI_HSYNC” 或 “CSI_VSYNC” 这些名称的原因 - 它们是通过对应的寄存器地址来表示的。而在电路图中,则直接使用引脚的功能名称来标识连接方式。
这种做法在嵌入式系统中很常见,因为它直接反映了硬件设计,而不需要额外的名称映射层。
三、从原理图分析设备树配置
3.1 引脚与GPIO的对应关系
查看i.MX6UL原理图,我们可以发现RGB LED连接到以下引脚:
-
红色LED: CSI_VSYNC引脚
-
绿色LED: CSI_HSYNC引脚
-
蓝色LED: CSI_DATA00引脚
根据i.MX6UL数据手册中的引脚复用表: -
CSI_VSYNC的ALT5功能对应GPIO1_04
-
CSI_HSYNC的ALT5功能对应GPIO4_20
-
CSI_DATA00的ALT5功能对应GPIO4_19
这是为什么设备树中我们配置了:
led-red {gpio-pin = <4>; /* GPIO1_04 */
}
3.2 寄存器地址解析
设备树中的reg属性定义了控制每个LED所需的寄存器地址:
- 时钟控制寄存器(CCM_CCGR1) : 0x020C4074
- 在i.MX6UL中,GPIO模块需要使能时钟才能工作
- CCM_CCGR1寄存器控制GPIO1的时钟门控
- 引脚复用控制寄存器 (IOMUXC_SW_MUX_CTL_PAD_CSI_VSYNC) : 0x020E01B0
- 控制CSI_VSYNC引脚的功能选择
- 写入0x05选择ALT5功能,即GPIO1_04
- 引脚电气特性寄存器(IOMUXC_SW_PAD_CTL_PAD_CSI_VSYNC) : 0x020E0478
- 控制引脚的驱动能力、上拉/下拉电阻等
- 值0x10B0配置适当的驱动强度和上拉电阻
- GPIO数据寄存器(GPIO1_DR) : 0x0209C000
- 控制GPIO1组引脚的输出电平
- 第4位控制GPIO1_04的输出电平
- GPIO方向寄存器(GPIO1_GDIR) : 0x0209C004
- 控制GPIO1组引脚的方向(输入/输出)
- 设置第4位为1,将GPIO1_04配置为输出
3.3 电路连接分析
从原理图可以看出,RGB LED采用的是共阳极连接方式:
- LED的阳极连接到电源(VCC)
- LED的阴极通过限流电阻连接到MCU的GPIO引脚
- 当GPIO输出低电平时,LED点亮
- 当GPIO输出高电平时,LED熄灭
这就是为什么在驱动代码中:
if (write_data & 0x02){register_data = ioread32(led_green.virtual_DR);register_data &= ~(0x01 << 20);iowrite32(register_data, led_green.virtual_DR); // GPIO4_20引脚输出低电平,绿灯亮}else{register_data = ioread32(led_green.virtual_DR);register_data |= (0x01 << 20);iowrite32(register_data, led_green.virtual_DR); // GPIO4_20引脚输出高电平,绿灯灭}
四、引脚复用机制详解
i.MX6处理器的引脚复用是通过IOMUXC模块实现的。每个引脚可以配置为多种功能(ALT0~ALT7)。
4.1 引脚功能选择过程
register_data = ioread32(led_red.virtual_IOMUXC_SW_MUX_CTL_PAD);register_data &= ~(0xf << 0);// 清除低4位register_data |= (0x05 << 0);// 设置为ALT5模式iowrite32(register_data, led_red.virtual_IOMUXC_SW_MUX_CTL_PAD); //设置复用功能
值0x05表示选择ALT5功能,将CSI_VSYNC配置为GPIO1_04。
4.2 为什么要配置PAD属性
PAD属性配置影响引脚的电气特性:
register_data = (0x10B0);iowrite32(register_data, led_red.virtual_IOMUXC_SW_PAD_CTL_PAD); //设置PAD 属性
值0x10B0包含以下配置:
- 上拉/下拉选择
- 上拉/下拉强度
- 开漏输出使能/禁用
- 驱动强度
- 速率控制
- 迟滞比较器使能/禁用
这些配置确保GPIO引脚有正确的驱动能力和电气特性,使LED能够正常工作。
五、实验
5.1 添加设备树
5.2 编译设备树
5.3 替换设备树
5.4 编译驱动文件
5.5 加载驱动文件
5.6 往设备文件写入值(点灯!!!)
sudo sh -c "echo '3'>/dev/rgb_led"
总结
通过本文,我们详细解析了在i.MX6ULL平台上如何:
- 编写驱动程序控制RGB LED
- 配置设备树定义硬件资源
- 根据原理图理解硬件连接与设备树配置的关系
这种基于设备树的驱动开发方式具有良好的可移植性和可维护性,是现代嵌入式Linux开发的标准实践。通过理解从原理图到设备树再到驱动代码的全链路,可以更加深入地掌握嵌入式系统的软硬件协同工作原理
相关文章:
Linux驱动开发实战(四):设备树点RGB灯
Linux驱动开发实战(四):设备树点RGB灯 文章目录 Linux驱动开发实战(四):设备树点RGB灯前言一、驱动实现1.1 驱动设计思路1.2 关键数据结构1.3 字符设备操作函数1.4 平台驱动探测函数1.5 匹配表和平台驱动结…...
大模型架构记录5-向量数据库
一 倒排索引、KNN、PQ 1.1 基础版本 query -> requery 对问题做处理,处理上下文 对query 做 refined query 1.2 向量数据库 二 搜索逻辑 2.1 knn 2.2 近似KNN 先和N个空间的均值比较再和空间内部的所有点比较,计算最近值。 优化一: …...
【 Fail2ban 使用教程】
Fail2ban 使用教程 1. 安装 Fail2ban2. 配置 Fail2ban2.1 创建 jail.local 文件2.2 基本配置参数说明2.3 配置具体服务的监控规则2.3.1 SSH 服务2.3.2 Apache 服务 3. 启动和管理 Fail2ban3.1 启动 Fail2ban 服务3.2 设置 Fail2ban 开机自启3.3 检查 Fail2ban 服务状态3.4 重新…...
Django系列教程(8)——函数视图及通用类视图
目录 什么是视图(View)及其工作原理 接近现实的函数视图 更复杂的案例: 视图处理用户提交的数据 基于函数的视图和基于类的视图 Django通用类视图 a. ListView b. DetailView c. CreateView d. UpdateView e. FormView f. DeleteView 小结 Django的视图(view)是处理…...
【C#学习笔记04】C语言格式化输出
引言 printf()函数不仅可以将数据输出到控制台,还可以通过格式化字符串灵活地控制输出的格式。printf()函数的使用规则,包括标志说明、字段宽度、转换精度、长度修饰、转换说明、转义字符。 1. printf()函数概述 printf…...
九点标定和十二点标定的区别
九点标定和十二点标定是机器视觉中常用的两种手眼标定方法,用于建立图像坐标系与机械坐标系之间的映射关系。它们的核心区别在于标定点的数量、变换模型和适用场景。以下是详细对比: 1. 九点标定 特点 标定点数量:9 个点,通常排…...
qt+opengl 播放yuv视频
一、实现效果 二、pro文件 Qt widgets opengl 三、主要代码 #include "glwidget.h"GLWidget::GLWidget(QWidget *parent) : QOpenGLWidget(parent) {connect(&m_timer, &QTimer::timeout, this,[&](){this->update();});m_timer.start(1000/33); }v…...
【揭秘测绘艺术】从基础到法律,绘制地球的智慧蓝图
在人类探索与塑造世界的征途中,有一门古老而又现代的科学默默发挥着基石作用——测绘。它不仅仅是地图的绘制,更是对地球空间信息的精准捕捉与智慧应用。今天,让我们一起走进测绘的世界,解码“测绘”与“基础测绘”的内涵…...
基于DeepSeek×MWORKS 2025a的ROM Builder自动化降阶实战
一、引言 当前,工业仿真领域正经历着前所未有的「智能焦虑」——当自动驾驶算法已能理解城市路网,当大模型开始设计蛋白质结构,这个驱动大国重器研发的核心领域,却仍在与千万级方程组成的庞杂模型艰难博弈。传统仿真降阶如同在数…...
NetAssist 5.0.14网络助手基础使用及自动应答使用方案
以下是NetAssist v5.0.14自动应答功能的详细使用步骤: 一、基础准备: 工具下载网址页面:https://www.cmsoft.cn/resource/102.html 下载安装好后,根据需要可以创建多个server,双击程序图标运行即可,下面…...
MySQL中有哪几种锁?
大家好,我是锋哥。今天分享关于【MySQL中有哪几种锁?】面试题。希望对大家有帮助; MySQL中有哪几种锁? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在MySQL中,锁是用来控制并发访问的机制,确…...
vue2的webpack(vue.config.js) 怎么使用请求转发 devServer.proxy
首先用 express 搭建后端服务器,注意使用中间件解析json格式的请求体,才会获取到 post 参数 app.use(express.json()); app.js const express require(express) const app express() app.use(express.json()); const port 3000app.post(/api/vue2, …...
【开源+代码解读】Search-R1:基于强化学习的检索增强大语言模型框架3小时即可打造个人AI-search
大语言模型(LLMs)在处理复杂推理和实时信息检索时面临两大挑战:知识局限性(无法获取最新外部知识)和检索灵活性不足(传统方法依赖固定检索流程)。现有方法如检索增强生成(RAG)和工具调用(Tool-Use)存在以下问题: RAG:单轮检索导致上下文不足,无法适应多轮交互场景…...
CSS中固定定位
1.如何设置为固定定位? 给元素设置position: fixed 即可实现固定定位. 可以使用left, right, top ,bottom 四个属性调整位置 2.固定定位的参考点在哪里? 参考他的视口 视口-->对于PC浏览器来说,视口就是我们看网页的那扇"窗户". 3.固定定位元素的特点 1.脱离文档…...
Kotlin高效实现 Android ViewPager2 顶部导航:动态配置与性能优化指南
高效实现:强调代码的性能优化。Android ViewPager2:明确技术栈。顶部导航:核心功能点。动态配置与性能优化指南:突出动态配置的灵活性和性能优化的重点。 在 Android 开发中,使用 ViewPager2 实现高效的顶部导航&…...
MFCday01、模式对话框
对话框类和应用程序类。 MFC中 Combo Box List Box List Control三种列表控件,日期控件Date Time Picker...
C++ 布尔类型(bool)深度解析
引言 在 C 编程里,布尔类型(bool)是一种基础且极为关键的数据类型。它专门用于表达逻辑值,在程序的条件判断、循环控制等诸多方面都发挥着重要作用。接下来,我们将对 C 中的布尔类型展开全面且深入的探讨。 一、布尔…...
新鲜速递:OpenAI-Agents-Python:构建智能代理系统的轻量级框架
图片来自于官方README.md 一、什么是OpenAI Agents SDK? OpenAI Agents SDK是一个轻量级但功能强大的框架,专为构建多智能体工作流而设计。作为OpenAI之前实验项目Swarm的生产级升级版本,该SDK提供了极少但高效的抽象概念,使开发…...
单例模式的五种实现方式
1、饿汉式 ①实现:在类加载的时候就初始化实例 ②优点:线程安全 ③缺点:实例在类加载的时候创建,可能会浪费资源 //饿汉式 public class EagerSingleton{private EagerSingleton(){} //私有构造方法private static EagerSingle…...
行为模式---状态模式
概念 状态模式是一种行为模式,用于在内部状态改变的时候改变其行为。它的核心思想就是允许一个对象在其内部状态改变的时候改变它的行为。状态模式通过将对象的状态封装成独立的类,并将其行为委托给当前的状态对象,从而使得对象行为随着状态…...
统一 Elastic 向量数据库与 LLM 功能,实现智能查询
作者:来自 Elastic Sunile Manjee 利用 LLM 功能进行查询解析,并使用 Elasticsearch 搜索模板,将复杂的用户请求转换为结构化的、基于模式的搜索,从而实现高精度查询结果。 想象一下,你在搜索“距离 Belongil Beach 25…...
(Lauterbach调试器学习笔记)一、首次连接TriCore开发板调试
Lauterbach调试器学习笔记 文章目录 Lauterbach调试器学习笔记前言一、Lauterbach调试器介绍二、调试步骤三、常用代码四、不常用代码,但是很有意思总结 前言 第一篇简单记录一下Lauterbach调试器的使用过程,主要是想写第二篇python api。 一、Lauterba…...
HTML星球大冒险之路线图
第一章:欢迎来到 HTML 星球! 1.1 宇宙的基石:HTML 是什么? 🌍 比喻:HTML 是网页世界的「乐高积木」,用标签搭建一切可见内容🎯 目标:理解 HTML 的作用,掌握…...
网络安全与七层架构
网络安全与七层架构 随着互联网技术的迅猛发展,网络安全问题日益凸显。网络安全不仅影响到个人用户的信息安全,更是企业及国家安全的重要组成部分。而七层架构(OSI模型)为网络通信提供了理论支撑,能够有效地帮助我们理…...
2025-03-13 学习记录--C/C++-PTA 练习2-17 生成3的乘方表
合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。💪🏻 一、题目描述 ⭐️ 练习2-17 生成3的乘方表 输入一个非负整数n,生成一张3的乘方表,输出3^0~$$3^n$$的值…...
改进YOLOv8系列,AAAI 2025,多尺度特征提取自注意力模块,全局信息聚合,即插即用!分享
**论文:https://arxiv.org/pdf/2404.07846 **代码地址: https://github.com/nagejacob/TBSN/blob/main/network/tbsn.py 改进YOLOv8系列:多尺度特征提取自注意力模块,全局信息聚合,即插即用!分享 🚀论文研究概括🚀加入到网络中的理论研究🚀需要修改的代码1 🍀🍀…...
我又又又又又又更新了~~纯手工编写C++画图,有注释~~~
再再再次感谢Ttcofee提的问题 本次更新内容: 鼠标图案(切换),版本号获取,输入框复制剪切板 提前申明:如果运行不了,请到主页查看RedpandaDevc下载,若还是不行就卸了重装。 版本号&…...
Vue源码深度解析:从2.x到3.x的架构演进与核心原理剖析
Vue源码深度解析:从2.x到3.x的架构演进与核心原理剖析 一、框架演变:从Vue2到Vue3的跨越 1.1 革命性升级 Vue3的发布标志着前端框架进入新纪元,其核心改进体现在三个方面: 性能飞跃:包体积减少41%,初始…...
评委打分5个评委 去掉一个最高分和一个最低分 取平均分
一键替换max用min 按shiftF6 public static int getMin(int[]scores){int min scores[0];for (int i 0; i < scores.length; i) {if(scores[i]> min){min scores[i];}}return min;} 这里有和c/c不一样的知识点 c/c调用函数类似于java的方法,但是c/c的函数调用需要声明…...
javabean类(测试类之外的类)
altinsert快捷键生成构造方法和get、set方法 或者插件ptg(连接外网搜索插件并且下载)...
C++ 邻接矩阵(代码)
C邻接矩阵代码,见下: #include<iostream>using namespace std;#define inf -1 class Graph{ private:int vertices;int **edges;public:Graph(int vertices);~Graph();void addEdge(int u, int v, int w);void printGraph(); };Graph::Graph(int …...
Cookie与Session详解
Cookie简介 Cookie 是浏览器提供的持久化存储数据的一种机制。是指某些网站为了辨别用户身份、进行会话跟踪而储存在用户本地终端上的数据(通常经过加密)。以下是关于 Cookie 的详细介绍: Cookie工作原理 当你访问一个网站时,该网…...
OpenBMC:BmcWeb 处理http请求
OpenBMC:BmcWeb 读取http请求头-CSDN博客 介绍了,在读取完http头后,将调用Connection::handle处理http请求 1.Connection::handle void handle() {...req = std::make_shared<crow::Request>(parser->release(), reqEc);...req->session = userSession;accept …...
【算法题解答·六】栈队列堆
【算法题解答六】栈队列堆 接上文【算法方法总结六】栈队列堆的一些技巧和注意事项 栈队列堆相关题目如下: 232.用栈实现队列 简单 准备两个栈,一个负责入队的栈A,一个负责出队的栈B出队和返回队列开头元素,都要先进行以下操作…...
计算机视觉算法实战——手势识别(主页有源码)
✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ 1. 领域简介:手势识别的价值与挑战 手势识别是连接人类自然行为与数字世界的核心交互技术,在智能设备控制、…...
JobScheduler省电机制
1.前言 JobScheduler(任务调度器)是 Android 提供的一种任务调度机制,可以替代传统的 WakeLock 和 Alarm 来执行后台任务。那么,它们之间的区别是什么?JobScheduler 又有哪些特别之处呢? 1.1 WakeLock 和 …...
设计模式学习笔记——命令模式
2025年3月13日,周四下午 相同的保存逻辑在各个组件中重复出现。 且需要修改保存逻辑时,各个组件的保存逻辑都需要进行相应修改。 使用了命令模式把保存逻辑从三个组件中独立出来后,减少了代码冗余。 可以通过“保存命令”来使用保存逻辑&am…...
[TPCTF 2025] crypto 复现两题
周末很忙。比赛都没怎么看。晚上把密码复现两个。 randomized random 这题在小鸡块博客里见过,稍有区别。 # FROM python:3 import random with open("flag.txt","rb") as f:flagf.read() for i in range(2**64):print(random.getrandbits(3…...
电子元器件选型与实战应用—16 怎么选一个合适的MCU芯片?
文章目录 1. 选型要素1.1 价格1.2 技术支持1.3 厂家优势1.4 功耗1.5 特殊功能1.6 统计外设1.7 确定外设占用的内存和flash大小1.8 确定外设通信接口1.9 确定外设通信接口的电平1.10 确定外设的GPIO数量1.11 确定外设的供电和功耗1.12 确定外设GPIO的种类1.13 确定ADC的数量1.14…...
第6关:牛牛鱼缸-附加题
任务描述 本关任务:问题描述:牛牛有一个鱼缸,鱼缸里面已经有n条鱼,每条鱼的大小为fishSizei,牛牛现在想把新捕捉的鱼放入鱼缸。鱼缸里存在着大鱼吃小鱼的定律。经过观察,牛牛发现一条鱼A的大小为另外一条鱼…...
go中间件学习
本博文源于笔者正在学习go中间件,罗列了较为常用的中间件,例如日志记录、认证授权、跨域资源共享、请求体解析、静态文件处理、错误处理、性能分析、速率限制、session 1、日志记录中间件 可以追加打印用,例如,将请求进行打印 …...
若依RuoYi-Cloud-Plus微服务版(完整版)前后端部署
一.目标 在浏览器上成功登录进入 二.源码下载 后端源码:前往Gitee下载页面(https://gitee.com/dromara/RuoYi-Cloud-Plus)下载解压到工作目录。 前端源码: 前往Gitee下载页面(https://gitee.com/JavaLionLi/plus-ui)下载解压到工作目录。 文档地址&a…...
航空电动力系统适航标准要点手册
航空电动力系统适航标准要点手册 1.标准制定背景与必要性1.1 为什么需要制定和遵循标准?1.2 标准制定依据与发布机构 2.关键核心标准概述2.1 电动航空与电推进系统2.2 混合动力系统2.3 硬件与通用要求 3.标准详细解读与应用场景3.1 DO-160G:环境适应性测…...
深入理解JavaScript构造函数与原型链:从原理到最佳实践
一、开篇:为什么需要理解原型链? 在JavaScript开发中,90%以上的"诡异"bug都与原型链机制相关。理解构造函数与原型链的运行原理,不仅能帮助我们写出更优雅的代码,还能在框架源码阅读、性能优化等场景中游刃…...
java每日精进 3.12 【WebSocket进阶】
基于 SpringWebSocket 进行二次封装,实现了更加简单的使用方式。例如说,WebSocket 的认证、Session 的管理、WebSocket 集群的消息广播等等。 1. 用户认证与登录用户信息传递 1.1 Token 过滤器 (TokenAuthenticationFilter) ① 在 WebSocket 连接建立…...
国家网络安全事件应急预案
目 录 1 总则 1.1 编制目的 1.2 编制依据 1.3 适用范围 1.4 事件分级 1.5 工作原则 2 组织机构与职责 2.1 领导机构与职责 2.2 办事机构与职责 2.3 各部门职责 2.4 各省(区、市)职责 3 监测与预警 3.1 预警分级 3.2 预警监测 3.3 预警研判…...
Markdown:Mermaid 画图
目录 安装基本语法流程图时序图甘特图总结 Mermaid 是一款用于生成流程图、时序图、甘特图等图表的 JavaScript 库。它可以将简单的文本描述转化为美观的图表,方便开发者进行可视化展示。 安装 Mermaid 可以直接在浏览器中使用,也可以在 Node.js 环境中…...
【视频】ffmpeg、Nginx搭建RTMP、HLS服务器
1、源码安装Nginx 1)源码下载 因为要使用Nginx的模块nginx-rtmp-module,所以要下载 nginx 和 nginx-rtmp-module 的源码。 下载地址: http://nginx.org/en/download.html https://github.com/arut/nginx-rtmp-module/tags2)解压、配置 在同一个目录中解压 nginx 和 nginx…...
时间有限,如何精确设计测试用例?5种关键方法
精确设计测试用例能够迅速识别并修复主要缺陷,确保产品质量,降低后期维护成本,并通过专注于核心功能来提升用户体验,为项目的成功奠定坚实基础。若未能精确设计测试用例,可能会导致关键功能测试不充分,使得…...
【算法】图论
⭐️个人主页:小羊 ⭐️所属专栏:Linux 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 持续更新中...1、DFS2、BFSN 叉树的层序遍历二叉树的锯齿形层序遍历二叉树最大宽度 3、多源BFS腐烂的苹果 4、拓扑排序 持续更新中…...