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

【Linux驱动】设备树模型的LED驱动 | 查询方式的按键驱动

🐱作者:一只大喵咪1201
🐱专栏:《Linux驱动》
🔥格言:你只管努力,剩下的交给时间!
图

目录

  • 🍮设备树模型的LED驱动
    • 🍩设备树文件
    • 🍩驱动程序
  • 🍮应用层读取按键值
    • 🍩查询方式
    • 🍩休眠唤醒方式
    • 🍩poll方式
    • 🍩异步通知方式
  • 🍮查询方式实现按键驱动
      • 编程
  • 🍮总结

🍮设备树模型的LED驱动

目前有三种方式来写LED驱动程序:

  • 最简单的驱动模型——硬件操作绑定在驱动函数中。
  • 总线驱动模型。
  • 设备树驱动模型。

下面设备树驱动模型来实现一下LED驱动程序,该模型主要分为两部分,设备树文件和驱动程序。

🍩设备树文件

图
如上图所示设备树文件,在设备树中增加Big-Miaomi-LED@0Big-Miaomi-LED@1两个设备节点:

  • compatible属性:属性值都是BigMiaomi,LED_Driver

  • pin属性:属性值是各自节点所用GPIO组和引脚编号组成的32位整数。

  • 如果在设备树节点里使用reg属性,内核在生成对应的platform_device时,reg属性会被转换成IORESOURCE_MEM类型的资源。

  • 如果在设备树节点里使用interrputs属性,内核在生成对应的platform_device时,interrupts属性会被转换成IORESOURCE_IRQ类型的资源。

但是本喵写的Big-Miaomi-LED节点中,属性名是pin,该属性名是本喵自己定义的,不在内核自动转换资源类型的的命名范围内。

所以就不能从转换后的platform_device结构体中的resources数组中获得引脚资源了,具体获取方式编程时候再说。

图
如上图,然后在内核目录中使用make dtbs指令编译设备树文件,转换为内核认识的dtb文件。

🍩驱动程序

驱动程序在总线驱动模型的基础上进行修改,驱动层的上层不用动,只需要改变下层中的部分代码:

tu
如上图所示,由于现在支持了设备树,所以需要初始化platform_deiver结构体中driver成员里的of_match_table成员,这是一个struct of_device_id类型的数组。

所以需要定义一个struct of_device_id类型的数组,名为BigMiaomi_LEDs

  • 只用platform_deviceplatform_driver匹配规则中优先级最高的compatible属性来匹配。
  • 只支持LED设备,所以compatible属性只有一个值。

compatible属性的值,必须和设备树中要支持节点的compatible属性值相同,才能匹配成功

然后就是在匹配成功以后,会自动调用paltform_driver中的probe函数,在该函数中,原本是从paltform_deviceresources数组中获取硬件资源,但是此时不能这样干了:

tu
如上图所示probe函数,在该函数中首先要获取pin资源:

  • 设备树中的pin属性没有被转换到resources数组中,但是在第一次转换为device_node里的properties中是有该属性的。
    • 从匹配成功的platform_device中得到当前节点的device_node结构体指针of_node
  • 使用of_property_read_32函数,从np指向的当前节点deivce_node中的properties里找到pin属性,并且以32位整数的方式读取该属性的value值。
    • 将表示引脚资源的32位属性值放入到记录引脚资源的全局数组g_ledpins中。

获取到引脚资源后的其他操作和总线模型中相同,也是要使用led_class_create_device/dev目录下创建设备节点。

  • 设备树文件中的设备节点,内核加载后并不会在/dev目录下创建相应的文件,它不属于文件字符设备文件系统。

图
如上图代码所示,既然probe中的获取引脚资源的方式变了,那么在remove中获取引脚资源的方式和其他处理也要做出相应变化:

  • 从要移除设备节点的device_node中获取引脚资源led_pin
  • 遍历存放引脚资源的全局数组找到要移除的节点,移除后将对应的值修改为-1。
  • 最后判断一下是否该类型的设备节点全部移除了,如果存放引脚资源的全局数组中,所有值都成了-1,则说明全部移除了。

此时整个驱动程序就修改完毕了,相比于总线驱动模型,只是在获取引脚资源的方式上做了改变。

图
如上图所示Makfile文件,只需要编译驱动层上层led_drv.c和下层chip_led_opr.c即可,board_A.c不用再参与编译了。

  • 因为引脚资源不再由board_A.c中的platform_device结构体提供了。
  • 引脚资源由设备树文件提供,由内核将设备节点转换为platform_device结构体。

图
如上图所示,将在Linux服务器中编译好的dtb设备树文件和led_drv.kochip_led_opr.ko驱动文件,还有led_drv_test测试文件拷贝到网络根文件系统中。

在开发板上将dtb设备树文件拷贝到/boot目录下,然后重启开发板.

图

如上图所示,在/sys/firmware/devicetree/base/路径下,存在Big-Miaomi-LED@0Big-Miaomi-LED@1两个设备节点,这是我们在设备树文件中添加的两个节点,此时加载到了内核中。然后使用insmod led_drv.koinsmod chip_led_opr.ko安装驱动程序。

图

如上图所示,此时执行测试程序,在命令行中输入./led_drv_test /dev/BigMiaomi_LED0 on,内核打印信息现实操作了GPIO3_1

🍮应用层读取按键值

应用层读取按键值有4种方式:

  • 查询方式
  • 休眠-唤醒方式
  • poll方式
  • 异步通知方式

无论使用哪个方式都需要有按键驱动程序,通过这四种方式可以掌握一些驱动的基本技能:中断、休眠、唤醒、poll等机制

这些基本技能是驱动开发的基础,其他大型驱动复杂的地方是它的框架及设计思想,但是基本技能就只有这些。

🍩查询方式

图
如上图所示查询方式的驱动模型,这种方式最简单,这里并不考虑驱动层中的架构,只看驱动层所做的工作。

在驱动程序中构造并注册一个file_operations结构体,里面提供对应的drv_opendrv_read函数,当应用层调用open系统调用时,在驱动层的drv_open函数中配置相应的引脚为输入引脚。

当应用层调用read系统调用时,在驱动层的drv_read函数中读取该GPIO引脚的寄存器,把引脚的状态返回给应用层。

  • 读取引脚状态时,直接返回寄存器中的值,没有其他多余的动作。

🍩休眠唤醒方式

图

如上图所示休眠唤醒方式的驱动模型,在驱动层中的drv_open函数中,除了要把GPIO设置为输入引脚,还有注册GPIO的中断处理函数

当应用层调用read系统调用时,在驱动层的drv_read驱动函数中:

  1. 如果有按键数据,则直接返回给应用层。
  2. 如果没有按键数据,则应用层的APP在内核态休眠。

当用户按下按键时,GPIO中断被触发,导致drv_open中注册的中断服务程序被执行,在中断服务程序中:

  1. 记录按键数据。
  2. 唤醒休眠中的应用层APP。

应用层的APP被唤醒以后,继续在内核态运行,即执行驱动层代码,把中断服务程序中记录的按键数据返回给应用层的APP。

  • 没有读取到数据时,就会休眠,直到有按键数据到来才被唤醒。

🍩poll方式

上面的休眠-唤醒方式存在一个缺点:如果用户一直没有按下按键,那么应用层的APP就永远休眠阻塞不再执行了,所以可以给APP定个闹钟,这就是poll方式:

图

如上图所示poll驱动模型,poll是应用层实现多路转接的系统调用接口,在驱动层的file_operations结构体中,同样有一个poll函数指针:

tu
如上图所示file_operations结构体的定义,所以当应用层的APP调用poll系统调用时,会调用到驱动层该结构体中poll函数指针指向的函数。

所以需要我们在驱动层去定义poll函数指针指向的函数,使得整个驱动层符合poll驱动模型。驱动层总体步骤为:

  • 注册file_operations结构体,里面提供openreadpoll等驱动层的函数。
  • 应用层APP调用open时,驱动层的drv_open会将GPIO设置为输入引脚,并且注册中断处理函数。
  • 应用层APP调用poll/select时,意图是查询按键数据是否就绪,并且可以指定一个超时时间:
    • 当按键数据就绪时,驱动层的poll向应用层返回就绪状态,APP继续使用read读取按键数据。
    • 当按键数据没有就绪时,驱动层的poll就会在内核态休眠一段时间。

当APP被唤醒时,有两种情况:

  1. 在休眠期间,硬件按键被按下,按键数据就绪。
  2. 超时时间到了,硬件按键仍然没有按下,按键数据没有就绪。

被唤醒后进行判断,如果是数据就绪被唤醒,则调用read从按键的寄存器中读取按键数据,如果是超时被唤醒,则不调用read去读取了。

  • poll/select起到监视事件就绪的作用,驱动层的drv_poll都会告诉应用层APP所监视事件的状态。
  • APP根据驱动层告知的事件状态进行下一步动作。

🍩异步通知方式

图

如上图所示异步通知方式,在该模型中,应用层在打开要操作的设备时,要调用fcntl设置其fdFASYNC标志,此时会调用驱动层的drv_fasync函数:

tu
如上图所示,在file_operations结构体中也有一个fsync函数指针,在该模型中,该指针指向的函数只需要记录当前进程的PID

除了设置给fd设置FASYNC表示异步通知外,还需要使用signal系统调用注册信号处理函数my_func

此时该模型的处理步骤为:

  • APP调用open配置GPIO引脚为输入方式,并注册中断服务函数。
  • APP调用fcntl设置fd指向的文件为异步通知方式,并且注册信号处理函数.
  • 当硬件按键被按下时,中断服务程序会给记录下来的进程PID表示的进程发送信号,信号递达后执行注册的my_func信号处理函数。
  • 在信号处理函数中,调用read来读取按键数据,此时必然是有按键数据的。
  • 在没有按键按下时,APP正常执行,当按键按下后立刻去读取按键数据,使得应用层实现了中断的处理方式。

我们的驱动程序可以实现上述 4 种提供按键驱动的方法,但是驱动程序不应该限制APP使用哪种方法。

  • 这就是驱动设计的一个原则:只提供能力,不提供策略

就是说,APP想用哪种方法都行,驱动程序都可以提供;但是驱动程序不能限制APP使用哪种方法。

🍮查询方式实现按键驱动

前面介绍了按键的四种驱动模型,但是由于后面三种都涉及到中断方面的知识,而到目前为止本喵还没有介绍驱动程序中的中断,所以这里先仅用查询方式实现一下按键驱动程序:

tu

如上图所示,采用简单的驱动层分层模型来实现查询方式的按键驱动层数:

  • 应用层open/read系统调用和驱动层的drv_open/drv_read通过file_operations结构体来建立联系。
  • 驱动层上层的drv_open/drv_read和驱动层下层的board_button_init/board_button_read通过button_opr结构体连建立联系。

驱动层下层的board_button_init/board_button_read由具体的单板提供:

  • 驱动层下层的board_button_init根据设备号确定哪个按键,并将GPIO配置为输入引脚。
  • 驱动层下层的board_button_read根据设备号确定哪个按键,并读取对应寄存器中的值返回引脚电平。

驱动层上层:

tu
如上图所示,在button_operations.h中定义button_operations结构体:

  • count:表示按键设备个数
  • init:驱动层下层提供的初始化按键设备方法。
  • read:驱动层下层提供的读取按键状态方法。

tu
如上图所示,在button_drv.c中,创建file_operations结构体,并且用drv_opendrv_read初始化openread函数指针:

  • drv_open函数中,使用p_button_opr结构体中的init,根据次设备号进行初始化。
  • drv_read函数中,使用p_button_opr结构体中的read,根据次设备号读取按键状态。
    • 将读取到的按键状态level拷贝到用户层缓冲区。

图
如上图所示,在入口函数button_init中使用register_chrdev向内核中注册file_operations结构体,并且获得主设备号。还要创建button_class设备类来提供设备信息。

在出口函数button_exit中,销毁设备类button_class,并且使用unregister_chrdev函数从内核中将前面注册的file_operations移除。

图
如上图,由于p_button_opr结构体指针是由驱动层下层提供的,所以驱动层上层要提供一个register_button_operations函数给下层,让下层向上层注册p_button_opr结构体。

  • 在注册时,还要将所有按键设备使用device_create在文件系统中创建设备节点文件。
  • 在卸载时,使用device_destroy将文件系统中的所有按键设备文件移除掉。

由于下层在使用这两个函数时会用到上层的button_class类,所以这两个函数需要使用EXPORT_SYMBOL导出给下层,供下层先使用。

图
如上图,最后完善一下设备信息,告诉内核哪个是入口函数,哪个是出口函数,并且声明该驱动程序使用GPL协议。

驱动层下层:

图
如上图所示,在驱动层下层的board_button.c文件中,创建button_operations结构体,并进行初始化:

  • count:按键设备有两个。
  • init:初始化按键设备的函数board_button_init
  • read:读取按键设备状态的函数board_button_read

在入口函数中,使用驱动层上层提供的register_button_operations函数将下层创建的my_button_oprs结构体对象注册到上层,供上层使用下层提供的初始化和读取数据的方法。

在出口函数汇中,使用上层提供的unregister_button_operations函数移除在文件系统中创建的设备节点文件。

最后完善一下设备信息。

对于驱动层下层,重点在于初始化和读取数据函数的实现:

图
如上图所示IMX6ULL按键的电路原理图:

  • KEY1:与GPIO5_1相连,按键按下时是低电平(0),未按下时是高电平(1)。
  • KEY2:与GPIO4_IO14相连,按键按下时是低电平(0),未按下时是高电平(1)。
  1. 使能GPIO

TU
如上图所示使能GPIO的寄存器:

  • CCM_CCGR1:物理地址是0x020C406C,其中的[31,30]控制GPIO5的使能,但是这里保留了,GPIO5默认使能,
  • CCM_CCGR3:物理地址是0x020C4074,其中的[13,12]控制GPIO的使能,当这两个比特位为11时,GPIO4使能。
  1. 选择GPIO模式

tu
如上图所示IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1寄存器:

  • 物理地址是0x0229000C
  • MUX_MODE:这四个bit为101时,表示GPIO5_IO01引脚用作通用GPIO。

图
如上图所示IOMUXC_SW_MUX_CTL_PAD_NAND_CE1_B寄存器:

  • 物理地址是0x020E01B0
  • MUX_MODE:这四个bit为0101时,表示GPIO4_IO14引脚用作通用GPIO。
  1. 设置GPIO方向

TU
如上图所示内存映射表:

  • GPIO5:该组寄存器的基地址是0x020AC000
  • GPIO4:该组寄存器的基地址是0x020A8000

图
如上图所示GPIO所有寄存器的内存映射表,以GPIO4为例:

  • 一共8个寄存器,每组GPIO都是这样。
  • DR寄存器开始,到EDGE_SEL寄存器结束,地址从低到高,每个寄存器所占4个字节。

所以定义一个结构体来描述GPIO组中的所有寄存器:

tu
如上图所示结构体,用该结构体创建gpio5gpio4结构体对象来操作相应的GPIO。

图
如上图所示GDIR寄存器:

  • 对于GPIO5_1:将gpio5->gdirbit1设置为0,表示输入。
  • 对于GPIO4_14:将gpio4->gdirbit14设置为0,表示输入。
  1. 读取按键状态:

tu
如上图所示PSR寄存器:

  • 对于GPIO5_1gpio5->psrbit1为0,表示按键按下,为低电平,为1,表示按键没有按下,为高电平。
  • 对于GPIO4_14gpio4->gdirbit14为0,表示按键按下,为低电平,为1,表示按键没有按下,为高电平。

编程

tu

如上图所示,在驱动层下层board_button.c中,将用到的寄存器全部定义出来,并且创建gpio4gpio5两个结构体变量来表示GPIO。

board_button_init:

图

如上图所示初始化函数中:

  • 将所有涉及到的寄存器都在内存中映射相应的虚拟地址,只映射一次。
    • 其中GPIO组进行整体映射,大小为struct imx6ull_gpio结构体的大小。
  • 根据次设备号对GPIO口进行初始化,控制相关寄存器。
    • 使能GPIO组,设置引脚模式为通用GPIO,设置方向为输入。

board_button_read:

图
如上图所示读取按键数据的函数,根据次设备号确定读取gpio5还是gpio4中的psr寄存器,然后返回该寄存器中的值。

应用层测试函数:

tu
如上图应用层测试函数,在测试的时候,命令行中输入./button_test /dev/BigMiaomi_button0或者./button_test /dev/BigMiaomi_button1,在mian函数中会使用read系统调用去获取按键状态,最终会调用驱动层下层的board_button_read函数。

  • 如果打印1,表示按键没有按下。
  • 如果打印0,表示按键按下。

图
如上图所示Makefile文件中,make以后:

  • 会生成button_test可执行程序,用来测试。
  • 会生成button_drv.koboard_button.ko两个模块文件,用来安装驱动程序。

图
如上图所示,在开发板上安装两个按键的驱动程序,可以看到在./dev目录下有BigMiaomi_button0BigMiaomi_button1两个设备节点。

TU

如上图所示,在开发板上执行测试程序:

  • 未在开发板上按下KEY1KEY2两个按键时,打印出的值是1,表示高电平,和电路逻辑相符。
  • 按下开发板上按下KEY1KEY2两个按键时,打印出的值是0,表示低电平,和电路逻辑相符。

🍮总结

要会使用设备树向内核中注册设备节点,并且会对驱动程序做相应的修改。除此之外,要知道APP读取按键的四种方式,以及实现简单的APP按键驱动程序编程。

相关文章:

【Linux驱动】设备树模型的LED驱动 | 查询方式的按键驱动

🐱作者:一只大喵咪1201 🐱专栏:《Linux驱动》 🔥格言:你只管努力,剩下的交给时间! 目录 🍮设备树模型的LED驱动🍩设备树文件🍩驱动程序 &#x1…...

GZ075 云计算应用赛题第4套

2023年全国职业院校技能大赛(高职组) “云计算应用”赛项赛卷4 某企业根据自身业务需求,实施数字化转型,规划和建设数字化平台,平台聚焦“DevOps开发运维一体化”和“数据驱动产品开发”,拟采用开源OpenSt…...

小型肉制品厂废水处理设备加工厂家

诸城市鑫淼环保小编带大家了解一下小型肉制品厂废水处理设备加工厂家 在小型肉制品厂,处理肉类加工废水是非常重要的环保问题。废水中含有蛋白质、脂肪、悬浮物和有机物等,需要进行合适的处理以减少对环境的污染。以下是一些常见的小型肉制品厂废水处理设…...

SpringBoot整合ElasticSearch实现CRUD操作

本文来说下SpringBoot整合ES实现CRUD操作 文章目录 概述项目搭建ES简单的crud操作本文小结 概述 SpringBoot支持两种技术和es交互。一种的jest,还有一种就是SpringData-ElasticSearch。根据引入的依赖不同而选择不同的技术。反正作为spring全家桶,目前是…...

香橙派--关于jammy-xfce-arm64.f12a43b3e629442a073a7236bf9166ce.tar.lz4的rootfs定制与镜像制作

使用 x64 的 Ubuntu22.04 电脑编译 Linux SDK,即 orangepi-build,支持在安装有 Ubuntu 22.04 的电脑上运行,所以下载 orangepi-build 前,请首先确保自己电脑已安装的 Ubuntu 版本是 Ubuntu22.04。查看电脑已安装的 Ubuntu 版本的命…...

前端八股文(HTML篇)一

目录 1.什么是DOCTYPE,有何用呢? 2.说说对html语义化的理解 3.src和href的区别? 4.title与h1的区别,b与strong的区别,i与em的区别? 5.什么是严格模式与混杂模式? 6.前端页面有哪三层构成,分…...

数据结构与算法python版本之线性结构之无序表抽象数据类型有序链表抽象数据类型和总结

我们知道,列表List是一种简单强大的数据集结构,提供了丰富的操作接口;但是并不是所有的编程语言都提供了List数据类型,有时候需要程序员自己实现。 那么什么是列表呐? 列表是一种数据项按照相对位置存放的数据集&…...

识别pdf中论文标题并重命名PDF名称(2024.1.2,第二次更新)判断标题中是否以空格结尾

63~66行增加语句,判断标题是否以空格结尾 83~85行增加语句,判断选句是否以空格结尾 import os import timeimport fitzdef find_largest_font_sentence(pdf_path):largest_font_size 0largest_font_sentence maxsize0# 打开PDF文件document fitz.ope…...

01.02作业

整理思维导图复习课上代码全局变量,int monster 10000;定义英雄类hero,受保护的属性string name,int hp,int attck;公有的无参构造,有参构造,虚成员函数 void Atk(){blood-0;},法师类继承自英雄…...

WPF+Halcon 培训项目实战(11):HS组件封装

文章目录 前言相关链接项目专栏运行环境匹配图片封装组件新增类库项目选择依赖顺序并添加Nuget修改原本矩形方法运行结果: 对矩形进行抽象封装抽象基类矩形抽象改造 圆形抽象封装代码运行结果 前言 为了更好地去学习WPFHalcon,我决定去报个班学一下。原…...

VUE——IDEA 启动前端工程VS文件启动前端工程

IDEA 启动前端 目录 前言一、打开控制台二、输入npm install三、依赖下载完之后,输入npm run dev,运行前端项目1、IDEA启动前端工程2、文件目录启动前端工程 四、点击http://localhost:8080后续敬请期待 前言 启动已有的vue前端项目 一、打开控制台 选…...

自动驾驶论文

文章目录 一、Convolutional Social Pooling for Vehicle Trajectory Prediction二、QCNet:Query-Centric Trajectory Prediction三、VectorNet: Encoding HD Maps and Agent Dynamics from Vectorized Representation 一、Convolutional Social Pooling for Vehicl…...

Java经典框架之SpringDataJPA

SpringDataJPA Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Spring整合Hibernate 2…...

向爬虫而生---Redis 基石篇3 <拓展List>

前言: 继上一篇向爬虫而生---Redis 基石篇2 <拓展Hash>-CSDN博客​​​​​​.往下继续---挖一挖list 正文: 在Redis中,列表(List)是一个常用的数据结构,尤其在爬虫应用中。例如,可以用列表实现…...

CSS渲染性能优化

✨ 专栏介绍 HTML/CSS专栏合集是一个涵盖HTML和CSS两个方面的栏目。HTML是一种标记语言,用于创建网页的结构和内容,而CSS是一种样式表语言,用于控制网页的外观和布局。 在HTML/CSS专栏合集中,我们将深入探讨HTML和CSS的基础知识…...

【C++入门】类和对象(完)

前言 在谈论C时,常常会涉及到一些高级特性和概念,比如初始化列表、static成员、友元、内部类、匿名对象等。这些概念在C编程中起着非常重要的作用,对于想要深入了解C语言的开发者来说,掌握这些知识是至关重要的。本文,…...

webshell检测方式深度剖析 --- Pixy系列二(数据流分析)

开篇 书接上文,这次我们来聊聊数据流分析,数据流分析的内容非常广泛,我们力求深入浅出通俗易懂,在简短的篇幅内将这一概念描述清楚。 简单来说,数据流分析是一种用来获取相关数据沿着程序执行路径流动的信息分析技术…...

[DAU-FI Net开源 | Dual Attention UNet+特征融合+Sobel和Canny等算子解决语义分割痛点]

文章目录 概要I Introduction小结 概要 提出的架构,双注意力U-Net与特征融合(DAU-FI Net),解决了语义分割中的挑战,特别是在多类不平衡数据集上,这些数据集具有有限的样本。DAU-FI Net 整合了多尺度空间-通…...

使用Triton部署ONNX模型

介绍 适用于各种 AI 工作负载的推理:借助 NVIDIA Triton™,在任何处理器(GPU、CPU 或其他)上,对使用基于任何框架的,经过训练的机器学习模型或深度学习模型,进行推理部署。Triton 是 NVIDIA AI…...

Python访问ElasticSearch

ElasticSearch是广受欢迎的NoSQL数据库,其分布式架构提供了极佳的数据空间的水平扩展能力,同时保障了数据的可靠性;反向索引技术使得数据检索和查询速度非常快。更多功能参见官网介绍 https://www.elastic.co/cn/elasticsearch/ 下面简单罗列…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

深度学习习题2

1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...

Spring Security 认证流程——补充

一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...