赛灵思 ZYNQ UltraScale+ MPSoC Petalinux驱动开发:Linux字符驱动开发

news2024/11/26 16:55:57

在这里插入图片描述

目录

    • 赛灵思 ZYNQ UltraScale+ MPSoC:Linux字符驱动开发
      • 1、Linux驱动程序简介
      • 2、Linux字符设备开发步骤
        • 2.1、系统调用
        • 2.2、驱动模块的加载与卸载
          • 2.2.1、驱动加载/卸载方式:
          • 2.2.2、驱动注册函数和卸载注册函数
          • 2.2.3、字符设备注册与注销
          • 2.2.4、实现设备操作函数
      • 3、字符设备驱动实验
        • 3.1、硬件环境
        • 3.2、LED字符设备驱动编写
        • 3.3、将驱动模块添加到系统中
        • 3.4、Makefile单独编写驱动
        • 3.5、编写应用程序
        • 3.6、测试程序

赛灵思 ZYNQ UltraScale+ MPSoC:Linux字符驱动开发

1、Linux驱动程序简介

Linux驱动可分为三类:字符设备驱动、块设备驱动、网络设备驱动。

字符设备是Linux驱动中最基本的一类设备驱动,字符设备就是一个一个字节,按照字节流进行读写的设备,读写数据是分先后顺序的,常见的字符设备有:LED、按键、I2CSPILCD等。

块设备驱动的特点是它按一定格式存储数据,具体的格式由文件系统决定;通常以存储设备EMMCFLASHSD卡、EEPROM等。

网络设备驱动与字符设备和块设备有很大区别,应用程序和网络设备驱动之间的驱动是由内核提供的一套数据包传输函数代替了open()、read()、write()函数;WiFi、以太网等属于网络设备。

Linux应用程序对驱动程序的调用流程如下:

在这里插入图片描述

①、应用程序调用库函数提供的open()函数打开某个设备文件;

②、库根据open()函数的输入参数引起CPU异常,进入内核;

③、Linux内核的异常处理函数根据输入参数找到相应的驱动程序,返回文件句柄给库,库函数再返回给应用程序;

④、应用程序再使用得到的文件句柄调用write()、read()等函数发出控制指令;

⑤、库根据write()、read()等函数的输入参数引起CPU异常,进入内核;

⑥、内核的异常处理函数根据输入参数调用相应的驱动程序执行相应的操作。

应用程序运行宇用户空间,驱动程序运行与内核空间。Linux系统可以通过MMU限制应用程序运行于某个内存块中,以避免这个应用程序出现错误导致整个系统崩溃。运行于内核空间的驱动程序属于系统的一部分。

2、Linux字符设备开发步骤

Linux下实现设备驱动的步骤大致如下:

①、查看原理图以及数据手册,了解设备操作方法;

②、修改设备树文件;

③、套用与设备相近的框架,或找到内核中相似设备的驱动代码直接修改,实现驱动程序的初始化以及操作函数;

④、将驱动编译进内核或单独编译加载驱动;

⑤、编写应用程序测试驱动程序。

2.1、系统调用

系统调用即设备操作函数,是字符设备驱动的核心。在内核文件include/linux/fs.h中定义了数据结构体 file_operations,包括了所有内核驱动操作函数:

 struct file_operations {
 	struct module *owner;
	 loff_t (*llseek) (struct file *, loff_t, int);
	 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
 	ssize_t (*write) (struct file *, const char __user *, size_t,loff_t *);
 	ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
 	ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
 	int (*iterate) (struct file *, struct dir_context *);
 	unsigned int (*poll) (struct file *, struct poll_table_struct *);
 	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
 	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
 	int (*mmap) (struct file *, struct vm_area_struct *);
 	int (*mremap)(struct file *, struct vm_area_struct *);
 	int (*open) (struct inode *, struct file *);
 	int (*flush) (struct file *, fl_owner_t id);
 	int (*release) (struct inode *, struct file *);
 	int (*fsync) (struct file *, loff_t, loff_t, int datasync);
 	int (*aio_fsync) (struct kiocb *, int datasync);
 	int (*fasync) (int, struct file *, int);
 	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t,loff_t *, int);
 	unsigned long (*get_unmapped_area)(struct file *, unsigned long,
	unsigned long, unsigned long, unsigned long);
 	int (*check_flags)(int);
 	int (*flock) (struct file *, int, struct file_lock *);
 	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,loff_t *, size_t, unsigned int);
 	ssize_t (*splice_read)(struct file *, loff_t *, struct
	pipe_inode_info *, size_t, unsigned int);
 	int (*setlease)(struct file *, long, struct file_lock **, void **);
 	long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);
 	void (*show_fdinfo)(struct seq_file *m, struct file *f);
 	#ifndef CONFIG_MMU
 	unsigned (*mmap_capabilities)(struct file *);
 	#endif
 };

file_operation 结构体中有如下几个比较重要的、常用的函数:

owner 拥有该结构体的模块的指针,一般设置为 THIS_MODULE

read 函数用于读取设备文件;

write 函数用于向设备文件写入(发送)数据;

poll 是个轮询函数,用于查询设备是否可以进行非阻塞的读写;

open 函数用于打开设备文件;

release 函数用于释放(关闭)设备文件,与应用程序中的 close 函数对应。

2.2、驱动模块的加载与卸载

2.2.1、驱动加载/卸载方式:

Linux驱动有两种运行方式:第一种将驱动编译进内核中,Linux内核启动时就会自动运行驱动程序;第二种是将驱动编译成模块(Linux下驱动模块扩展名为.ko),当Linux启动后使用insmod命令加载驱动模块,这种方式方便调试。

Linux驱动相关加载/卸载相关命令:

驱动加载命令:insmodmodprobe

insmod:是最简单的驱动模块加载命令,用于加载指定的.ko模块;如:

	insomd led.ko

insmod命令的缺点是:不能解决模块的依赖关系,如key.ko驱动依赖led.ko,就必须先加载led.ko模块。

modprobe:modprobe会自动分析模块的依赖关系,将所需要的依赖模块加载到内核中;主要智能在提供了模块依赖性分析、错误检查、错误报告等。

驱动卸载命令:rmmodmodprobe -r

rmmod:用于卸载指定驱动模块;如:

	rmmod led.ko

modprobe -r:可用于卸载驱动模块,但需注意:使用modprobe -r 命令卸载驱动会将驱动所依赖的其他驱动模块一起卸载。

总结:可使用modprobe命令加载驱动模块,使用rmmod命令卸载驱动。

2.2.2、驱动注册函数和卸载注册函数

注册函数:module_init(xxx_init)

module_init 函数用来向Linux内核注册一个模块加载函数,参数xxx_init即需要注册的具体函数;使用insmod命令加载驱动模块时就会调用驱动注册函数。

卸载注册函数:module_exit(xxx_exit)

module_exit函数用来向Linux内核注册模块卸载函数,参数xxx_exit参数即具体的卸载函数,当调用rmmod命令时,就会调用module_exit函数。

字符设备驱动模块加载和卸载模板:

/* 驱动入口函数 */
static int __init xxx_init(void)
{
	/* 入口函数具体内容 */
	return 0;
}

static void __exit xxx_exit(void)
{
	/* 出口函数具体内容 */
}

module_init(xxx_init);
module_exit(xxx_exit);
2.2.3、字符设备注册与注销

对应字符设备,当驱动模块加载成功后需要注册字符设备,卸载驱动模块时也需要注销字符设备。字符设备的注册和注销函数原型如下:

static inline int register_chrdev(unsigned int major, const char *name,
								  const struct file_operations *fops)
								  
static inline void unregister_chardev(unsigned int major,const char *name)		

register_chrdev函数用于注册字符设备,参数如下:

major:主设备号,Linux下每个设备都有设备号,设备号分为主设备号和次设备号两部分;

name:设备名称,指向一串字符串;

fops:结构体file_operations类型指针,指向设备的操作函数集合变量;

unregister_chardev函数用户注销字符设备,参数如下:

major:要注销的设备对应的主设备号;

name:要注销的设备对应的设备号。

static struct file_operations test_fops;

static int __init xxx_init(void)
{
	/* 入口函数具体内容 */
	int retvalue = 0;
    
    /* 注册字符设备驱动 */
    retvalue = register_chardev(200,"chrtest",&test_fops);
    if(retvalue < 0{
        /* 字符设备注册失败,自行处理 */
    }
    return 0;
}

/* 驱动出口函数 */
static void __exit xxx_exit(void)
{
    /* 注销字符设备驱动 */
    unregister_chrdev(200,"chrtest");
}

/* 驱动入口和出口函数 */
module_init(xxx_init);
module_exit(xxx_exit);

Linux设备号

每个设备文件都有主次设备号major,主设备号是唯一的,每个主设备下有次设备号minor,次设备号在这个设备下也是唯一的。在Linux系统下使用如下命令可以查看已被注册的主设备号:

cat/proc/devices
2.2.4、实现设备操作函数

file_operations结构体就是设备的具体操作函数;需要对该结构体变量进行初始化,即初始化其中的open、release、readwrite等具体的设备操作函数。再添加驱动描述信息:

MODULE_LICENSE("GPL");

字符设备的驱动框架如下:

/* 驱动名称 */
#define DEVICE_NAME 	"gpio_leds"

/* 驱动主设备号 */
#define GPIO_LED_MAJOR	200

/* open 函数实现,对应到Linux系统调用函数的open函数 */
static int gpio_leds_open(struct inode_p, struct file *file_p)
{
    return 0;
}

/* write函数实现,对应到Linux系统调用函数的write函数 */
static ssize_t gpio_leds_write(struct file *file_p, const char __user *buf, size_t led, loff_t *loff_t_p)
{
    return 0;
}

/* release函数实现,对应到Linux系统调用函数的close函数 */
static int gpio_leds_release(struct inode *inode_p, struct file *file_p)
{
    return 0;
}

/* file_operations结构体申明,是open、write实现函数与系统调用函数对应的关键 */
static struct file_operations gpio_leds_fops = {
    .owner		=	THIS_MODULE,
    .open		=	gpio_leds_open,
    .write		=	gpio_leds_write,
    .release	=	gpio_leds_release,
};

/* 模块加载时调用的入口函数 */
static int __init gpio_led_init(void)
{
    int ret;
    /* 通过模块主设备号、名称、模块带有的功能函数来注册模块 */
    ret = register_chrdev(GPIO_LED_MAJOR,DEVICE_NAME,&gpio_leds_fops);
    if(ret < 0)
    {
        return ret;
    }
    else
    {
        
    }
    return 0;
}

/* 卸载模块函数 */
static void __exit gpio_led_exit(void)
{
    /* 注销模块,释放模块对这个设备号和名称的占用 */
    unregister_chrdev(GPIO_LED_MAJOR,DEVICE_NAME);
}

/* 注册模块入口和出口函数 */
module_init(gpio_led_init);
module_exit(gpio_led_exit);

/* 添加LICENSE信息 */
MODULE_LICENSE("GPL");

3、字符设备驱动实验

3.1、硬件环境

通过编写板子上PS端的MIO实现LED设备驱动,通过驱动可控制LED点亮和熄灭。

PSLED使用的是MIO41引脚;查看UG1085GPIO手册可知:GPIO寄存器基地址为0xFF0A0000

在这里插入图片描述

由上图可知,MIO41属于Bank1,控制GPIO需要三步:使能、设置方向、控制输出,Bank1的使能寄存器OEN_1:0xFF0A0248、方向寄存器DIRM_1:0xFF0A0244、控制寄存器DATA_1:0xFF0A0044

3.2、LED字符设备驱动编写

led_drv.c

#include <linux/module.h>  
#include <linux/kernel.h>  
#include <linux/fs.h>  
#include <linux/init.h>  
#include <linux/ide.h>  
#include <linux/types.h>  
  
/* 驱动名称 */  
#define DEVICE_NAME       "gpio_leds"  
/* 驱动主设备号 */  
#define GPIO_LED_MAJOR    200  
  
/* gpio寄存器虚拟地址 */  
static unsigned long gpio_add_minor;  
/* gpio寄存器物理基地址 */  
#define GPIO_BASE         0xFF0A0000  
/* gpio寄存器所占空间大小 */  
#define GPIO_SIZE         0x1000  
/* gpio方向寄存器 */  
#define GPIO_DIRM_1       (unsigned int *)(0x0000000000000244 + (unsigned long)gpio_add_minor)  
/* gpio使能寄存器 */   
#define GPIO_OEN_1        (unsigned int *)(0x0000000000000248 + (unsigned long)gpio_add_minor)  
/* gpio控制寄存器 */  
#define GPIO_DATA_1       (unsigned int *)(0x0000000000000044 + (unsigned long)gpio_add_minor)       
  
/* open函数实现, 对应到Linux系统调用函数的open函数 */  
static int gpio_leds_open(struct inode *inode_p, struct file *file_p)  
{  
    printk("gpio_test module open\n");  
      
    return 0;  
}  
  
  
/* write函数实现, 对应到Linux系统调用函数的write函数 */  
static ssize_t gpio_leds_write(struct file *file_p, const char __user *buf, size_t len, loff_t *loff_t_p)  
{  
    int rst;  
    char writeBuf[5] = {0};  
      
    printk("gpio_test module write\n");  
  
    rst = copy_from_user(writeBuf, buf, len);  
    if(0 != rst)  
    {  
        return -1;    
    }  
      
    if(1 != len)  
    {  
        printk("gpio_test len err\n");  
        return -2;  
    }  
    if(1 == writeBuf[0])  
    {  
        *GPIO_DATA_1 |= 0x00004000;   
        printk("gpio_test ON *GPIO_DATA_1 = 0x%X\r\n", *GPIO_DATA_1);  
    }  
    else if(0 == writeBuf[0])  
    {  
        *GPIO_DATA_1 &= 0xFFFFBFFF; 
        printk("gpio_test OFF *GPIO_DATA_1 = 0x%X\r\n", *GPIO_DATA_1); 
    }  
    else  
    {  
        printk("gpio_test para err\n");  
        return -3;  
    }  
      
    return 0;  
}  

/* release函数实现, 对应到Linux系统调用函数的close函数 */  
static int gpio_leds_release(struct inode *inode_p, struct file *file_p)  
{  
    printk("gpio_test module release\n");  
    return 0;  
}  
	  
/* file_operations结构体声明, 是上面open、write实现函数与系统调用函数对应的关键 */  
static struct file_operations gpio_leds_fops = {  
    .owner   = THIS_MODULE,  
    .open    = gpio_leds_open,  
    .write   = gpio_leds_write,    
    .release = gpio_leds_release,   
};  
  
/* 模块加载时会调用的函数 */  
static int __init gpio_led_init(void)  
{  
    int ret;  
      
    /* 通过模块主设备号、名称、模块带有的功能函数(及file_operations结构体)来注册模块 */  
    ret = register_chrdev(GPIO_LED_MAJOR, DEVICE_NAME, &gpio_leds_fops);  
    if (ret < 0)   
    {  
        printk("gpio_led_dev_init_ng\n");  
        return ret;  
    }  
    else  
    {  
        /* 注册成功 */ 
        printk("gpio_led_dev_init_ok\n");  
        /* 把需要修改的物理地址映射到虚拟地址 */
        gpio_add_minor = ioremap_wc(GPIO_BASE, GPIO_SIZE);
        printk("gpio_add_minor = 0x%lX\n", gpio_add_minor); 
        printk("GPIO_DIRM_1    = 0x%lX\n", (unsigned long)GPIO_DIRM_1);
        printk("GPIO_OEN_1     = 0x%lX\n", (unsigned long)GPIO_OEN_1);

        /* MIO_0设置成输出 */  
        *GPIO_DIRM_1 |= 0x00004000;  
        /* MIO_0使能 */  
        *GPIO_OEN_1  |= 0x00004000;  
          
        printk("*GPIO_DIRM_1   = 0x%X\n", *GPIO_DIRM_1);
        printk("*GPIO_OEN_1    = 0x%X\n", *GPIO_OEN_1);
    }  
    return 0;  
}  
  
/* 卸载模块 */  
static void __exit gpio_led_exit(void)  
{  
    *GPIO_OEN_1 &= 0xFFFFBFFF;  
       
    /* 释放对虚拟地址的占用 */  
    iounmap(gpio_add_minor); 
    /* 注销模块, 释放模块对这个设备号和名称的占用 */  
    unregister_chrdev(GPIO_LED_MAJOR, DEVICE_NAME);
	
    printk("gpio_led_dev_exit_ok\n");  
}  
  
/* 标记加载、卸载函数 */  
module_init(gpio_led_init);  
module_exit(gpio_led_exit);  
  
/* 驱动描述信息 */  
MODULE_AUTHOR("kevin");  
MODULE_ALIAS("gpio_led");  
MODULE_DESCRIPTION("GPIO LED driver Test");  
MODULE_VERSION("v1.0");  
MODULE_LICENSE("GPL");  

ioremap_wc()函数用于把物理地址映射到虚拟地址。在Linux中由于MMU内存映射的关系,无法直接操作物理地址,而需把物理地址映射到虚拟地址上在操作对应的虚拟地址。ioremap_wc()定义在头文件arch/arm/include/asm/io.h中。

#define ioremap(cookie.size) __arm_ioremap((cookie),(size),MT_DEVICE)

ZU5EV为64位SOC,在64位系统中使用ioremap_wc(),在32位系统中使用oremap()。

3.3、将驱动模块添加到系统中

1、在petalinux工程目录下,使用如下命令添加新驱动:

petalinux-create -t modules --name lef_drc

在这里插入图片描述

2、将驱动内容拷贝到petalinux模块下,在rootfs中添加驱动

petalinux-config -c rootfs

在这里插入图片描述
在这里插入图片描述

3、编译系统

petalinux-build

3.4、Makefile单独编写驱动

新建Makefile文件

modname: = ps-led
obj-m: = $(modname).o

PWD := $(shell pwd)
MAKE := make
/* 内核地址 */
KERNELDIR =

CROSS_COMPILE = aarch64-linux-gnu-ARCH=arm64

all:
	$(MAKR) ARCH=$(ARCH) CROSS_COMPILE = $(CROSS_COMPILE) -C $(KERNELDIR)
M=$(PWD) modules

clean:
	rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions
	
.PHONY:all clean

使用make编译生成.ko文件

3.5、编写应用程序

led_app.c

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

 int main(int argc, char **argv)
 {
 int fd;
 char buf;

 if(3 != argc)
 {
 printf("none para\n");
 return -1;
 }

 fd = open(argv[1], O_RDWR);
 if(fd < 0)
 {
 printf("Can't open file %s\r\n", argv[1]);
 return -1;
 }

 if(!strcmp("on",argv[2]))
 {
 printf("ps_led1 on\n");
 buf = 1;
 write(fd, &buf, 1);
 }
 else if(!strcmp("off",argv[2]))
 {
 printf("ps_led1 off\n");
 buf = 0;
 write(fd, &buf, 1);
 }
 else
 {
 printf("wrong para\n");
 return -2;
 }

 close(fd);
 return 0;
 }

编译得到可执行文件:led_app

3.6、测试程序

1、将可执行文件添加到Linux系统中

2、加载驱动模块 insmod new-led-drv.ko

3、创建设备文件:

/* 模板:mknod /dev/xxx type major minor */
mknod /dev/ps-led c 200 0

3、运行应用程序:./led_app

printf("请关注微信公众号:Kevin的学习站,关于AUTSAR和自动驾驶嵌入式相关的文章!")

赛灵思-Zynq UltraScale+ MPSoC学习笔记汇总

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

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

相关文章

遥感云大数据在灾害、水体与湿地领域典型案例实践及GPT模型应用

近年来遥感技术得到了突飞猛进的发展&#xff0c;航天、航空、临近空间等多遥感平台不断增加&#xff0c;数据的空间、时间、光谱分辨率不断提高&#xff0c;数据量猛增&#xff0c;遥感数据已经越来越具有大数据特征。遥感大数据的出现为相关研究提供了前所未有的机遇&#xf…

GRPC C++ windows下的简易安装方法

最近因为想给Llama.cpp加一个grpc入口&#xff0c;折腾了一圈GRPC运行时的安装&#xff0c;起初参考GRPC官方的Build from source&#xff0c;未果。 主要原因是基于cmake的安装和调用遭遇到几次大的问题。 一是vscode编译器集成的问题&#xff0c;二是cmake的find_package的…

C++入门--初步认识类和对象

0.前言 前面几章&#xff0c;我们一起学习了C和C语言的不同之处&#xff0c;已经算是半只脚迈入了C的“门槛”&#xff0c;本章让我们继续学习C的类和对象。 1.面向对过程和面向对象的初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&…

【网络协议详解】——电子邮件系统协议(学习笔记)

目录 &#x1f552; 1. 电子邮件系统概述&#x1f552; 2. 简单邮件传送协议SMTP&#x1f552; 3. SMTP协议的命令和响应&#x1f558; 3.1 命令&#x1f564; 3.1.1 HELO&#x1f564; 3.1.2 MAIL FROM&#x1f564; 3.1.3 RCPT TO&#x1f564; 3.1.4 DATA&#x1f564; 3.1.…

【软件设计与体系结构】 软件体系结构风格

软件体系结构&#xff08;Software Architecture&#xff09; 软件体系结构&#xff08;Software Architecture&#xff09;包括构成系统的设计元素的描述、 设计元素 之间的交互、 设计元素的组合模式以及在这些模式中的约束。 定义 软件体系结构表示系统的框架结构&#xf…

IIC接口

一、IIC总线简介 IIC总线是由飞利浦公司推出的一种串行、同步、半双工通信协议。它由两条线组成&#xff0c;时钟线&#xff08;SCL&#xff09;和数据线&#xff08;SDA&#xff09;。主机产生通信用的时钟&#xff0c;可以产生起始信号和结束信号来开始或者结束一次通信。 …

OFGF光流引导特征:用于视频动作识别的快速且稳健的运动表示【含源码】

论文地址:https://openaccess.thecvf.com/content_cvpr_2018/papers/Sun_Optical_Flow_Guided_CVPR_2018_paper.pdf 这个 repo 包含论文的实现代码: Optical Flow Guided Feature: A Fast and Robust Motion Representation for Video Action Recognition,Shuyang Sun,Zh…

基于MATLAB的数字滤波器语音信号去噪

文章目录 一、滤波器的种类及简介二、设计流程三、滤波器设计实现与结果仿真参考文献基于MATLAB的FPR滤波器设计源代码 本课程设计通过分析FIR滤波器的基本原理&#xff0c;在MATLAB环境下利用窗函数法设计出FIR滤波器,实现FIR滤波器的仿真。首先是采集一段语音信号&#xff0c…

C++高级数据结构——ST表(倍增表)

从上次写文章到现在已经27天了&#xff0c;将近一个月蒟蒻没有更新了。 最近学的ST表太难理解了&#xff0c;再加上忙&#xff0c;一直没时间…… ----------------------------------------------------------------------------------------------------------------------…

Tarball管理

文章目录 Tarball管理Tarball安装的基本步骤一般 Tarball 软件安装的建议事项 Tarball管理 从源代码的说明我们知道制作一个二进制程序需要很多东西&#xff0c;这包括下面这些基础的软件。 gcc或cc等C语言编译器make及autoconfig等软件需要内核提供的Library以及相关的inclu…

win11使用命令行建立wifi热点,并可以设定名称密码等

主要是想自动化的实现打开wifi热点,ssid和wifi密码可控!手机设定比较简单,但是用程序行来设定还真是比较麻烦。 查了一下,有人使用netsh 无法解决,也就是说无法使用如下命令启动移动热点: netsh wlan set hostednetwork mode=allow ssid=wifi888 key=88888888 netsh wl…

信息安全实践1.2(重放攻击)

前言 这个实验是看一本书做的&#xff0c;就是李华峰老师的书——《Metasploit Web 渗透测试实战》&#xff0c;我之前写过一篇Slowloris DoS攻击的博客&#xff0c;也是看这本书写的&#xff0c;总的来说&#xff0c;有用处。这篇博客其实也只是很浅显的去做一下重放攻击。 要…

PyTorch 深度学习 || 专题二:PyTorch 编程基础

PyTorch 编程基础 文章目录 PyTorch 编程基础1. backword 求梯度2. 常用损失函数2.1 均方误差损失函数2.2 L1范数误差损失函数2.3 交叉熵损失函数 3. 优化器 1. backword 求梯度 import torchw torch.tensor([1.], requires_gradTrue) x torch.tensor([2.], requires_gradTr…

R实践——【rgplates】安装、介绍、入门

【rgplates】安装、介绍、入门 1. rgplates 安装1.1 easy way1.2 备案方法 2. rgplates 介绍3. rgplates 在线方法入门3.1 加载rgplates3.2 板块重建3.3 独立的地点坐标3.3.1 单个现存坐标点3.3.2 单个点的古坐标3.3.3 多个点的古坐标 3.4 现今的海岸线3.5 其他的重建模型3.6 在…

JMeter 性能测试基本过程及示例

jmeter 为性能测试提供了一下特色&#xff1a; 2023年最新出炉性能测试教程&#xff0c;真实企业性能压测全流程项目实战训练大合集&#xff01;_哔哩哔哩_bilibili2023年最新出炉性能测试教程&#xff0c;真实企业性能压测全流程项目实战训练大合集&#xff01;共计11条视频&…

javascript获取对象的键名列表、键值列表

Object.keys&#xff1a;获取对象的键名列表 Object.values&#xff1a;获取对象的键值列表 <script>var obj {name: 1,age: 2,order: 3}const klist Object.keys(obj)const vals Object.values(obj)console.log(obj, obj)console.log(键名列表, klist)console.log(键…

STM32F4_位带操作

目录 1. 位带简介 2. 别名区地址的计算 2.1 合并计算 3. 位带操作访问ODR和IDR寄存器 4. GPIOB->MODER&~(3<<(9*2));GPIOB->MODER|0<<9*2 / GPIOB->MODER&~(3<<(9*2));GPIOB->MODER|1<<9*2 位带操作在写单片机程序时&#xf…

springboot+vue 刘老师

课程内容 前端&#xff1a;vue elementui 后端&#xff1a;springboot mybatisplus 公共云部署 ------boot-------- 热部署 不用devtools&#xff0c;交给jrebel工具 RequestMapping ​ 参数 value 路径 method 方法consumes 请求媒体类型 如 application/jsonproduces …

DJ5-7 缓冲区管理

目录 5.7.1 缓冲的引入 5.7.2 单缓冲和双缓冲 1、单缓冲&#xff08;Single Buffer&#xff09; 2、双缓冲&#xff08;Double Buffer&#xff09; 3、双机通信时缓冲区的设置 5.7.3 循环缓冲 1、循环缓冲的组成 2、循环缓冲区的使用 3、进程同步 5.7.4 缓冲池 …

Spring Security源码剖析从入门到精通.跟学尚硅谷

1.1 概要 Spring 是非常流行和成功的 Java 应用开发框架&#xff0c;Spring Security 正是 Spring 家族中的成员。Spring Security 基于 Spring 框架&#xff0c;提供了一套 Web 应用安全性的完整解决方案。 正如你可能知道的关于安全方面的两个主要区域是“认证”和“授权”…