Linux 驱动开发基础知识——总线设备驱动模型(八)

 个人名片:

🦁作者简介:学生
🐯个人主页:妄北y

🐧个人QQ:2061314755

🐻个人邮箱:2061314755@qq.com
🦉个人WeChat:Vir2021GKBS
🐼本文由妄北y原创,首发CSDN🎊🎊🎊
🐨座右铭:大多数人想要改造这个世界,但却罕有人想改造自己。

专栏导航:

妄北y系列专栏导航:

C/C++的基础算法:C/C++是一种常用的编程语言,可以用于实现各种算法,这里我们对一些基础算法进行了详细的介绍与分享。🎇🎇🎇

QT基础入门学习:对QT的基础图形化页面设计进行了一个简单的学习与认识,利用QT的基础知识进行了翻金币小游戏的制作🤹🤹🤹

Linux基础编程:初步认识什么是Linux,为什么学Linux,安装环境,进行基础命令的学习,入门级的shell编程。🍻🍻🍻

Linux应用开发基础开发:分享Linux的基本概念、命令行操作、文件系统、用户和权限管理等,网络编程相关知识,TCP/IP 协议、套接字(Socket)编程等,可以实现网络通信功能。💐💐💐

Linux项目开发:Linux基础知识的实践,做项目是最锻炼能力的一个学习方法,这里我们会学习到一些简单基础的项目开发与应用,而且都是毕业设计级别的哦。🤸🤸🤸


非常期待和您一起在这个小小的互联网世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨ 

文章介绍:

🎉本篇文章对Linux驱动基础学习的相关知识进行分享!🥳🥳🥳

Linux驱动程序 = 驱动框架 + 硬件操作 = 驱动框架 + 单片机,我们需要掌握别人的驱动框架,了解框架的思想,才能更好的去修改和运用别人的框架

如果您觉得文章不错,期待你的一键三连哦,你的鼓励是我创作动力的源泉,让我们一起加油,一起奔跑,让我们顶峰相见!!!💪💪💪

🎁感谢大家点赞👍收藏⭐评论✍️

目录: 

目录

一、LED 模板驱动程序的改造

1.1 原来的框架

1.2 要实现的框架 

二、代码分析:

2.1 board_A_led.c

2.2 chip_demo_gpio.c 

2.3 leddrv.c

三、注意事项

3.1  release 函数

3.2 EXPORT_SYMBOL

四、上机测试

4.1 编译

4.2 挂载到开发板 


一、LED 模板驱动程序的改造

1.1 原来的框架

1.2 要实现的框架 

二、代码分析:

2.1 board_A_led.c

        平台设备文件


#include <linux/module.h>#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>#include "led_resource.h"static void led_dev_release(struct device *dev)
{
}static struct resource resources[] = {{.start = GROUP_PIN(3,1),.flags = IORESOURCE_IRQ,.name = "100ask_led_pin",},{.start = GROUP_PIN(5,8),.flags = IORESOURCE_IRQ,.name = "100ask_led_pin",},
};static struct platform_device board_A_led_dev = {.name = "100ask_led",.num_resources = ARRAY_SIZE(resources),.resource = resources,.dev = {.release = led_dev_release,},
};static int __init led_dev_init(void)
{int err;err = platform_device_register(&board_A_led_dev);   return 0;
}static void __exit led_dev_exit(void)
{platform_device_unregister(&board_A_led_dev);
}module_init(led_dev_init);
module_exit(led_dev_exit);MODULE_LICENSE("GPL");

第27~38行:

static struct resource resources[] = {

如果我们再想增加一盏灯的话,我们可以在这里的平台设备在这里的资源再增加一盏灯

    

  .start = GROUP_PIN(3,1),

指定第3组里面的第1个引脚

第41~48行:

static struct platform_device board_A_led_dev = {

注册一个board_A_led_dev

 将上面代码资源数组中的资源添加到platform_device

 .name = "100ask_led":平台设备的名字,与chip_demo_gpio_driver进行匹配

 .num_resources = ARRAY_SIZE(resources):资源的个数

 .resource = resources:指向这个数组

第50~62行:

board_A.c 作为一个可加载模块,里面也有入口函数、出口函数。

static int __init led_dev_init(void)
static void __exit led_dev_exit(void)

设置注册好board_A_led_dev的入口函数和出口函数

 第64~67行:

module_init(led_dev_init);
module_exit(led_dev_exit);

修饰入口函数和出口函数

MODULE_LICENSE("GPL");

确定GPL协议

第50~57行:

        在入口函数中注册 platform_device 结构体,在 platform_device 结构体中指定使用哪个 GPIO 引脚。

static int __init led_dev_init(void)
{int err;err = platform_device_register(&board_A_led_dev);   return 0;
}

第23~48行:board_A_led_dev 结构体定义如下:

static void led_dev_release(struct device *dev)
{
}static struct resource resources[] = {{.start = GROUP_PIN(3,1),.flags = IORESOURCE_IRQ,.name = "100ask_led_pin",},{.start = GROUP_PIN(5,8),.flags = IORESOURCE_IRQ,.name = "100ask_led_pin",},
};static struct platform_device board_A_led_dev = {.name = "100ask_led",.num_resources = ARRAY_SIZE(resources),.resource = resources,.dev = {.release = led_dev_release,},
};

        在 resouces 数组中指定了 2 个引脚(第 27~38 行); 我们还提供了一个空函数         led_dev_release(第 23~25 行),它被赋给 board_A_led_dev 结构体(第 46 行),这个函数在卸载 platform_device 时会 被调用,如果不提供的话内核会打印警告信息。

第27~38行:

static struct resource resources[] = {

定义资源数组

 

2.2 chip_demo_gpio.c 

#include <linux/module.h>#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>#include "led_opr.h"
#include "leddrv.h"
#include "led_resource.h"static int g_ledpins[100];
static int g_ledcnt = 0;static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */       
{   //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);printk("init gpio: group %d, pin %d\n", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));switch(GROUP(g_ledpins[which])){case 0:{printk("init pin of group 0 ...\n");break;}case 1:{printk("init pin of group 1 ...\n");break;}case 2:{printk("init pin of group 2 ...\n");break;}case 3:{printk("init pin of group 3 ...\n");break;}}return 0;
}static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
{//printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));switch(GROUP(g_ledpins[which])){case 0:{printk("set pin of group 0 ...\n");break;}case 1:{printk("set pin of group 1 ...\n");break;}case 2:{printk("set pin of group 2 ...\n");break;}case 3:{printk("set pin of group 3 ...\n");break;}}return 0;
}static struct led_operations board_demo_led_opr = {.init = board_demo_led_init,.ctl  = board_demo_led_ctl,
};struct led_operations *get_board_led_opr(void)
{return &board_demo_led_opr;
}static int chip_demo_gpio_probe(struct platform_device *pdev)
{struct resource *res;int i = 0;while (1){res = platform_get_resource(pdev, IORESOURCE_IRQ, i++);if (!res)break;g_ledpins[g_ledcnt] = res->start;led_class_create_device(g_ledcnt);g_ledcnt++;}return 0;}static int chip_demo_gpio_remove(struct platform_device *pdev)
{struct resource *res;int i = 0;while (1){res = platform_get_resource(pdev, IORESOURCE_IRQ, i);if (!res)break;led_class_destroy_device(i);i++;g_ledcnt--;}return 0;
}static struct platform_driver chip_demo_gpio_driver = {.probe      = chip_demo_gpio_probe,.remove     = chip_demo_gpio_remove,.driver     = {.name   = "100ask_led",},
};static int __init chip_demo_gpio_drv_init(void)
{int err;err = platform_driver_register(&chip_demo_gpio_driver); register_led_operations(&board_demo_led_opr);return 0;
}static void __exit lchip_demo_gpio_drv_exit(void)
{platform_driver_unregister(&chip_demo_gpio_driver);
}module_init(chip_demo_gpio_drv_init);
module_exit(lchip_demo_gpio_drv_exit);MODULE_LICENSE("GPL");

 第138~144行:

chip_demo_gpio.c 中注册 platform_driver 结构体 , 它使用Bus/Dev/Drv 模型,当有匹配的 platform_device 时,它的 probe 函数就会被调用。 

在 probe 函数中所做的事情跟之前的代码没有差别。

138 static struct platform_driver chip_demo_gpio_driver = {
139 .probe = chip_demo_gpio_probe,
140 .remove = chip_demo_gpio_remove,
141 .driver = {
142 .name = "100ask_led",
143 },
144 };
145
146 static int __init chip_demo_gpio_drv_init(void)
147 {
148 int err;
149
150 err = platform_driver_register(&chip_demo_gpio_driver);
151 register_led_operations(&board_demo_led_opr);
152
153 return 0;
154 }

注册一个chip_demo_gpio_driver

.driver  = {.name   = "100ask_led",},

设备名称,与board_A_led_dev中设备名称进行对应

.probe      = chip_demo_gpio_probe:记录引脚

.remove     = chip_demo_gpio_remove:销毁设备

         第 150 行:向内核注册一个 platform_driver 结构体,这个结构体的核心在于第 100 行的 chip_demo_gpio_probe 函数。 chip_demo_gpio_probe 函数代码如下:

100 static int chip_demo_gpio_probe(struct platform_device *pdev)
101 {
102 struct resource *res;
103 int i = 0;
104
105 while (1)
106 {
107 res = platform_get_resource(pdev, IORESOURCE_IRQ, i++);
108 if (!res)
109 break;
110
111 g_ledpins[g_ledcnt] = res->start;
112 led_class_create_device(g_ledcnt);
113 g_ledcnt++;
114 }
115 return 0;
116
117 }

        第 107 行:从匹配的 platform_device 中获取资源,确定 GPIO 引脚。

        第 111 行:把引脚记录下来,在操作硬件时要用。

        第 112 行:新发现了一个 GPIO 引脚,就调用上层驱动的代码创建设备节点

第146~159行:

static int __init chip_demo_gpio_drv_init(void)
static void __exit lchip_demo_gpio_drv_exit(void)

设置注册好chip_demo_gpio_driver的入口函数和出口函数

 第64~67行:

module_init(chip_demo_gpio_drv_init);
module_exit(lchip_demo_gpio_drv_exit);

修饰入口函数和出口函数

MODULE_LICENSE("GPL");

确定GPL协议

第100~117行:

static int chip_demo_gpio_probe(struct platform_device *pdev)

board_A_led_dev提供 .probe 

        第105~144行:从资源里确定引脚

                第107行:获得设备pdev中的第i个IORESOURCE_IRQ资源

                第111行:记录引脚

                第112行:创建device

第119~135行:

static int chip_demo_gpio_remove(struct platform_device *pdev)

board_A_led_dev提供 .remove

        第126行:销毁设备pdev中的第i个IORESOURCE_IRQ资源

操作硬件的代码如下,第 31、63 行的代码里用到了数组 g_ledpins,里面的值来自 platform_device,在 probe 函数中根据 platform_device 的资源确定了引脚:

static int g_ledpins[100];
static int g_ledcnt = 0;static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */       
{   //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);printk("init gpio: group %d, pin %d\n", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));switch(GROUP(g_ledpins[which])){case 0:{printk("init pin of group 0 ...\n");break;}case 1:{printk("init pin of group 1 ...\n");break;}case 2:{printk("init pin of group 2 ...\n");break;}case 3:{printk("init pin of group 3 ...\n");break;}}return 0;
}static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
{//printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));switch(GROUP(g_ledpins[which])){case 0:{printk("set pin of group 0 ...\n");break;}case 1:{printk("set pin of group 1 ...\n");break;}case 2:{printk("set pin of group 2 ...\n");break;}case 3:{printk("set pin of group 3 ...\n");break;}}return 0;
}static struct led_operations board_demo_led_opr = {.init = board_demo_led_init,.ctl  = board_demo_led_ctl,
};struct led_operations *get_board_led_opr(void)
{return &board_demo_led_opr;
}

第30和61行: 打印出想操作的引脚

第32和63行:判断引脚

第151行:

register_led_operations(&board_demo_led_opr);

 底层向上层调用

2.3 leddrv.c

#include <linux/module.h>#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>#include "led_opr.h"/* 1. 确定主设备号                                                                 */
static int major = 0;
static struct class *led_class;
struct led_operations *p_led_opr;#define MIN(a, b) (a < b ? a : b)void led_class_create_device(int minor)
{device_create(led_class, NULL, MKDEV(major, minor), NULL, "100ask_led%d", minor); /* /dev/100ask_led0,1,... */
}
void led_class_destroy_device(int minor)
{device_destroy(led_class, MKDEV(major, minor));
}
void register_led_operations(struct led_operations *opr)
{p_led_opr = opr;
}EXPORT_SYMBOL(led_class_create_device);
EXPORT_SYMBOL(led_class_destroy_device);
EXPORT_SYMBOL(register_led_operations);/* 3. 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}/* write(fd, &val, 1); */
static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{int err;char status;struct inode *inode = file_inode(file);int minor = iminor(inode);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);err = copy_from_user(&status, buf, 1);/* 根据次设备号和status控制LED */p_led_opr->ctl(minor, status);return 1;
}static int led_drv_open (struct inode *node, struct file *file)
{int minor = iminor(node);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);/* 根据次设备号初始化LED */p_led_opr->init(minor);return 0;
}static int led_drv_close (struct inode *node, struct file *file)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}/* 2. 定义自己的file_operations结构体                                              */
static struct file_operations led_drv = {.owner	 = THIS_MODULE,.open    = led_drv_open,.read    = led_drv_read,.write   = led_drv_write,.release = led_drv_close,
};/* 4. 把file_operations结构体告诉内核:注册驱动程序                                */
/* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
static int __init led_init(void)
{int err;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);major = register_chrdev(0, "100ask_led", &led_drv);  /* /dev/led */led_class = class_create(THIS_MODULE, "100ask_led_class");err = PTR_ERR(led_class);if (IS_ERR(led_class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "led");return -1;}return 0;
}/* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数           */
static void __exit led_exit(void)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);class_destroy(led_class);unregister_chrdev(major, "100ask_led");
}/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL");

 第30~33行:创建设备

       

void led_class_create_device(int minor)
EXPORT_SYMBOL(led_class_create_device);

产生依赖只有使用led_class_create_device才能产生led_class_create_device

第34~37行:销毁设备

void led_class_destroy_device(int minor)
EXPORT_SYMBOL(led_class_destroy_device);

产生依赖只有使用(led_class_destroy_device才能产生led_class_destroy_device

第38~41行:底层向上层注册函数

void register_led_operations(struct led_operations *opr)
EXPORT_SYMBOL(register_led_operations);

产生依赖只有底层调用才能产生register_led_operations

三、注意事项

3.1  release 函数

        如果 platform_device 中不提供 release 函数,如下图所示不提供红框部分的函数:

        则在调用 platform_device_unregister 时会出现警告,如下图所示:

        你可以提供一个 release 函数,如果实在无事可做,把这函数写为空。 

3.2 EXPORT_SYMBOL

        a.c 编译为 a.ko,里面定义了 func_a;如果它想让 b.ko 使用该函数,那么 a.c 里需要导出此函数(如果 a.c, b.c 都编进内核,则无需导出):

EXPORT_SYMBOL(led_device_create);

        并且,使用时要先加载 a.ko。如果先加载 b.ko,会有类似如下“Unknown symbol”的提示:

 

四、上机测试

4.1 编译

编译程序,把代码上传代服务器后执行 make 命令。

4.2 挂载到开发板 

在开发板上挂载 NFS 

[root@100ask:/mnt]# insmod board_A_led.ko
[root@100ask:/mnt]# insmod  leddrv.ko
[root@100ask:/mnt]# insmod chip_demo_gpio.ko
[root@100ask:/mnt]# ls /dev/100ask_led*
[root@100ask:/mnt]# ./ledtest /dev/100ask_led0 on
[root@100ask:/mnt]# ./ledtest /dev/100ask_led0 off

 

大佬觉得有用的话点个赞 👍🏻 呗。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

🔥🔥🔥任务在无形中完成,价值在无形中升华,让我们一起加油吧!🌙🌙🌙

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/660438.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

动网格-尺寸函数耦合运动(五)

尺寸函数 **尺寸函数(Size Function)**通常和局部体网格重构结合使用&#xff0c;尺寸函数用于控制重构过程中的网格分布。简单地说&#xff0c;尺寸函数的功能就是在运动边界处约束网格&#xff0c;使其维持在一个较小的尺度&#xff0c;在远离运动边界处&#xff0c;逐步将其…

Windows存储空间不足局域网文件共享 Dism备份系统空间不足

问题情景 在日常使用中难免遇到Windows的空间不足的情况&#xff0c;常用办法是清理垃圾释放空间&#xff0c;部分场景例如我们需要使用Dism备份完整系统&#xff0c;所以需要非常大的存储空间不够&#xff0c;如果空间不够什么才是最有效的方案呢&#xff1f; 我们假设身边没有…

如何使用docker部署Swagger Editor并实现无公网ip远程协作编辑文档

文章目录 Swagger Editor本地接口文档公网远程访问1. 部署Swagger Editor2. Linux安装Cpolar3. 配置Swagger Editor公网地址4. 远程访问Swagger Editor5. 固定Swagger Editor公网地址 Swagger Editor本地接口文档公网远程访问 Swagger Editor是一个用于编写OpenAPI规范的开源编…

【方案】TSINGSEE青犀智能分析网关V4+EasyCVR智慧服务区一体化监控平台

随着年关将近&#xff0c;春运大潮已然开启&#xff0c;届时又伴随着大雨暴雪天气&#xff0c;高速路况的新闻层出不穷。由于长期驾车且高速拥堵严重&#xff0c;不少人就聚集在服务区休息&#xff0c;导致服务区流量爆满&#xff0c;空前的拥堵极易导致服务区瘫痪。如何利用智…

计算机毕业设计 | springboot 多功能商城 购物网站(附源码)

1&#xff0c; 概述 国家大力推进信息化建设的大背景下&#xff0c;城市网络基础设施和信息化应用水平得到了极大的提高和提高。特别是在经济发达的沿海地区&#xff0c;商业和服务业也比较发达&#xff0c;公众接受新事物的能力和消费水平也比较高。开展商贸流通产业的信息化…

OpenHarmony—编辑器使用技巧

DevEco Studio支持使用多种语言进行应用/服务的开发&#xff0c;包括ArkTS、JS和C/C。在编写应用/服务阶段&#xff0c;可以通过掌握代码编写的各种常用技巧&#xff0c;来提升编码效率。 代码高亮 支持对代码关键字、运算符、字符串、类、标识符、注释等进行高亮显示&#x…

少儿编程教育市场分析:行业规模有望在2025年达到约500亿元

少儿编程教育是通过编程游戏启蒙、可视化图形编程等课程&#xff0c;培养学生的计算思维和创新解难能力的课程。与成人的编程不同&#xff0c;少儿编程教育并非高等教育那样学习如何写代码、编制应用程序&#xff0c;而是通过编程游戏启蒙、可视化图形编程等课程&#xff0c;培…

C语言——标准输入函数(scanf、getchar和gets)

目录 1. 标准输入输出头文件2. scanf2.1 scanf2.1.1 函数申明2.1.2 基本用法2.1.3 返回值2.1.4 占位符2.1.5 赋值忽略符 3. getchar3.1 函数申明3.2 基本用法 4. gets4.1 函数申明4.2 基本用法 1. 标准输入输出头文件 #include <stdio.h>在使用标准输入输出函数的时候都…

摄影分享|基于Springboot的摄影分享网站设计与实现(源码+数据库+文档)

摄影分享网站目录 目录 基于Springboot的摄影分享网站设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、图片素材管理 3、视频素材管理 4、公告信息管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐…

企业网络基础架构监控工具

IT 基础架构已成为提供基本业务服务的基石&#xff0c;无论是内部管理操作还是为客户托管的应用程序服务&#xff0c;监控 IT 基础设施至关重要&#xff0c;并且已经建立起来&#xff0c;SMB IT 基础架构需要简单的网络监控工具来监控性能和报告问题。通常&#xff0c;几个 IT …

UE5 虚幻游戏报错常用解决方法(幻兽帕鲁UE5报错)

在体验使用虚幻引擎5、4&#xff08;UE5/UE4&#xff09;开发的游戏如《幻兽帕鲁》时&#xff0c;玩家可能会遇到各种报错情况&#xff0c;例如黑屏、闪退、C运行时错误等。本博客将汇集一系列有效解决方案&#xff0c;通过调整虚幻引擎内置命令行参数以及优化系统环境&#xf…

区块链游戏解说:Sunflower Land 是什么

数据源&#xff1a;Sunflower Land Dashboard 作者&#xff1a;lesleyfootprint.network 什么是 Sunflower Land Sunflower Land 是基于 Polygon 网络的区块链农场游戏。玩家可以在一个充满活力和身临其境的环境中耕种、收获和交易各种农产品。Sunflower Land 使用了非同质…

Springboot 整合 Quartz(定时任务框架)

一、java 定时任务调度的实现方式 1、Timer 特点是&#xff1a;简单易用&#xff0c;但由于所有任务都是由同一个线程来调度&#xff0c;因此所有任务都是串行执行的&#xff0c;同一时间只能有一个任务在执行&#xff0c;前一个任务的延迟或异常都将会影响到之后的任务&#…

STM32存储左右互搏 QSPI总线读写FLASH W25QXX

STM32存储左右互搏 QSPI总线读写FLASH W25QXX FLASH是常用的一种非易失存储单元&#xff0c;W25QXX系列Flash有不同容量的型号&#xff0c;如W25Q64的容量为64Mbit&#xff0c;也就是8MByte。这里介绍STM32CUBEIDE开发平台HAL库Qual SPI总线操作W25Q各型号FLASH的例程。 W25Q…

【通讯录案例-沙盒路径 Objective-C语言】

一、接下来,我们来学习“存储”的相关的一些东西, 1.打开这个“数据存储“的ppt, 打开这个ppt, 首先呢,关于存储这一块儿, 存储呢,首先,有常见的几种方式,注意啊,这个里边儿是“方式”,方式,什么意思,是表示怎么去存,有五种方式: 1)XML属性列表(plist)归档:…

【数据结构】(三)树Tree

目录 1、基本概念 2、二叉树Binary Tree 3、树、森林与二叉树的转换 4、赫夫曼树Huffman Tree与赫夫曼编码Huffman Coding 1、基本概念 &#xff08;1&#xff09;树&#xff08;Tree&#xff09;是 n&#xff08;n ≥\geq 1&#xff09;个节点的有限集&#xff0c;n 0时称…

记elasticsearch CPU负载100%问题

记elasticsearch CPU负载100%问题 环境&#xff1a;问题表现&#xff1a;初步排查&#xff1a;日志查询hot_thread 深入查询当前elasticsearch正在运行的Task查看Task详情解决问题对导致问题的原因的几个猜测问题复现&#xff1a;导致问题的原因。json导入规则问题json导入规则…

Linux系统安全之iptables防火墙

目录 一、iptables防火墙的基本介绍 1、netfile与iptables的关系 1.1netfile 1.2iptables 1.3iptables是基于内核的防火墙&#xff0c;其中内置了raw&#xff0c;mangle&#xff0c;nat和filter四个规则表 2、iptables防火墙默认规则表&#xff0c;链结构 二、iptables的…

HashSet 的基本操作【集合容器知识回顾 ④】

HashSet 是 Java 中的一个集合类&#xff0c;它实现了 Set 接口。Set 是一种不允许包含重复元素的集合&#xff0c;而 HashSet 则是 Set 接口的一个具体实现。因此&#xff0c;HashSet 用于存储一组唯一的元素&#xff0c;不允许重复。 HashSet 的一些特点&#xff1a; 不允许…

漏洞03-CSRF漏洞

CSRF漏洞 文章目录 CSRF CSRF