Linux 中断实验

news2024/9/20 15:17:58

目录

一、Linux 中断简介

上半部与下半部

二、添加设备树

三、编写驱动

1、定义宏

 2、编写一个key结构体

3、imx6uirq设备添加成员 

​编辑4、按键中断处理函数

5、按键初始化

6、在驱动入口添加初始化

7、 驱动出口函数

 代码如下

四、利用定时器进行消抖处理

1、添加定时器

 2、修改中断处理函数

3、添加定时器处理函数

4、在按键初始化函数最后添加初始化定时器

 5、驱动出口函数添加删除定时器

五、编写测试app

1、添加原子操作

2、初始化原子变量

3、按下和释放操作

4、读函数操作

总体代码如下


一、Linux 中断简介

在 Linux 内核中要想使用某个中断是需要申请的,使用完成以后就要释放掉相应的中断,申请中断的时候需要设置中断处理函数,还有设置使能中断与禁止

上半部与下半部

有些资料中也将上半部和下半部称为顶半部和底半部。

上半部:上半部就是中断处理函数,那些处理过程比较快,不会占用很长时间的处理就可以放在上半部完成。
下半部:如果中断处理过程比较耗时,那么就将这些比较耗时的代码提出来,交给下半部去执行,这样中断处理函数就会快进快出。
至于哪些代码属于上半部,哪些代码属于下半部并没有明确的规定,如果要处理的内容不希望被其他中断打断、处理的任务对时间敏感或处理的任务与硬件有关,那么可以放到上半部,其余以外的其他任务,优先考虑放到下半部

二、添加设备树

打开原理图找到KEY

 可以看到KEY0是接到UART1 CTS上

打开参考手册,找到IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B

看到是可以复用为GPIO1_IO18的

根据之前key驱动实验编写的key节点,添加 184-185两行

184行, 指定父中断,也就是中断控制器,因为key复用为GPIO1_IO18,所以为gpio1

185行,设置中断源,指定中断号,触发方式。因为复用GPIO1_IO18,所以为18,

        IRQ_TYPE_EDGE_BOTH 定义在文件 include/linux/irq.h 中

 IRQ_TYPE_EDGE_BOTH 表示上升沿和下降沿同时有效,相当于KEY0 按下和释放都会触发中断

添加完成之后编译设备树,用此设备树启动

三、编写驱动

导入模板,修改makefile

1、定义宏

 2、编写一个key结构体

irq_desc为中断描述符,这里是key,所以用irq_keydesc 

3、imx6uirq设备添加成员 

在imx6uirq设备中使用,用数组的形式主要是方便添加多个按键

4、按键中断处理函数

实现key结构体中的按键中断处理函数

71行,中断处理函数格式如下

irqreturn_t (*irq_handler_t) (int, void *)

 第一个参数是要中断处理函数要相应的中断号。第二个参数是一个指向 void 的指针,也就是个通用指针,用于区分共享中断的不同设备,也可以指向设备数据结构。中断处理函数的返回值为 irqreturn_t 类型。

73行,dev_id指向dev的设备,也就是imx6uirq

74行,获取gpio的值

5、按键初始化

 

 88行,通过路径查找设备树节点

93-94行,通过循环来进行获取关于节点属性

100-103行,通过循环初始化名字数组;sprintf()用来作格式化的输出;申请使用gpio

109行,设置gpio输出

111行和113行作用一样,都是获取中断号,前者只能利用gpio获取,后者利用通过属性索引获取

116行,设置key0的中断处理函数

117行,设置key0的按键值

120行,在 Linux 内核中要想使用某个中断是需要申请的, request_irq 函数用于申请中断,request_irq函数可能会导致睡眠,因此不能在中断上下文或者其他禁止睡眠的代码段中使用 request_irq 函数。 request_irq 函数会激活(使能)中断,所以不需要我们手动去使能中断, request_irq 函数原型如下:

int request_irq(unsigned int irq
                        irq_handler_t handler,
                        unsigned long flags,
                        const char * name,
                        void * dev):

irq:要申请中断的中断号。
handler:中断处理函数,当中断发生以后就会执行此中断处理函数。
flags:中断标志,可以在文件 include/linux/interrupt.h 里面查看所有的中断标志。这里使用上升沿和下降沿触发

name:中断名字,设置以后可以在/proc/interrupts 文件中看到对应的中断名字。
dev: 如果将 flags 设置为 IRQF_SHARED 的话, dev 用来区分不同的中断,一般情况下将dev 设置为设备结构体, dev 会传递给中断处理函数 irq_handler_t 的第二个参数。
返回值: 0 中断申请成功,其他负值 中断申请失败,如果返回-EBUSY 的话表示中断已经
被申请了
 

6、在驱动入口添加初始化

7、 驱动出口函数

 代码如下

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/atomic.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/irq.h>
#include <linux/interrupt.h>

#define IMX6UIRQ_CNT 1
#define IMX6UIRQ_NAME "imx6uirq"
#define KEY_NUM 1       /* 按键数量 	*/
#define KEY0VALUE 0X01  /* KEY0按键值 	*/
#define INVAKEY 0XFF    /* 无效的按键值 */

/*key结构体*/
struct irq_keydesc{
    int gpio;  /*io编号*/
    int irqnum; /*中断号*/
    unsigned char value; /*键值*/
    char name[10]; /*名字*/
    irqreturn_t(*handler) (int ,void *); /*中断处理函数*/
};

struct imx6uirq_dev{
    dev_t devid;
    int major;
    int minor;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct device_node *nd;
    struct irq_keydesc irqkey[KEY_NUM];
}imx6uirq;
static int imx6uirq_open(struct inode *inode, struct file *filp){
    filp->private_data = &imx6uirq;
    return 0;
}
static ssize_t imx6uirq_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    return 0;
}
static ssize_t imx6uirq_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	return 0;
}
static int imx6uirq_release(struct inode *inode, struct file *filp){
     return 0;
}

static const  struct file_operations imx6uirq_fops = {
    .owner	=   THIS_MODULE,
    .open   =   imx6uirq_open,
    .read   =   imx6uirq_read,
    .write  =   imx6uirq_write,
    .release =  imx6uirq_release,
};
/*按键中段处理函数*/
static irqreturn_t key0_handler(int irq,void *dev_id){
    int value = 0;
    struct imx6uirq_dev * dev = dev_id;
    value = gpio_get_value(dev->irqkey[0].gpio);
    if(value == 0){
        /*按下*/
    printk("KEY0 push\r\n");
    }else if(value == 1){
        /*释放*/
        printk("KEY0 release\r\n");
    }
    return IRQ_HANDLED;
}
/*按鍵初始化*/
static int keyio_init(struct imx6uirq_dev *dev){
    int i,ret =0 ;
    /*按鍵初始化*/
    dev->nd = of_find_node_by_path("/key");
    if(dev->nd == NULL){
        ret = -EINVAL;
        goto fail_nd;
    }
    for(i=0;i<KEY_NUM;i++){
        dev->irqkey[i].gpio = of_get_named_gpio(dev->nd,"key-gpios",i);
        if(dev->irqkey[i].gpio < 0){
            ret = -EINVAL;
            goto fail_gpio;
        }
    }
    for(i=0;i<KEY_NUM;i++){
        memset(dev->irqkey[i].name,0,sizeof(dev->irqkey[i].name));
        sprintf(dev->irqkey[i].name,"KEY%d",i);
        ret = gpio_request(dev->irqkey[i].gpio , dev->irqkey[i].name);
        if(ret){
            ret = -EBUSY;
            printk("IO %d can't request\r\n",dev->irqkey[i].gpio);
            goto fail_request;
        }
        gpio_direction_input(dev->irqkey[i].gpio);
        /*获取中断号*/
        dev->irqkey[i].irqnum = gpio_to_irq(dev->irqkey[i].gpio);
#if 0
        dev->irqkey[i].irqnum = irq_of_parse_and_map(dev->nd,i);
 #endif
    }
    dev->irqkey[0].handler = key0_handler;
    dev->irqkey[0].value   = KEY0VALUE;
        /*按键中断初始化*/
    for(i=0;i<KEY_NUM;i++){
        ret = request_irq(dev->irqkey[i].irqnum,dev->irqkey[i].handler,
                            IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING,
                            dev->irqkey[i].name,&imx6uirq);
        if(ret){
            printk("irq %d request failed!\r\n",dev->irqkey[i].irqnum);
            goto fail_irq;
        }
    }
    return 0;
fail_irq:
    for(i=0;i<KEY_NUM;i++){
        gpio_free(dev->irqkey[i].gpio);
    }
fail_request:
fail_gpio:
fail_nd:
    return ret;
}

static int __init imx6uirq_init(void){
    int ret = 0;
    imx6uirq.major = 0;
    if(imx6uirq.major){
        imx6uirq.devid =MKDEV(imx6uirq.major,0);
        ret = register_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT,IMX6UIRQ_NAME);
        if(ret < 0){
            goto fail_devid;
        }
    }else{
        ret = alloc_chrdev_region(&imx6uirq.devid,0,IMX6UIRQ_CNT,IMX6UIRQ_NAME);
        if(ret < 0){
            goto fail_devid;
        }
        imx6uirq.major = MAJOR(imx6uirq.devid);
        imx6uirq.minor = MINOR(imx6uirq.devid);
        printk("imx6uirq major = %d, minor = %d\r\n", imx6uirq.major, imx6uirq.minor);
    }
    imx6uirq.cdev.owner = THIS_MODULE;
    cdev_init(&imx6uirq.cdev, &imx6uirq_fops);
    ret = cdev_add(&imx6uirq.cdev,imx6uirq.devid,IMX6UIRQ_CNT);
    if(ret){
        goto fail_cdevadd;
    }
    imx6uirq.class = class_create(THIS_MODULE,IMX6UIRQ_NAME);
    if(IS_ERR(imx6uirq.class)){
        ret = PTR_ERR(imx6uirq.class);
        goto fail_class;
    }
    imx6uirq.device = device_create(imx6uirq.class,NULL,imx6uirq.devid,NULL,IMX6UIRQ_NAME);
    if(IS_ERR(imx6uirq.device)){
        ret = PTR_ERR(imx6uirq.device);
        goto fail_device;
    }

    /*初始化IO*/
    ret = keyio_init(&imx6uirq);
    if(ret < 0){
        goto fail_keyinit;
    }

    return 0;
fail_keyinit:
    device_destroy(imx6uirq.class,IMX6UIRQ_CNT);
fail_device:
    class_destroy(imx6uirq.class);
fail_class:
    cdev_del(&imx6uirq.cdev);
fail_cdevadd:
    unregister_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT);
fail_devid:
    return ret;
}
static void __exit imx6uirq_exit(void){
    int i=0;
    /*释放中断*/
    for(i=0;i<KEY_NUM;i++){
        free_irq(imx6uirq.irqkey[i].irqnum,&imx6uirq);
    }
    /*释放IO*/
    for(i=0;i<KEY_NUM;i++){
        gpio_free(imx6uirq.irqkey[i].gpio);
    }
    device_destroy(imx6uirq.class,imx6uirq.devid);
    class_destroy(imx6uirq.class);
    cdev_del(&imx6uirq.cdev);
    unregister_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT);
    printk("imx6uirq_exit\r\n");
}

module_init(imx6uirq_init);
module_exit(imx6uirq_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ba che kai qi lai");

编译到开发板上,按下按键0,就会打印相关内容,释放也会,注意此处没做消抖

四、利用定时器进行消抖处理

1、添加定时器

 2、修改中断处理函数

 在进入到中断处理后,定时器处理函数会周期延时20毫秒作消抖处理

3、添加定时器处理函数

消抖后判断是否按下按键

4、在按键初始化函数最后添加初始化定时器

 5、驱动出口函数添加删除定时器

加载驱动进行测试之后,按键按下和释放都会相对准确,在按下和释放速度过快就会打印相同信息的情况

五、编写测试app

1、添加原子操作

2、初始化原子变量

3、按下和释放操作

4、读函数操作

总体代码如下

驱动

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/atomic.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/irq.h>
#include <linux/interrupt.h>

#define IMX6UIRQ_CNT 1
#define IMX6UIRQ_NAME "imx6uirq"
#define KEY_NUM 1       /* 按键数量 	*/
#define KEY0VALUE 0X01  /* KEY0按键值 	*/
#define INVAKEY 0XFF    /* 无效的按键值 */

/*key结构体*/
struct irq_keydesc{
    int gpio;  /*io编号*/
    int irqnum; /*中断号*/
    unsigned char value; /*键值*/
    char name[10]; /*名字*/
    irqreturn_t(*handler) (int ,void *); /*中断处理函数*/
};

struct imx6uirq_dev{
    dev_t devid;
    int major;
    int minor;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct device_node *nd;
    struct irq_keydesc irqkey[KEY_NUM];
    struct timer_list timer;
    atomic_t keyvalue;
    atomic_t releasekey;
}imx6uirq;
static int imx6uirq_open(struct inode *inode, struct file *filp){
    filp->private_data = &imx6uirq;
    return 0;
}
static ssize_t imx6uirq_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    int ret = 0;
    unsigned char keyvalue;
    unsigned char releasekey;
    struct imx6uirq_dev *dev = filp->private_data;
    keyvalue = atomic_read(&dev->keyvalue);
    releasekey = atomic_read(&dev->releasekey);
    if(releasekey){/*有效按键*/
        if(keyvalue & 0x80){
            keyvalue &= ~0x80;
            ret=__copy_to_user(buf,&keyvalue,sizeof(keyvalue));
        }else{
            goto data_error;
        }
        atomic_set(&dev->releasekey,0);/*按下标志清零*/
    }else{
         goto data_error;
    }
    return ret;
data_error:
    return -EINVAL;
}
static ssize_t imx6uirq_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	return 0;
}
static int imx6uirq_release(struct inode *inode, struct file *filp){
     return 0;
}

static const  struct file_operations imx6uirq_fops = {
    .owner	=   THIS_MODULE,
    .open   =   imx6uirq_open,
    .read   =   imx6uirq_read,
    .write  =   imx6uirq_write,
    .release =  imx6uirq_release,
};
/*按键中断处理函数*/
static irqreturn_t key0_handler(int irq,void *dev_id){
    
    struct imx6uirq_dev * dev = dev_id;
    dev->timer.data = (volatile unsigned long)dev_id;
    mod_timer(&dev->timer,jiffies + msecs_to_jiffies(20));/*10ms*/

    return IRQ_HANDLED;
}
/*定时器处理函数*/
static void timer_func(unsigned long arg){
    int value = 0;
    struct imx6uirq_dev *dev = (struct imx6uirq_dev *)arg;
    value = gpio_get_value(dev->irqkey[0].gpio);
    if(value == 0){
        /*按下*/
        atomic_set(&dev->keyvalue,dev->irqkey[0].value);

    }else if(value == 1){
        /*释放*/
        atomic_set(&dev->keyvalue,0x80 | (dev->irqkey[0].value));
        atomic_set(&dev->releasekey,1);
    }

}
/*按鍵初始化*/
static int keyio_init(struct imx6uirq_dev *dev){
    int i,ret =0 ;
    /*按鍵初始化*/
    dev->nd = of_find_node_by_path("/key");
    if(dev->nd == NULL){
        ret = -EINVAL;
        goto fail_nd;
    }
    for(i=0;i<KEY_NUM;i++){
        dev->irqkey[i].gpio = of_get_named_gpio(dev->nd,"key-gpios",i);
        if(dev->irqkey[i].gpio < 0){
            ret = -EINVAL;
            goto fail_gpio;
        }
    }
    for(i=0;i<KEY_NUM;i++){
        memset(dev->irqkey[i].name,0,sizeof(dev->irqkey[i].name));
        sprintf(dev->irqkey[i].name,"KEY%d",i);
        ret = gpio_request(dev->irqkey[i].gpio , dev->irqkey[i].name);
        if(ret){
            ret = -EBUSY;
            printk("IO %d can't request\r\n",dev->irqkey[i].gpio);
            goto fail_request;
        }
        gpio_direction_input(dev->irqkey[i].gpio);
        /*获取中断号*/
        dev->irqkey[i].irqnum = gpio_to_irq(dev->irqkey[i].gpio);
#if 0
        dev->irqkey[i].irqnum = irq_of_parse_and_map(dev->nd,i);
 #endif
    }
    dev->irqkey[0].handler = key0_handler;
    dev->irqkey[0].value   = KEY0VALUE;
        /*按键中断初始化*/
    for(i=0;i<KEY_NUM;i++){
        ret = request_irq(dev->irqkey[i].irqnum,dev->irqkey[i].handler,
                            IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING,
                            dev->irqkey[i].name,&imx6uirq);
        if(ret){
            printk("irq %d request failed!\r\n",dev->irqkey[i].irqnum);
            goto fail_irq;
        }
    }
    /*初始化定时器*/
    init_timer(&imx6uirq.timer);
    imx6uirq.timer.function = timer_func;

    return 0;
fail_irq:
    for(i=0;i<KEY_NUM;i++){
        gpio_free(dev->irqkey[i].gpio);
    }
fail_request:
fail_gpio:
fail_nd:
    return ret;
}

static int __init imx6uirq_init(void){
    int ret = 0;
    imx6uirq.major = 0;
    if(imx6uirq.major){
        imx6uirq.devid =MKDEV(imx6uirq.major,0);
        ret = register_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT,IMX6UIRQ_NAME);
        if(ret < 0){
            goto fail_devid;
        }
    }else{
        ret = alloc_chrdev_region(&imx6uirq.devid,0,IMX6UIRQ_CNT,IMX6UIRQ_NAME);
        if(ret < 0){
            goto fail_devid;
        }
        imx6uirq.major = MAJOR(imx6uirq.devid);
        imx6uirq.minor = MINOR(imx6uirq.devid);
        printk("imx6uirq major = %d, minor = %d\r\n", imx6uirq.major, imx6uirq.minor);
    }
    imx6uirq.cdev.owner = THIS_MODULE;
    cdev_init(&imx6uirq.cdev, &imx6uirq_fops);
    ret = cdev_add(&imx6uirq.cdev,imx6uirq.devid,IMX6UIRQ_CNT);
    if(ret){
        goto fail_cdevadd;
    }
    imx6uirq.class = class_create(THIS_MODULE,IMX6UIRQ_NAME);
    if(IS_ERR(imx6uirq.class)){
        ret = PTR_ERR(imx6uirq.class);
        goto fail_class;
    }
    imx6uirq.device = device_create(imx6uirq.class,NULL,imx6uirq.devid,NULL,IMX6UIRQ_NAME);
    if(IS_ERR(imx6uirq.device)){
        ret = PTR_ERR(imx6uirq.device);
        goto fail_device;
    }

    /*初始化IO*/
    ret = keyio_init(&imx6uirq);
    if(ret < 0){
        goto fail_keyinit;
    }
    /*初始化原子变量*/
    atomic_set(&imx6uirq.keyvalue,INVAKEY);
    atomic_set(&imx6uirq.releasekey,0);
    return 0;
fail_keyinit:
    device_destroy(imx6uirq.class,IMX6UIRQ_CNT);
fail_device:
    class_destroy(imx6uirq.class);
fail_class:
    cdev_del(&imx6uirq.cdev);
fail_cdevadd:
    unregister_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT);
fail_devid:
    return ret;
}
static void __exit imx6uirq_exit(void){
    int i=0;
    /*释放中断*/
    for(i=0;i<KEY_NUM;i++){
        free_irq(imx6uirq.irqkey[i].irqnum,&imx6uirq);
    }
    /*释放IO*/
    for(i=0;i<KEY_NUM;i++){
        gpio_free(imx6uirq.irqkey[i].gpio);
    }
    del_timer_sync(&imx6uirq.timer);
    device_destroy(imx6uirq.class,imx6uirq.devid);
    class_destroy(imx6uirq.class);
    cdev_del(&imx6uirq.cdev);
    unregister_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT);
    printk("imx6uirq_exit\r\n");
}

module_init(imx6uirq_init);
module_exit(imx6uirq_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ba che kai qi lai");

APP

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>


#define CLOSE_CMD _IO(0XEF ,1)  /*关闭命令*/
#define OPEN_CMD _IO(0XEF,2)    /*打开命令*/
#define SETPERIOD_CMD _IO(0XEF,3) /*设置周期*/


int main(int argc, char *argv[])
{
    int fd,ret;
    char *filename;
    unsigned char data;
    
    /*判断命令行输入参数是否正确*/
    if(argc != 2){
        printf("error usage!\r\n");
        return -1;
    }
    /*用指针指向文件*/
    filename = argv[1];
    /*打开文件*/
    fd = open(filename , O_RDWR);
    if(fd < 0){
        printf("file open failed\r\n",filename);
        return -1;
    }
    /*循环读取*/
    while(1){
        ret = read(fd,&data,sizeof(data));
        if(ret<0){

        }else{
            if(data)
                printf(" key vaule = %d\r\n",data);
        }
    }
   
    /*关闭文件*/
    close(fd);

    return 0;
}

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

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

相关文章

Spring Security in Action 第十四章 实现资源服务器端

本专栏将从基础开始&#xff0c;循序渐进&#xff0c;以实战为线索&#xff0c;逐步深入SpringSecurity相关知识相关知识&#xff0c;打造完整的SpringSecurity学习步骤&#xff0c;提升工程化编码能力和思维能力&#xff0c;写出高质量代码。希望大家都能够从中有所收获&#…

ArcGIS中的附件功能

从ArcGIS10起,空间数据库增加了"附件"的功能,可灵活管理与要素相关的附加信息,可以是图像、PDF、文本文档或任意其他文件类型。例如,如果用某个要素表示建筑物,则可以使用附件来添加多张从不同角度拍摄的建筑物照片。 启动附件功能 要想使用附件功能,要素类必…

Docker 中遇到的问题

1&#xff1a;docker-tomcat 篇 第一天启动主机和虚拟机都可以正常访问&#xff0c;晚上睡觉的时候就挂起关机睡觉了&#xff0c;但到了第二天主机访问不了了&#xff0c;ping 也能ping 通&#xff0c;后来停掉容器&#xff0c;重启了虚拟机就好了&#xff0c;就很离谱。 这是成…

Web3CN|Damus刷频背后,大众在期待什么样的去中心化社交?

刚过去的一周&#xff0c;许多人的朋友圈包括Twitter、Faceboo在内都在被一串公钥字母刷屏&#xff0c;其重要起因就是 Twitter 前首席执行官 Jack Dorsey 发推称&#xff0c;&#xff08;2月1日&#xff09;基于去中心化社交协议 Nostr 的社交产品 Damus 和 Amethyst 已分别在…

互联网舆情监测系统的设计研究,TOOM舆情监测系统研究框架?

舆情监测研究分析是指通过对社会公众对某个事件、话题、品牌、政策等的态度和情绪进行收集、处理、分析和评估&#xff0c;帮助政府、企业、媒体等利益相关者及时掌握公众的反应&#xff0c;做好应对危机和制定舆情管理策略的工作&#xff0c;互联网舆情监测系统的设计研究&…

全志V853芯片 如何在Tina V85x平台切换sensor?

目的 V85x某方案目前默认Sensor是GC2053。实际使用时若需要用到GC4663&#xff08;比如wdr功能&#xff09;和SC530AI&#xff08;支持500W&#xff09;&#xff0c;可按如下步骤完成切换。 步骤 下面以GC4663为例&#xff0c;SC530AI按相应方式适配。 Step1 检查Sensor驱动…

Spring Security in Action 第十七章 全局方法安全:预过滤和后过滤

本专栏将从基础开始&#xff0c;循序渐进&#xff0c;以实战为线索&#xff0c;逐步深入SpringSecurity相关知识相关知识&#xff0c;打造完整的SpringSecurity学习步骤&#xff0c;提升工程化编码能力和思维能力&#xff0c;写出高质量代码。希望大家都能够从中有所收获&#…

Rust学习入门--【8】复合类型

复合类型&#xff08;compound type&#xff09; 可以将多个不同类型的值组合为一个类型。 Rust中提供了两种内置的复合数据类型&#xff1a;元组&#xff08;tuple&#xff09;和数组&#xff08;array&#xff09;。 元组类型 元组是一个具有 固定长度 的数据集合 —— 无…

按键输入驱动

目录 一、硬件原理 二、添加设备树 1、创建pinctrl 2、创建节点 3、检查 编译复制 三、修改工程模板​编辑 四、驱动编写 1、添加keyio函数 2、添加调用 3、驱动出口函数添加释放 4、添加原子操作 5、添加两个宏定义 6、初始化原始变量 7、打开操作 8、读操作 总体代…

自启动管理 - Win10

自启动管理 - Win10前言关闭开机自启方案1&#xff1a;在软件中设置方案2&#xff1a;在任务管理器设置方案3&#xff08;不推荐&#xff09;&#xff1a;通过注册表管理方案4&#xff1a;通过第三方工具管理工具1&#xff1a;360安全卫士工具2&#xff1a;Autoruns工具3&#…

性能测试概述

目录 一.什么是性能测试 1.生活中软件存在的性能问题 2.性能测试的概念 3.功能测试和性能测试的区别 4.什么样的软件表现是性能好的表现&#xff0c;什么样的软件是性能不好的表现 二.一个项目为什么要进行性能测试 三.性能测试常见术语以及衡量指标 1.专业术语&#x…

Docker的数据卷管理与容器互联

目录 一、Docker数据管理介绍 二、数据卷 1、数据卷概念 三、数据卷容器 1、数据卷容器的概念 2、数据卷容器示例 四、容器互联 1、容器互联概念 2、容器互联示例 一、Docker数据管理介绍 用户在使用Docker的过程中&#xff0c;往往需要能查看容器内应用产生的数据&…

基于transformer和图卷积网络的人体运动预测时空网络

效果演示&#xff1a; python行为识别行为骨骼框架检测动作识别动作检测行为动作分类近年来&#xff0c;人体运动预测已成为计算机视觉领域的一个活跃研究课题。然而&#xff0c;由于人体运动的复杂性和随机性&#xff0c;它仍然是一个具有挑战性的问题。在以前的工作中&#x…

[golang] 实现 jwt 方式登录

1 Jwt 和 Session 登录方案介绍 JSON Web Token&#xff08;缩写 JWT&#xff09;是目前流行的跨域认证解决方案。 原理是生存的凭证包含标题 header&#xff0c;有效负载 payload 和签名组成。用户信息payload中&#xff0c;后端接收时只验证凭证是否有效&#xff0c;有效就…

【Spark分布式内存计算框架——Spark Core】11. Spark 内核调度(下)

8.5 Spark 基本概念 Spark Application运行时&#xff0c;涵盖很多概念&#xff0c;主要如下表格&#xff1a; 官方文档&#xff1a;http://spark.apache.org/docs/2.4.5/cluster-overview.html#glossary Application&#xff1a;指的是用户编写的Spark应用程序/代码&#x…

leetcode练习二:排序

文章目录排序一、排序算法1.1 冒泡排序1.1.1 算法步骤1.1.2 算法分析1.1.3 代码实现&#xff1a;1.1.4 冒泡排序优化1.2 选择排序1.2.1 算法步骤1.2.2 算法分析1.2.3 代码实现1.3 插入排序1.3.1 算法步骤1.3.2 算法分析1.3.3 代码实现1.4 希尔排序1.4.1 算法步骤1.4.2 算法分析…

【网络基础】DNS是什么

本文不会直接引入复杂枯燥概念&#xff0c;用形象例子通俗讲解&#xff0c;旨在入门理解。 DNS作用 DNS是用来做域名解析的。 相当于把网址翻译成实际ip地址&#xff0c;供其他设备访问。 一个例子 有一个网站的服务器IP地址为1.1.1.1&#xff0c;用电脑访问该网站的话只需…

挂载Samba到Windows系统和Linux系统

1、搭建Samba服务 1.1安装Samba服务 yum -y install samba结果如下&#xff1a; 1.2配置Samba服务 修改Samba服务的配置文件 vim /etc/samba/smb.conf[sambadir]自定义路径 comment Samba Directories自定义描述 path /samba/dir自定义路径 [global]workgroup SAMBAsec…

ElasticSearch-学习笔记-阶段总结(易错点易混淆点归纳)

Java后端-学习路线-笔记汇总表【黑马程序员】ElasticSearch-学习笔记01【ElasticSearch基本介绍】【day01】ElasticSearch-学习笔记02【ElasticSearch索引库维护】ElasticSearch-学习笔记03【ElasticSearch集群】ElasticSearch-学习笔记04【Java客户端操作索引库】【day02】Ela…