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

input子系统框架、外设驱动开发

一、input子系统基本框架

Linux内核为了两个目的:

  1. 简化纯输入类外设(如:键盘、鼠标、游戏杆、轨迹球、触摸屏。。。等等)的驱动开发
  2. 统一输入类外设产生的数据格式(struct input_event),更加方便应用层编程

设计了输入子系统

在这里插入图片描述

事件处理层:接收来自核心层上报的事件,并选择对应的handler(事件处理器 struct input_handler)去处理。内核维护着多个事件处理器对象,每个input_handler对象专门处理一类事件,所有产生同类事件的设备驱动共用同一个handler。

设备驱动层:主要实现获取硬件设备的数据信息(包括触摸屏被按下、按下位置、鼠标移动、键盘按下等等),并转换为核心层定义的规范事件后提交给核心层,该层每个设备对应一个struct input_dev对象,

核心层:负责连接设备驱动层和事件处理层,为设备驱动层提供输入设备驱动的接口(struct input_dev)以及输入设备驱动的注册函数(input_register_device),为事件处理层提供输入事件驱动的接口;通知事件处理层对事件进行处理。

二、驱动开发步骤

/*init或probe函数中:
1. 创建struct input_dev对象input_allocate_device
2. 设置事件类型以及相关参数set_bit
3. 注册struct input_dev对象input_register_device
*//*exit或remove函数中:
1. 注销struct input_dev对象input_unregister_device
2. 销毁struct input_dev对象input_free_device
*//*上报事件两种事件上报方式:1. 对有中断支持的输入设备:在其中断处理函数(上半部或下半部)中上报事件2. 对无中断支持的输入设备:使用workqueue循环定时上报(struct delayed_work)主要函数:input_eventinput_report_absinput_sync
*/

相关接口:

/*_init*/
struct input_dev *input_allocate_device(void)/*创建一个输入设备对象。返回一个指向 input_dev 结构的指针,该结构用于表示输入设备。*/void set_bit(struct input_dev *dev, unsigned long whichbits)/*设置输入设备的事件类型。dev 是输入设备对象的指针,whichbits 是一个位掩码,用于指定事件类型。例如,使用 set_bit(dev, EV_KEY) 可以设置输入设备支持按键事件。whichbits:EV_KEY:按键事件。这个事件类型用于处理键盘、鼠标等输入设备的按键事件EV_ABS:绝对坐标事件。这个事件类型用于处理绝对坐标的事件,例如触摸屏的触摸位置。*/void input_set_abs_params(struct input_dev *dev, unsigned int axis, int min, int max, int fuzz, int flat)/*配置输入设备的绝对坐标参数。dev 是输入设备对象的指针,axis 是要配置的坐标轴(如ABS_X、ABS_Y等),min 和 max 分别是坐标轴的最小值和最大值,fuzz 和 flat 是用于指定坐标轴的模糊度和平坦度参数。*/int input_register_device(struct input_dev *dev)/*注册输入设备到内核。将输入设备对象注册到内核,以便它可以开始上报事件。*//*_exit*/
void input_unregister_device(struct input_dev *dev)//注销输入设备。从内核中注销输入设备,停止事件的上报。
void input_free_device(struct input_dev *dev)//释放输入设备。释放输入设备对象的内存。/*上报事件*/
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)/*上报一个通用输入事件。通常,这个函数用于上报不是绝对坐标或按键事件的事件。dev 是输入设备对象的指针,type 表示事件类型,code 表示事件代码(例如,按键代码),value 表示事件的值。*/void input_report_key(struct input_dev *dev, unsigned int code, int value)/*上报按键事件。dev 是输入设备对象的指针,code 表示按键事件的代码,value 表示按键事件的值(0表示松开,1表示按下)。*/void input_report_abs(struct input_dev *dev, unsigned int code, int value)/*上报绝对坐标事件。dev 是输入设备对象的指针,code 表示绝对坐标事件的代码,value 表示绝对坐标的值。*/void input_sync(struct input_dev *dev)//上报完成后需要调用这些函数来通知系统处理完整事件, 这个函数告诉内核事件已经完整,可以处理了。/*应用层数据类型*/
struct input_event { 		//这是一个用于表示输入事件的结构体。它包含以下字段:struct timeval time; 	//事件的时间戳。__u16 type; 			//事件类型,如 EV_KEY(按键事件)、EV_ABS(绝对坐标事件)等。__u16 code; 			//事件代码,具体表示事件的含义,例如按下哪个键或是哪个绝对坐标轴。__s32 value; 			//事件的值,通常表示按键的状态(按下或松开)或绝对坐标的值。
}

三、key2-input版代码解析

key2.c

#include <linux/module.h>          // Linux内核模块头文件
#include <linux/kernel.h>          // 内核相关功能的头文件
#include <linux/fs.h>              // 文件系统相关功能的头文件
#include <linux/gpio.h>            // GPIO库的头文件
#include <linux/interrupt.h>       // 中断处理相关功能的头文件
#include <linux/of_gpio.h>         // Open Firmware GPIO相关功能的头文件
#include <linux/of_irq.h>          // Open Firmware中断相关功能的头文件
#include <linux/cdev.h>            // 字符设备相关功能的头文件
#include <linux/wait.h>            // 等待队列相关功能的头文件
#include <linux/sched.h>           // 调度相关功能的头文件
#include <linux/poll.h>            // poll相关功能的头文件
#include <linux/mm.h>              // 内存管理相关功能的头文件
#include <linux/input.h>           // 输入子系统相关功能的头文件
#include <linux/delay.h>           // 延时相关功能的头文件
#include <linux/slab.h>            // 内存分配相关功能的头文件
#include <asm/uaccess.h>           // 用户态内核态数据传输相关功能的头文件struct fs4412key2_dev
{struct input_dev *pdev;     // 输入设备结构体指针,用于注册输入事件int gpio;                   // GPIO引脚的编号int irqno;                  // 中断编号
};struct fs4412key2_dev *pgmydev = NULL; // 指向驱动程序数据结构的指针// 中断处理函数,处理按键中断
irqreturn_t key2_irq_handle(int no, void *arg)
{struct fs4412key2_dev *pmydev = (struct fs4412key2_dev *)arg;int status1 = 0;int status2 = 0;// 读取GPIO引脚状态两次,用于防抖status1 = gpio_get_value(pmydev->gpio);mdelay(1);status2 = gpio_get_value(pmydev->gpio);// 如果两次状态不一致,认为是抖动,不处理if (status1 != status2){return IRQ_NONE;}// 根据按键状态生成输入事件if (status1){input_event(pmydev->pdev, EV_KEY, KEY_2, 0); // 按键释放事件input_sync(pmydev->pdev);                   // 同步输入事件}else{input_event(pmydev->pdev, EV_KEY, KEY_2, 1); // 按键按下事件input_sync(pmydev->pdev);                   // 同步输入事件}return IRQ_HANDLED;
}// 模块初始化函数
int __init fs4412key2_init(void)
{int ret = 0;struct device_node *pnode = NULL;// 查找设备树节点pnode = of_find_node_by_path("/mykey2_node");if (NULL == pnode){printk("find node failed\n");return -1;}// 分配驱动程序数据结构内存pgmydev = (struct fs4412key2_dev *)kmalloc(sizeof(struct fs4412key2_dev), GFP_KERNEL);if (NULL == pgmydev){printk("kmalloc for struct fs4412key2_dev failed\n");return -1;}// 从设备树中获取GPIO引脚编号pgmydev->gpio = of_get_named_gpio(pnode, "key2-gpio", 0);// 从设备树中获取中断编号pgmydev->irqno = irq_of_parse_and_map(pnode, 0);// 分配并注册输入设备pgmydev->pdev = input_allocate_device();set_bit(EV_KEY, pgmydev->pdev->evbit);set_bit(KEY_2, pgmydev->pdev->keybit);ret = input_register_device(pgmydev->pdev);// 请求中断处理函数ret = request_irq(pgmydev->irqno, key2_irq_handle, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "fs4412key2", pgmydev);if (ret){printk("request_irq failed\n");input_unregister_device(pgmydev->pdev);input_free_device(pgmydev->pdev);kfree(pgmydev);pgmydev = NULL;return -1;}return 0;
}// 模块卸载函数
void __exit fs4412key2_exit(void)
{// 释放中断free_irq(pgmydev->irqno, pgmydev);// 注销输入设备input_unregister_device(pgmydev->pdev);input_free_device(pgmydev->pdev);// 释放驱动程序数据结构内存kfree(pgmydev);pgmydev = NULL;
}MODULE_LICENSE("GPL"); // 指定模块许可证
module_init(fs4412key2_init); // 指定模块初始化函数
module_exit(fs4412key2_exit); // 指定模块卸载函数

testkey2.c

#include <sys/types.h>
#include <sys/stat.h>
#include <linux/input.h>
#include <fcntl.h>
#include <unistd.h>#include <stdio.h>int main(int argc,char *argv[])
{int fd = -1;struct input_event evt;if(argc < 2){printf("Argument is too few\n");return 1;}/*open*/fd = open(argv[1],O_RDONLY);if(fd < 0){printf("open %s failed\n",argv[1]);return 2;}/*init mpu6050*/while(1){read(fd,&evt,sizeof(evt));if(evt.type == EV_KEY && evt.code == KEY_2){if(evt.value){printf("KEY2 DOWN\n");}else{printf("KEY2 UP\n");}}}/*close*/close(fd);fd = -1;return 0;
}

四、mpu6050-input版代码解析

mpu6050drv.c

#include <linux/module.h>          // Linux内核模块头文件
#include <linux/kernel.h>          // 内核相关功能的头文件
#include <linux/fs.h>              // 文件系统相关功能的头文件
#include <linux/i2c.h>             // I2C总线相关功能的头文件
#include <linux/cdev.h>            // 字符设备相关功能的头文件
#include <linux/wait.h>            // 等待队列相关功能的头文件
#include <linux/sched.h>           // 调度相关功能的头文件
#include <linux/poll.h>            // poll相关功能的头文件
#include <linux/slab.h>            // 内存分配相关功能的头文件
#include <linux/mm.h>              // 内存管理相关功能的头文件
#include <linux/input.h>           // 输入子系统相关功能的头文件
#include <linux/io.h>              // I/O内存操作相关功能的头文件
#include <asm/uaccess.h>           // 用户态内核态数据传输相关功能的头文件
#include <asm/atomic.h>            // 原子操作相关功能的头文件/****************MPU6050内部寄存器地址****************/#define	SMPLRT_DIV		0x19	//陀螺仪采样率,典型值:0x07(125Hz)
#define	CONFIG			0x1A	//低通滤波频率,典型值:0x06(5Hz)
#define	GYRO_CONFIG		0x1B	//陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define	ACCEL_CONFIG	0x1C	//加速计自检、测量范围及高通滤波频率,典型值:0x18(不自检,2G,5Hz)
#define	ACCEL_XOUT_H	0x3B
#define	ACCEL_XOUT_L	0x3C
#define	ACCEL_YOUT_H	0x3D
#define	ACCEL_YOUT_L	0x3E
#define	ACCEL_ZOUT_H	0x3F
#define	ACCEL_ZOUT_L	0x40
#define	TEMP_OUT_H		0x41
#define	TEMP_OUT_L		0x42
#define	GYRO_XOUT_H		0x43
#define	GYRO_XOUT_L		0x44
#define	GYRO_YOUT_H		0x45
#define	GYRO_YOUT_L		0x46
#define	GYRO_ZOUT_H		0x47
#define	GYRO_ZOUT_L		0x48
#define	PWR_MGMT_1		0x6B	//电源管理,典型值:0x00(正常启用)
#define	WHO_AM_I		0x75	//IIC地址寄存器(默认数值0x68,只读)
#define	SlaveAddress	0x68	//MPU6050-I2C地址// 定义MPU6050设备结构体
struct mpu6050_dev
{struct input_dev * pinput;   // 输入设备结构体指针struct i2c_client *pclient; // I2C客户端结构体指针struct delayed_work work;   // 延迟工作结构体
};struct mpu6050_dev *pgmydev = NULL; // 指向MPU6050设备数据结构的指针// 读取MPU6050寄存器的函数
int mpu6050_read_byte(struct i2c_client *pclt, unsigned char reg)
{int ret = 0;char txbuf[1] = {reg};char rxbuf[1] = {0};struct i2c_msg msg[2] = {{pclt->addr, 0, 1, txbuf},{pclt->addr, I2C_M_RD, 1, rxbuf}};ret = i2c_transfer(pclt->adapter, msg, ARRAY_SIZE(msg));if (ret < 0){printk("ret = %d, in mpu6050_read_byte\n", ret);return ret;}return rxbuf[0];
}// 写入MPU6050寄存器的函数
int mpu6050_write_byte(struct i2c_client *pclt, unsigned char reg, unsigned char val)
{int ret = 0;char txbuf[2] = {reg, val};struct i2c_msg msg[1] = {{pclt->addr, 0, 2, txbuf},};ret = i2c_transfer(pclt->adapter, msg, ARRAY_SIZE(msg));if (ret < 0){printk("ret = %d, in mpu6050_write_byte\n", ret);return ret;}return 0;
}// 延迟工作函数,用于读取MPU6050传感器数据
void mpu6050_work_func(struct work_struct *pwk)
{struct mpu6050_dev *pmydev = container_of((struct delayed_work *)pwk, struct mpu6050_dev, work);unsigned short ax = 0;unsigned short ay = 0;unsigned short az = 0;unsigned short gx = 0;unsigned short gy = 0;unsigned short gz = 0;unsigned short temp = 0;// 读取加速度和陀螺仪数据ax = mpu6050_read_byte(pmydev->pclient, ACCEL_XOUT_L);ax |= (mpu6050_read_byte(pmydev->pclient, ACCEL_XOUT_H) << 8);input_report_abs(pmydev->pinput, ABS_X, ax);ay = mpu6050_read_byte(pmydev->pclient, ACCEL_YOUT_L);ay |= (mpu6050_read_byte(pmydev->pclient, ACCEL_YOUT_H) << 8);input_report_abs(pmydev->pinput, ABS_Y, ay);az = mpu6050_read_byte(pmydev->pclient, ACCEL_ZOUT_L);az |= (mpu6050_read_byte(pmydev->pclient, ACCEL_ZOUT_H) << 8);input_report_abs(pmydev->pinput, ABS_Z, az);gx = mpu6050_read_byte(pmydev->pclient, GYRO_XOUT_L);gx |= (mpu6050_read_byte(pmydev->pclient, GYRO_XOUT_H) << 8);input_report_abs(pmydev->pinput, ABS_RX, gx);gy = mpu6050_read_byte(pmydev->pclient, GYRO_YOUT_L);gy |= (mpu6050_read_byte(pmydev->pclient, GYRO_YOUT_H) << 8);input_report_abs(pmydev->pinput, ABS_RY, gy);gz = mpu6050_read_byte(pmydev->pclient, GYRO_ZOUT_L);gz |= (mpu6050_read_byte(pmydev->pclient, GYRO_ZOUT_H) << 8);input_report_abs(pmydev->pinput, ABS_RZ, gz);temp = mpu6050_read_byte(pmydev->pclient, TEMP_OUT_L);temp |= (mpu6050_read_byte(pmydev->pclient, TEMP_OUT_H) << 8);input_report_abs(pmydev->pinput, ABS_MISC, temp);input_sync(pmydev->pinput);schedule_delayed_work(&pgmydev->work, msecs_to_jiffies(1000)); // 延迟1秒后再次读取数据
}// 初始化MPU6050传感器
void init_mpu6050(struct i2c_client *pclt)
{mpu6050_write_byte(pclt, PWR_MGMT_1, 0x00);mpu6050_write_byte(pclt, SMPLRT_DIV, 0x07);mpu6050_write_byte(pclt, CONFIG, 0x06);mpu6050_write_byte(pclt, GYRO_CONFIG, 0xF8);mpu6050_write_byte(pclt, ACCEL_CONFIG, 0x19);
}// I2C设备驱动的探测函数
static int mpu6050_probe(struct i2c_client *pclt, const struct i2c_device_id *pid)
{int ret = 0;pgmydev = (struct mpu6050_dev *)kmalloc(sizeof(struct mpu6050_dev), GFP_KERNEL);if (NULL == pgmydev){printk("kmalloc failed\n");return -1;}memset(pgmydev, 0, sizeof(struct mpu6050_dev));pgmydev->pclient = pclt;init_mpu6050(pgmydev->pclient);pgmydev->pinput = input_allocate_device();set_bit(EV_ABS, pgmydev->pinput->evbit);input_set_abs_params(pgmydev->pinput, ABS_X, -32768, 32767, 0, 0);input_set_abs_params(pgmydev->pinput, ABS_Y, -32768, 32767, 0, 0);input_set_abs_params(pgmydev->pinput, ABS_Z, -32768, 32767, 0, 0);input_set_abs_params(pgmydev->pinput, ABS_RX, -32768, 32767, 0, 0);input_set_abs_params(pgmydev->pinput, ABS_RY, -32768, 32767, 0, 0);input_set_abs_params(pgmydev->pinput, ABS_RZ, -32768, 32767, 0, 0);input_set_abs_params(pgmydev->pinput, ABS_MISC, -32768, 32767, 0, 0);ret = input_register_device(pgmydev->pinput);if (ret){printk("input_register_device failed\n");input_free_device(pgmydev->pinput);pgmydev->pinput = NULL;kfree(pgmydev);pgmydev = NULL;return -1;}INIT_DELAYED_WORK(&pgmydev->work, mpu6050_work_func);schedule_delayed_work(&pgmydev->work, msecs_to_jiffies(1000)); // 初始化后立即开始读取数据return 0;
}// I2C设备驱动的卸载函数
static int mpu6050_remove(struct i2c_client *pclt)
{cancel_delayed_work(&pgmydev->work);input_unregister_device(pgmydev->pinput);input_free_device(pgmydev->pinput);pgmydev->pinput = NULL;kfree(pgmydev);pgmydev = NULL;return 0;
}// 匹配设备树中的MPU6050节点
struct of_device_id mpu6050_dt[] =
{{.compatible = "invensense,mpu6050"},{}
};// 定义MPU6050设备驱动的ID
struct i2c_device_id mpu6050_ids[] =
{{"mpu6050", 0},{}
};// 定义MPU6050设备驱动结构体
struct i2c_driver mpu6050_driver =
{.driver = {.name = "mpu6050",.owner = THIS_MODULE,.of_match_table = mpu6050_dt,},.probe = mpu6050_probe,.remove = mpu6050_remove,.id_table = mpu6050_ids,
};// 注册MPU6050设备驱动
module_i2c_driver(mpu6050_driver);MODULE_LICENSE("GPL"); // 指定模块许可证

相关文章:

input子系统框架、外设驱动开发

一、input子系统基本框架 Linux内核为了两个目的&#xff1a; 简化纯输入类外设&#xff08;如&#xff1a;键盘、鼠标、游戏杆、轨迹球、触摸屏。。。等等&#xff09;的驱动开发统一输入类外设产生的数据格式&#xff08;struct input_event&#xff09;&#xff0c;更加方…...

Google Chrome 浏览器以全屏模式打开

目录 前言以全屏模式打开禁止弹出无法更新的提示窗禁止翻译网页Chrome设置禁止翻译网页可能1可能2可能3 网页添加指令禁止Chrome翻译网页 禁用脚本气泡浏览器解决办法html解决办法方法1&#xff1a;鼠标滑过超链接时&#xff0c;使状态栏不出现超链接方法2&#xff1a;方法3&am…...

安装torch113、cuda116并运行demo【Transformer】

文章目录 01. 导读02. 显卡驱动版本03. 创建环境、下载安装必要包04. 运行参考代码&#xff1a; 01. 导读 安装torch113、cuda116并运行demo【Transformer】 02. 显卡驱动版本 C:\Users\Administrator>nvidia-smi -l 10 Wed Sep 13 23:35:08 2023 ----------------------…...

基于scRNA-seq的GRN分析三阴性乳腺癌的肿瘤异质性

三阴性乳腺癌即TNBC是一种肿瘤异质性高的乳腺癌亚型。最近的研究表明&#xff0c;TNBC患者可能包含具有不同分子亚型的细胞。此外&#xff0c;基于scRNA-seq数据构建的GRN已经证明了对关键调控因子研究的重要性。作者使用scRNA-seq对TNBC患者的GRN进行了全面分析。从scRNA-seq数…...

Python:二进制文件实现等间隔取相同数据量并合并

举例&#xff1a;每3byte为一页&#xff0c;每3页为一wl。将所有wl的第一页/第二页/第三页分别合并为一个文件。 data b\x01\x02\x03\x04\x05\x06\x07\x08\x09\x01\x02\x03\x04\x05\x06\x07\x08\x09\x01\x02\x03\x04\x05\x06\x07\x08\x09\x01\x02\x03\x04\x05\x06\x07\x08\x0…...

python使用openvc库进行图像数据增强

以下是使用Python和OpenCV库实现图像数据增强的简单示例代码&#xff0c;其中包括常用的数据增强操作&#xff1a; import cv2 import numpy as np import os# 水平翻转 def horizontal_flip(image):return cv2.flip(image, 1)# 垂直翻转 def vertical_flip(image):return cv2…...

如何利用Api接口获取手机当前的网络位置信息

在移动互联网时代&#xff0c;手机定位已经成为了一个日常化的需求&#xff0c;无论是导航、社交还是打车等服务都需要获取手机的位置信息。而获取手机位置信息最基础的一步就是获取手机当前的网络位置信息&#xff0c;本文将介绍如何利用API接口获取手机当前的网络位置信息。 …...

vue-elementPlus自动按需导入和主题定制

elementPlus自动按需导入 装包 -> 配置 1. 装包&#xff08;主包和两个插件包&#xff09; $ npm install element-plus --save npm install -D unplugin-vue-components unplugin-auto-import 2. 配置 在vite.config.js文件中配置&#xff0c;配置完重启&#xff08;n…...

idea中dataBase模板生成

controller.java.vm ##定义初始变量 #set($tableName $tool.append($tableInfo.name, "Controller")) ##设置回调 $!callback.setFileName($tool.append($tableName, ".java")) $!callback.setSavePath($tool.append($tableInfo.savePath, "/contro…...

pc端测试手机浏览器运行情况,主要是测试硬件功能

测试h5震动摇晃等功能时不方便测试&#xff0c;需要连电脑显示调试数据 方法&#xff1a; 1.需要手机下载谷歌浏览器&#xff0c;pc端用edge或这谷歌浏览器 2.手机打开USB调试&#xff0c;打开要测试的网页 3.pc端地址栏输入edge://inspect/#devices&#xff08;这里用的edge浏…...

软件概要设计-架构真题(二十五)

软件概要设计包括软件设计的结构、确定系统功能模块及其相互关系&#xff0c;主要采用&#xff08;&#xff09;描述程序的结构。&#xff08;2018年&#xff09; 程序流程图、PAD图和伪代码模块结构图、数据流图和盒图模块结构图、层次图和HIPO图程序流程图、数据流图和层次图…...

CSDN发文表情包整理

文章目录 简介部分Emoji表情符号简表人物自然物品地点符号 各种Emoji表情链接 简介 CSDN支持Markdown语法及Emoji表情&#xff0c;使用各种Emoji表情可以使得自己的博文更加生动多彩。一般有两种在支持Markdown的语法环境中添加Emoji表情&#xff1a;1.直接将表情包复制到文档…...

springBoot对接Apache POI 实现excel下载和上传

搭建springboot项目 此处可以参考 搭建最简单的SpringBoot项目_Steven-Russell的博客-CSDN博客 配置Apache POI 依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.2</version> </…...

定积分的计算:牛顿-莱布尼茨公式

目录 牛顿-莱布尼茨公式 用C语言代码实现 利用换元积分法和分部积分法 利用奇偶性和周期性求积分 利用已有公式求积分 牛顿-莱布尼茨公式 牛顿-莱布尼茨公式&#xff08;Newton-Leibniz formula&#xff09;是微积分学中的基本定理之一&#xff0c;它反映了定积分与被积函…...

shell脚本之case 的用法

shell脚本之case case是Shell脚本中的一种控制流语句&#xff0c;它允许根据变量的值选择不同的执行路径。case语句的语法如下&#xff1a; case word in pattern [| pattern]...) command-list ;; pattern [| pattern]...) command-list ;; ... *) command-list ;; esa…...

第3章 helloworld 驱动实验(iTOP-RK3568开发板驱动开发指南 )

在学习C语言或者其他语言的时候&#xff0c;我们通常是打印一句“helloworld”来开启编程世界的大门。学习驱动程序编程亦可以如此&#xff0c;使用helloworld作为我们的第一个驱动程序。 接下来开始编写第一个驱动程序—helloworld。 3.1 驱动编写 本小节来编写一个最简单的…...

基于PyTorch使用LSTM实现新闻文本分类任务

本文参考 PyTorch深度学习项目实战100例 https://weibaohang.blog.csdn.net/article/details/127154284?spm1001.2014.3001.5501 文章目录 本文参考任务介绍做数据的导入 环境介绍导入必要的包介绍torchnet和keras做数据的导入给必要的参数命名加载文本数据数据前处理模型训…...

Flutter插件的制作和发布

Flutter制作插件有两种方式&#xff08;以下以android和ios为例&#xff09;&#xff1a; 目录 1.直接在主工程下的android和ios项目内写插件代码&#xff1a;2.创建独立Flutter Plugin项目&#xff0c;制作各端插件后&#xff0c;再引入项目&#xff1a;1. 创建Flutter Plugin…...

【JAVA】异常

作者主页&#xff1a;paper jie 的博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文录入于《JAVASE语法系列》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和…...

合同矩阵充要条件

两个实对称矩阵合同的充要条件是它们的正负惯性指数相同。 正惯性指数是矩阵正特征值个数&#xff0c;负惯性指数是矩阵负特征值个数。 即合同矩阵的充分必要条件是特征值的正负号个数相同。 证明&#xff1a; 本论证中的所有矩阵都是对称矩阵。 根据定义&#xff0c;若矩…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...