驱动(RK3588S)第九课时:多节点驱动与函数接口
目录
- 一、多节点概念
- 1、所用到的结构体说明
- 2、函数接口主要是read和write函数
- 2.1、把应用层的数据拷贝给底层
- 2.2、把应用层的数据拷贝给底层
- 3、应用层的read和write函数
- 4、底层的read和write函数
- 二、ioctl控制命令接口
- 1、概念
- 2、函数介绍应用层和驱动层
- 三、代码与现象
- 1.编写LED灯的多节点驱动实现流水灯
- 2.编写KEY按键驱动实现底层按键按下反馈给应用层
- 3.编写beep的驱动代码可以使用ioctl控制
学习目标:
1.编写LED灯的多节点驱动实现流水灯
2.编写KEY按键驱动实现底层按键按下反馈给应用层
3.编写beep的驱动代码可以使用ioctl控制
一、多节点概念
这里所谓的多节点驱动其实指的就是一个设备对应一个设备节点。比如我现在有 4 个 led 等,你怎么做到单独的去控制每一盏灯。此时如果你想单独的去操控一个 LED 灯,那么你就需要单独给他们每一个灯去申请注册一个设备节点。多节点对于一类设备他们的主设备号必然是一样的,只不过是一类设备当中的不同的子设备。
比如有四个灯,那么他们的设备编号如下:
LED1 crwx----------- 350 0 /dev/led1
LED2 crwx----------- 350 1 /dev/led2
LED3 crwx----------- 350 2 /dev/led3
LED4 crwx----------- 350 3 /dev/led4
此时你在去使用应用层的 open 去打开单独的一个硬件设备节点,这样你就可以单独的操作这个设备。
1、所用到的结构体说明
这里内核是通过你 open 打开对应节点的设备号去区分不同的设备的,靠的就是函数的参数。
int (*open) (struct inode *, struct file *);
struct inode {
i_rdev:如果索引节点代表设备文件,则表示设备的主设备号和次设备号
};
struct file{
void *private_data;
}
private_data:他是一个私有数据,他主要就是给其他函数使用的
2、函数接口主要是read和write函数
函数接口里主要讲解的就是 read 和 write是 对数据进行读写操作的。内核是不允许让应用层和底层进行直接数据交互的,就是为了保护内核的安全。那么内核层和应用能不能进行数据交互呢?肯定是可以的,但是必须要使用内核提供的函数,进行数据的交互。所谓的数据交互就是应用层把数据拷贝给内核层,内核层把数据拷贝给应用层这就是所谓的数据交互。上层的写函数和读函数是不能直接给底层的写函数和读函数进行数据,若想直接交互的话,这里就需要使用以下两个函数
2.1、把应用层的数据拷贝给底层
函数功能:把应用层的数据拷贝给底层
函数原型:unsigned long copy_from_user(void *to, const void __user *from,
unsigned long n)
函数头文件:#include <linux/uaccess.h>
函数参数:to:他就是你要保存应用层数据的位置,把要接受的数据保存到哪里
from:他就是底层写函数的里的 buf
n:就是数据的大小 — from
函数返回值:成功返回 0 失败返回负数
2.2、把应用层的数据拷贝给底层
函数功能:把内核层的数据拷贝给应用层
函数原型:unsigned long copy_to_user(void __user *to, const void *from,
unsigned long n)
函数头文件:#include <linux/uaccess.h>
函数参数:to:就是底层读函数里的 buf
from: 要拷贝底层的具体数据
n:就是数据的大小 即,from大小
函数返回值:成功返回 0 失败返回负数
3、应用层的read和write函数
ssize_t read(int fd, void *buf, size_t count)
参数:fd: — 打开文件的描述符
buf: — 读取数据保存的位置
count:---- 读取数据的大小
ssize_t write(int fd, const void *buf, size_t count)
参数:fd: — 打开文件的描述符
buf: — 你要写入文件的数据的保存位置
count:---- 写入数据的大小
4、底层的read和write函数
**ssize_t (*read) (struct file *fp, char __user buf, size_t size, loff_t offset)
参数:fp:保存文件信息的核心结构体
buf:保存底层给应用层读取数据的保存位置 ,里面就保存内核要给用层的数据。
size:就数据的大小 — 就是 buf 的大小
offset:当前文件光标的位置
**ssize_t (write) (struct file fp, const char __user buf, size_t size,loff_toffset)
参数:fp:保存文件信息的核心结构体
buf:保存应用层给底层写人数据保存位置
size:就数据的大小 — 就是 buf 的大小
offset:当前文件光标的位置
二、ioctl控制命令接口
1、概念
ioctl用来做一些控制命令接口 类似:msgctl、semctl、shmctl 等(ioctl 是设备
驱动程序中对设备的 I/O 通道进行管理的函数。所谓对 I/O 通道进行管理,就
是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等)
2、函数介绍应用层和驱动层
函数功能:做一些控制命令的接口
函数原型:int ioctl(int fd, unsigned long request, …)
函数头文件:#include <sys/ioctl.h>
函数参数:fd:就是 open 打开的文件描述符
request:cmd 就是控制的命令
函数返回值:成功返回 0 失败返回负数
函数功能:做控制的命令
函数原型:**long (unlocked_ioctl) (struct file fp, unsigned int cmd, unsigned long arg);
函数头文件:#include <linux/fs.h>
函数参数:fp:保存文件信息结构体
cmd:就是你应用层传递过来的命令 — request
arg:暂时不用管
函数返回值:成功返回 0 失败负数
三、代码与现象
1.编写LED灯的多节点驱动实现流水灯
内核层:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
int led[2]={0};
const char *devs_name[2]={"myqxjled1","myqxjled2"};
int i;
dev_t dev[2]={0};
struct cdev mydev;
struct class *myclass=NULL;int myled_open (struct inode *inode, struct file *fp)
{if(inode->i_rdev==dev[0]){gpio_set_value(led[0],1);}if(inode->i_rdev==dev[1]){gpio_set_value(led[1],1);}printk("myled open 正确打开\n");return 0;
}int myled_close (struct inode *inode, struct file *fp)
{if(inode->i_rdev==dev[0]){gpio_set_value(led[0],0);}if(inode->i_rdev==dev[1]){gpio_set_value(led[1],0);}printk("myled close 关闭正确\n");return 0;
}
struct file_operations myfops={.open = myled_open,.release = myled_close,
};int myled_probe(struct platform_device *pdev)
{printk("探测函数:设备端和驱动端匹配成功\n");//led[0] led[1]返回的是gpio编口号led[0]=of_get_named_gpio(pdev->dev.of_node,"leds-gpios",0);//获得设备树的属性led[1]=of_get_named_gpio(pdev->dev.of_node,"leds-gpios",1);gpio_request(led[0], "led1 pc5");//21 申请你要使用 gpio 口的资源gpio_request(led[1], "led2 pc6");//22gpio_direction_output(led[0],0);//配置 gpio 口的工作模式gpio_direction_output(led[1],0); alloc_chrdev_region(dev,0,2,"led");//动态申请设备号 linux2.6或杂项类型dev[1]=dev[0]+1;cdev_init(&mydev,&myfops);//初始化核心结构体cdev_add(&mydev,dev[0],2);//向内核去申请 linux2.6 字符设备myclass=class_create(THIS_MODULE,"class_led");//创建类if(myclass == NULL){printk("class_create error\n");printk("class_create 类创建失败\n");return -1;}for(i=0;i<=1;i++){device_create(myclass,NULL,dev[i],NULL,devs_name[i]);//自动创建设备节点}return 0;
}int myled_remove (struct platform_device *pdev)
{printk("移除函数成功\n");device_destroy(myclass,dev[0]);//销毁设备节点 在/dev/name ---device_createdevice_destroy(myclass,dev[1]);class_destroy(myclass);//销毁类 --class_createcdev_del(&mydev);//释放申请的字符设备 --cdev_addunregister_chrdev_region(dev[0],2);//释放申请的设备号 ---alloc_chrdev_regiongpio_free(led[0]);// 释放 gpio 口资源 ----gpio_requestgpio_free(led[1]);return 0;
}
struct of_device_id mydev_node={.compatible="xyd-led",
};struct platform_driver drv={.probe = myled_probe,.remove = myled_remove,.driver = {.name = "myxyd_leds",//与设备端必须保持一致.of_match_table = &mydev_node,},
};
static int __init myled_init(void)
{ platform_driver_register(&drv);return 0;
}
static void __exit myled_exit(void)
{platform_driver_unregister(&drv);
}
module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
应用层:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{int fd = 0;while(1){fd = open("/dev/myqxjled1",O_RDWR); // --- 底层的open函数sleep(1);close(fd);//底层的closesleep(1);fd=open("/dev/myqxjled2",O_RDWR); // --- 底层的open函数sleep(1);close(fd);//底层的closesleep(1); }return 0;
}
编译:
obj-m += led_driver.o #最终生成模块的名字就是 led.ko KDIR:=/home/stephen/RK3588S/kernel #他就是你现在rk3588s里内核的路径 CROSS_COMPILE_FLAG=/home/stephen/RK3588S/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-#这是你的交叉编译器路径 --- 这里你也要替换成你自己的交叉编译工具的路径
all:make -C $(KDIR) M=$(PWD) modules ARCH=arm64 CROSS_COMPILE=$(CROSS_COMPILE_FLAG)aarch64-none-linux-gnu-gcc app.c -o app#调用内核层 Makefile 编译目标为 modules->模块 文件在当前路径# 架构 ARCH=arm64
clean:rm -f *.o *.mod.o *.mod.c *.symvers *.markers *.order app *.mod
灯现象:
2.编写KEY按键驱动实现底层按键按下反馈给应用层
内核层:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
int key[2]={0};
int beep = 0;
int key_value = 0;
int beep_value[2] = {0};
dev_t dev;
struct cdev mydev;
struct class *myclass=NULL;int myled_open (struct inode *inode, struct file *fp)
{printk("myled open 正确打开\n");return 0;
}int myled_close (struct inode *inode, struct file *fp)
{printk("myled close 关闭正确\n");return 0;
}
ssize_t mykey_read (struct file *fp, char __user *buf, size_t size, loff_t *offset)
{unsigned long ret=0;if(gpio_get_value(key[0])==0){key_value=1;printk("按键1被按下\n");}else if(gpio_get_value(key[1])==0){key_value=2;printk("按键2被按下\n");}ret=copy_to_user(buf,&key_value,4);if(ret<0){printk("copy_to_user 错误\n");return -1;}key_value=0;return 0;
}
ssize_t mykey_write (struct file *fp, const char __user *buf, size_t size, loff_t *offset)
{ unsigned long ret=0;ret=copy_from_user(beep_value,buf,4);if(ret<0){printk("copy_from_user 错误\n");return -1;}if(beep_value[0]==1){gpio_set_value(beep,beep_value[0]);}else if(beep_value[1]==0){gpio_set_value(beep,beep_value[1]);}return 0;
}
struct file_operations myfops={.open = myled_open,.release = myled_close,.read = mykey_read,.write = mykey_write,
};int myled_probe(struct platform_device *pdev)
{printk("探测函数:设备端和驱动端匹配成功\n");//led[0] led[1]返回的是gpio编口号key[0]=of_get_named_gpio(pdev->dev.of_node,"devices-gpios",2);//获得设备树的属性key[1]=of_get_named_gpio(pdev->dev.of_node,"devices-gpios",3);beep = of_get_named_gpio(pdev->dev.of_node,"devices-gpios",4);gpio_request(key[0], "key1 pa7");//21 申请你要使用 gpio 口的资源gpio_request(key[1], "key2 pb1");//22gpio_request(beep, "beep pa4");//36gpio_direction_input(key[0]);//配置 gpio 口的工作模式gpio_direction_input(key[1]); gpio_direction_output(beep,0);//高电平叫alloc_chrdev_region(&dev,0,1,"led");//动态申请设备号 linux2.6或杂项类型cdev_init(&mydev,&myfops);//初始化核心结构体cdev_add(&mydev,dev,1);//向内核去申请 linux2.6 字符设备myclass=class_create(THIS_MODULE,"class_led");//创建类if(myclass == NULL){printk("class_create error\n");printk("class_create 类创建失败\n");return -1;}device_create(myclass,NULL,dev,NULL,"mykey");//自动创建设备节点return 0;
}int myled_remove (struct platform_device *pdev)
{printk("移除函数成功\n");device_destroy(myclass,dev);//销毁设备节点 在/dev/name ---device_createclass_destroy(myclass);//销毁类 --class_createcdev_del(&mydev);//释放申请的字符设备 --cdev_addunregister_chrdev_region(dev,1);//释放申请的设备号 ---alloc_chrdev_regiongpio_free(key[0]);// 释放 gpio 口资源 ----gpio_requestgpio_free(key[1]);gpio_free(beep);return 0;
}
struct of_device_id mydev_node={.compatible="xyd-device",
};struct platform_driver drv={.probe = myled_probe,.remove = myled_remove,.driver = {.name = "xyd-device",//与设备端必须保持一致.of_match_table = &mydev_node,},
};
static int __init myled_init(void)
{ platform_driver_register(&drv);return 0;
}
static void __exit myled_exit(void)
{platform_driver_unregister(&drv);
}
module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
应用层:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{int fd = 0;int beep_value[2]={1,0};int key_value=0;fd = open("/dev/mykey",O_RDWR); // --- 底层的open函数while(1){write(fd,&beep_value[0],4);usleep(500000);write(fd,&beep_value[1],4);usleep(500000);read(fd,&key_value,4);if(key_value==1){printf("第%d个按键按下\n",key_value);}else if(key_value==2){printf("第%d个按键按下\n",key_value);}usleep(500000);}close(fd);//底层的close return 0;
}
编译:
obj-m += led_driver.o #最终生成模块的名字就是 led.ko KDIR:=/home/stephen/RK3588S/kernel #他就是你现在rk3588s里内核的路径 CROSS_COMPILE_FLAG=/home/stephen/RK3588S/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-#这是你的交叉编译器路径 --- 这里你也要替换成你自己的交叉编译工具的路径
all:make -C $(KDIR) M=$(PWD) modules ARCH=arm64 CROSS_COMPILE=$(CROSS_COMPILE_FLAG)aarch64-none-linux-gnu-gcc app.c -o app#调用内核层 Makefile 编译目标为 modules->模块 文件在当前路径# 架构 ARCH=arm64
clean:rm -f *.o *.mod.o *.mod.c *.symvers *.markers *.order app *.mod
3.编写beep的驱动代码可以使用ioctl控制
驱动层:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
int key[2]={0};
int beep = 0;
int key_value = 0;
int beep_value[2] = {0};
dev_t dev;
struct cdev mydev;
struct class *myclass=NULL;int myled_open (struct inode *inode, struct file *fp)
{printk("myled open 正确打开\n");return 0;
}int myled_close (struct inode *inode, struct file *fp)
{printk("myled close 关闭正确\n");return 0;
}
ssize_t mykey_read (struct file *fp, char __user *buf, size_t size, loff_t *offset)
{unsigned long ret=0;if(gpio_get_value(key[0])==0){key_value=1;printk("按键1被按下\n");}else if(gpio_get_value(key[1])==0){key_value=2;printk("按键2被按下\n");}ret=copy_to_user(buf,&key_value,4);if(ret<0){printk("copy_to_user 错误\n");return -1;}key_value=0;return 0;
}
ssize_t mykey_write (struct file *fp, const char __user *buf, size_t size, loff_t *offset)
{ unsigned long ret=0;ret=copy_from_user(&beep_value,buf,4);if(ret<0){printk("copy_from_user 错误\n");return -1;}if(beep_value[0]==1){gpio_set_value(beep,beep_value[0]);}else if(beep_value[1]==0){gpio_set_value(beep,beep_value[1]);}return 0;
}
long mybeep_ioctl (struct file *fp, unsigned int cmd, unsigned long arg)
{if(cmd==1){gpio_set_value(beep,1);}if(cmd==0){gpio_set_value(beep,0);}return 0;
}
struct file_operations myfops={.open = myled_open,.release = myled_close,.read = mykey_read,.write = mykey_write,.unlocked_ioctl=mybeep_ioctl,
};int myled_probe(struct platform_device *pdev)
{printk("探测函数:设备端和驱动端匹配成功\n");//led[0] led[1]返回的是gpio编口号key[0]=of_get_named_gpio(pdev->dev.of_node,"devices-gpios",2);//获得设备树的属性key[1]=of_get_named_gpio(pdev->dev.of_node,"devices-gpios",3);beep = of_get_named_gpio(pdev->dev.of_node,"devices-gpios",4);gpio_request(key[0], "key1 pa7");//21 申请你要使用 gpio 口的资源gpio_request(key[1], "key2 pb1");//22gpio_request(beep, "beep pa4");//36gpio_direction_input(key[0]);//配置 gpio 口的工作模式gpio_direction_input(key[1]); gpio_direction_output(beep,0);//高电平叫alloc_chrdev_region(&dev,0,1,"led");//动态申请设备号 linux2.6或杂项类型cdev_init(&mydev,&myfops);//初始化核心结构体cdev_add(&mydev,dev,1);//向内核去申请 linux2.6 字符设备myclass=class_create(THIS_MODULE,"class_led");//创建类if(myclass == NULL){printk("class_create error\n");printk("class_create 类创建失败\n");return -1;}device_create(myclass,NULL,dev,NULL,"mykey");//自动创建设备节点return 0;
}int myled_remove (struct platform_device *pdev)
{printk("移除函数成功\n");device_destroy(myclass,dev);//销毁设备节点 在/dev/name ---device_createclass_destroy(myclass);//销毁类 --class_createcdev_del(&mydev);//释放申请的字符设备 --cdev_addunregister_chrdev_region(dev,1);//释放申请的设备号 ---alloc_chrdev_regiongpio_free(key[0]);// 释放 gpio 口资源 ----gpio_requestgpio_free(key[1]);gpio_free(beep);return 0;
}
struct of_device_id mydev_node={.compatible="xyd-device",
};struct platform_driver drv={.probe = myled_probe,.remove = myled_remove,.driver = {.name = "xyd-device",//与设备端必须保持一致.of_match_table = &mydev_node,},
};
static int __init myled_init(void)
{ platform_driver_register(&drv);return 0;
}
static void __exit myled_exit(void)
{platform_driver_unregister(&drv);
}
module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
应用层:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc,char *argv[])
{int fd = 0;fd = open("/dev/mykey",O_RDWR); // --- 底层的open函数while(1){ioctl(fd,1);usleep(500000);ioctl(fd,1);usleep(500000);}close(fd);//底层的close return 0;
}
编译:
obj-m += led_driver.o #最终生成模块的名字就是 led.ko KDIR:=/home/stephen/RK3588S/kernel #他就是你现在rk3588s里内核的路径 CROSS_COMPILE_FLAG=/home/stephen/RK3588S/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-#这是你的交叉编译器路径 --- 这里你也要替换成你自己的交叉编译工具的路径
all:make -C $(KDIR) M=$(PWD) modules ARCH=arm64 CROSS_COMPILE=$(CROSS_COMPILE_FLAG)aarch64-none-linux-gnu-gcc app.c -o app#调用内核层 Makefile 编译目标为 modules->模块 文件在当前路径# 架构 ARCH=arm64
clean:rm -f *.o *.mod.o *.mod.c *.symvers *.markers *.order app *.mod
相关文章:

驱动(RK3588S)第九课时:多节点驱动与函数接口
目录 一、多节点概念1、所用到的结构体说明2、函数接口主要是read和write函数2.1、把应用层的数据拷贝给底层2.2、把应用层的数据拷贝给底层 3、应用层的read和write函数4、底层的read和write函数二、ioctl控制命令接口1、概念2、函数介绍应用层和驱动层 三、代码与现象1.编写L…...

Linux系统下配置MySQL
1. 寻找MySQL的配置文件 MySQL的配置文件通常位于以下位置: 在大多数Linux系统上,主配置文件通常位于/etc/mysql/my.cnf或/etc/my.cnf。在macOS上,如果你使用Homebrew安装MySQL,配置文件通常位于/usr/local/etc/my.cnf。在Window…...

信捷 XD PLC POU编程之FB
在使用信捷的POU方式编程,可以建立两种POU:FB和FC。 FB和FC这两种POU又各自可以建立梯形图语言POU和C语言POU。 函数块(FB)是把反复使用的部分程序块转换成一种通用部件,他可以在程序中反复被调用,不仅 提高了程序的开…...

终于有人把云计算、大数据和人工智能讲明白了!
引言 在当今数字化时代,云计算、大数据和人工智能成为了全球科技界的热门话题。这些技术的迅猛发展以及应用范围的不断扩大,正深刻地改变着我们的生活和工作方式。云计算为我们提供了有效的计算和存储能力,大数据则以海量的信息资源为基础&a…...

【编程底层思考】详解Java内存模型(JMM)原理及其作用
Java内存模型(Java Memory Model, JMM)是Java虚拟机(JVM)的一个核心概念,它定义了Java程序中各种变量(线程共享变量)的访问规则,以及在并发环境下,为了确保数据的可见性、…...

Docker的基本概念和优势
Docker是一个开源的容器化平台,它可以将应用程序及其所有依赖项和运行环境打包到一个称为容器的独立单元中。容器化使得应用程序在不同的环境中可以以相同的方式运行,并且更加轻量级和可移植。 Docker的基本概念包括以下几点: 镜像…...

数据结构————内核链表
内核链表是Linux内核中广泛使用的一种数据结构,它具有以下特点: 1.双向循环链表:每个节点包含两个指针,一个指向前驱节点(prev),另一个指向后继节点(next),…...

使用API接口获取某宝商品数据详情
什么是淘宝API接口? 淘宝API接口是淘宝开放平台为开发者提供的一种应用程序接口。它允许开发者通过编程方式,安全、高效地与淘宝平台进行数据交互,从而获取商品详细信息、用户信息、订单信息等多种数据。这些接口不仅简化了数据获取流程&…...

用Python实现时间序列模型实战——Day 15: 时间序列模型的选择与组合
一、学习内容 1. 模型选择的标准与方法(如 AIC、BIC) 在时间序列建模中,模型的选择是非常重要的,常用的模型选择标准包括 AIC (Akaike Information Criterion) 和 BIC (Bayesian Information Criterion)。 AIC (Akaike Informat…...

大数据之Flink(五)
15、Flink SQL 15.1、sql-client准备 启用Hadoop集群(在Hadoop100上) start-all.sh启用yarn-session模式 /export/soft/flink-1.13.0/bin/yarn-session.sh -d启动sql-client bin/sql-client.sh embedded -s yarn-sessionsql文件初始化 可以初始化模式、环境(流/批…...

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析
查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但…...

基于 jenkins 的持续测试方案
CI/CD Continuous Integration; Continuous Deployment; 持续集成,将新代码和旧代码一起打包、构建;持续部署,将新构建的包进行部署;持续测试,将新代码、新单元测试一起测试;方案: 公有云DevO…...

我算见识到算法岗transformer面试的难度了
在面试算法岗的时候看到了这篇Transformer面试题,作者梳理一些关于Transformer的知识点,还会陆续更新最新的面试题和讲解答案! 也算是见识到了transformer的面试难度了 1.Transformer为何使用多头注意力机制?(为什么不使用一个头) 2.Tra…...

CommonCollections1
CommonCollections1链 CommonCollections1poc展示调用链分析AbstractInputCheckedMapDecoratorTransformedMapChainedTransformerConstantTransformerInvokerTransformer poc分析通过反射实现Runtime.getRuntime().exec("calc.exe")forNamegetMethodinvoke 依据反射构…...

6、关于Medical-Transformer
6、关于Medical-Transformer Axial-Attention原文链接:Axial-attention Medical-Transformer原文链接:Medical-Transformer Medical-Transformer实际上是Axial-Attention在医学领域的运行,只是在这基础上增加了门机制,实际上也就…...

19_单片机开发常用工具的使用
工欲善其事必先利其器,我们做单片机开发的时候,不管是调试电路还是调试程序,都需要借助一些辅助工具来帮助查找和定位问题,从而帮助我们顺利解决问题。没有任何辅助工具的单片机项目开发很可能就是无法完成的任务,不过…...

最新版微服务项目搭建
一,项目总体介绍 在本项目中,我将使用alibabba的 nacos 作为项目的注册中心,使用 spring cloud gateway 做为项目的网关,用 openfeign 作为服务间的调用组件。 项目总体架构图如下: 注意:我的Java环境是17…...

spring揭秘19-spring事务01-事务抽象
文章目录 【README】【1】事务基本元素【1.1】事务分类 【2】java事务管理【2.1】基于java的局部事务管理【2.2】基于java的分布式事务管理【2.2.1】基于JTA的分布式事务管理【2.2.2】基于JCA的分布式事务管理 【2.3】java事务管理的问题 【3】spring事务抽象概述【3.1】spring…...

基于Matlab的图像去雾系统(四种方法)关于图像去雾的基本算法代码的集合,方法包括局部直方图均衡法、全部直方图均衡法、暗通道先验法、Retinex增强。
基于Matlab的图像去雾系统(四种方法) 关于图像去雾的基本算法代码的集合,方法包括局部直方图均衡法、全部直方图均衡法、暗通道先验法、Retinex增强。 所有代码整合到App designer编写的GUI界面中,包括导入图片,保存处…...

油猴插件录制请求,封装接口自动化参数
参考:如何使用油猴插件提高测试工作效率 一、背景 在酷家乐设计工具测试中,总会有许多高频且较繁琐的工作,比如: 查询插件版本:需要打开Chrome控制台,输入好几个命令然后过滤出版本信息。 查询模型商品&…...

循环购模式!结合引流和复购于一体的商业模型!
欢迎各位朋友,我是你们的电商策略顾问吴军。今天,我将向大家介绍一种新颖的商业模式——循环购模式,它将如何改变我们的消费和收益方式。你是否好奇,为何商家会提供如此慷慨的优惠?消费一千元,不仅能够得到…...

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧
Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用&…...

c中 int 和 unsigned int
c语言中,char、short、int、int64以及unsigned char、unsigned short、unsigned int、unsigned int64等等类型都可以表示整数。但是他们表示整数的位数不同,比如:char/unisigned char表示8位整数; short/unsigned short表示16位整…...

sheng的学习笔记-AI-话题模型(topic model),LDA模型,Unigram Model,pLSA Model
AI目录:sheng的学习笔记-AI目录-CSDN博客 基础知识 什么是话题模型(topic model) 话题模型(topic model)是一族生成式有向图模型,主要用于处理离散型的数据(如文本集合),在信息检索、自然语言处理等领域有广泛应用…...

html 页面引入 vue 组件之 http-vue-loader.js
一、http-vue-loader.js http-vue-loader.js 是一个 Vue 单文件组件加载器,可以让我们在传统的 HTML 页面中使用 Vue 单文件组件,而不必依赖 Node.js 等其他构建工具。它内置了 Vue.js 和样式加载器,并能自动解析 Vue 单文件组件中的所有内容…...

html+css网页设计 旅行 蜘蛛旅行社3个页面
htmlcss网页设计 旅行 蜘蛛旅行社3个页面 网页作品代码简单,可使用任意HTML辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作)。 获取源码 1&#…...

考拉悠然产品发布会丨以悠然远智全模态AI应用平台探索AI行业应用
9月6日,成都市大模型新技术新成果发布暨供需对接系列活动——考拉悠然专场,在成都市高新区菁蓉汇盛大举行。考拉悠然重磅发布了悠然远智丨全模态AI应用平台,并精彩展示了交通大模型应用——智析快处等最新的AI产品和技术成果。 在四川省科学…...

LLM大模型学习:揭秘LLM应用构建:探究文本加载器的必要性及在LangChain中的运用
构建 LLM 应用为什么需要文本加载器,langchain 中如何使用文本加载器? 在不同的应用场景中需要使用不同的文本内容作为内容的载体,针对不同的类型的文本,langchain 提供了多种文本加载器来帮助我们快速的将文本切片,从…...

Flutter函数
在Dart中,函数为 一等公民,可以作为参数对象传递,也可以作为返回值返回。 函数定义 // 返回值 (可以不写返回值,但建议写)、函数名、参数列表 showMessage(String message) {//函数体print(message); }void showMessage(String m…...

P3565 [POI2014] HOT-Hotels
~~~~~ P3565 [POI2014] HOT-Hotels ~~~~~ 总题单链接 思路 ~~~~~ 设 g [ u ] [ i ] g[u][i] g[u][i] 表示在 u u u 的子树内,距离 u u u 为 i i i 的点的个数。 ~~~~~ 设 d p [ u ] [ i ] dp[u][i] dp[u][i] 表示: u u u 的子树内存在两个点 x , …...