嵌入式驱动开发详解15(电容触摸屏gt9147)
文章目录
- 前言
- 电容触摸屏特点
- MT触摸消息
- 电容触摸屏协议
- 电容屏触摸时序
- Type A 触摸点信息上报时序
- Type B 触摸点信息上报时序
- 多点触摸所使用到的API函数
- 驱动部分
- 驱动框图
- 设备树节点修改
- 设备树引脚配置
- 设备节点配置
- 具体驱动开发
- I2C驱动框架
- I2C框架内部实现
- 参考文献
前言
随着智能手机的发展,电容触摸屏也得到了飞速的发展。相比电阻触摸屏,电容触摸屏有 很多的优势,比如支持多点触控、不需要按压,只需要轻轻触摸就有反应。
电容触摸屏特点
- 电容触摸屏是 IIC 接口的,需要触摸IC,以正点原子的 ATK7016 为例,其所使用的触摸屏控制IC为 FT5426,因此所谓的电容触摸驱动就是 IIC 设备驱动。
- 触摸 IC 提供了中断信号引脚(INT),可以通过中断来获取触摸信息。
- 电容触摸屏得到的是触摸位置绝对信息以及触摸屏是否有按下。
- 电容触摸屏不需要校准,当然了,这只是理论上的,如果电容触摸屏质量比较差,或者触摸玻璃和 TFT 之间没有完全对齐,那么也是需要校准的。
因此对应到驱动开发上,我们可以得出电容触摸屏驱动其实就是以下几种linux驱动框架的组合:
- IIC 设备驱动,因为电容触摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 设备驱动。
- 通过中断引脚(INT)向 linux 内核上报触摸信息,因此需要用到 linux 中断驱动框架。坐 标的上报在中断服务函数中完成。
- 触摸屏的坐标信息、屏幕按下和抬起信息都属于 linux 的 input 子系统,因此向 linux 内 核上报触摸屏坐标信息就得使用 input 子系统。只是,我们得按照 linux 内核规定的规则来上报 坐标信息。
MT触摸消息
电容触摸屏协议
老版本的 linux 内核是不支持多点电容触摸的(Multi-touch,简称 MT),MT 协议是后面加入 的,因此如果使用 2.x 版本 linux 内核的话可能找不到 MT 协议。MT 协议被分为两种类型,Type A 和 TypeB,这两种类型的区别如下:
Type A:适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据(此类型在实际使 用中非常少!)。
Type B:适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot 更新某一个 触摸点的信息,FT5426 就属于此类型,一般的多点电容触摸屏 IC 都有此能力。
触摸点的信息通过一系列的 ABS_MT 事件(有的资料也叫消息)上报给 linux 内核,只有 ABS_MT 事件是用于多点触摸的,ABS_MT 事件定义在文件 include/uapi/linux/input.h 中
#define ABS_MT_SLOT 0x2f /* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
#define ABS_MT_POSITION_X 0x35 /* Center X touch position */
#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */
#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */
#define ABS_MT_TOOL_X 0x3c /* Center X tool position */
#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */
其 中 ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 用 来 上 报 触 摸 点 的 (X,Y) 坐 标 信 息 ,ABS_MT_SLOT 用来上报触摸点 ID , 对 于 Type B 类型的设备,需要用到 ABS_MT_TRACKING_ID 事件来区分触摸点。
如果设备支持的话,还可以使用 ABS_MT_TOUCH_MAJOR 和 ABS_MT_WIDTH_MAJOR 这两个消息上报触摸面积信息,关于 其他 ABS_MT 事件的具体含义大家可以查看 Linux 内核中的 multi-touch-protocol.txt 文档。
电容屏触摸时序
Type A 触摸点信息上报时序
下面这个是发送两个触摸点的例子:
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
SYN_MT_REPORT
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT
Linux 内核里面也有 Type A 类型的多点触摸驱动,找到 st2332.c 这个驱动文件,具体实例如下:
static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
{struct st1232_ts_data *ts = dev_id;struct st1232_ts_finger *finger = ts->finger;struct input_dev *input_dev = ts->input_dev;int count = 0;int i, ret;ret = st1232_ts_read_data(ts);if (ret < 0)goto end;/* multi touch protocol */for (i = 0; i < MAX_FINGERS; i++) {if (!finger[i].is_valid)continue;input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t);input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y);input_mt_sync(input_dev);count++;}/* SYN_MT_REPORT only if no contact */if (!count) {input_mt_sync(input_dev);if (ts->low_latency_req.dev) {dev_pm_qos_remove_request(&ts->low_latency_req);ts->low_latency_req.dev = NULL;}} else if (!ts->low_latency_req.dev) {/* First contact, request 100 us latency. */dev_pm_qos_add_ancestor_request(&ts->client->dev,&ts->low_latency_req,DEV_PM_QOS_RESUME_LATENCY, 100);}/* SYN_REPORT */input_sync(input_dev);
end:return IRQ_HANDLED;
}
其中input_mt_sync和input_sync对应着SYN_MT_REPORT和SYN_REPORT,每 上报完一个触摸点坐标,都要调用 input_mt_sync 函数上报一个 SYN_MT_REPORT 信息。 每上报完一轮触摸点信息就调用一次 input_sync 函数,也就是发送一个 SYN_REPORT 事件。
Type B 触摸点信息上报时序
下面这个是发送两个触摸点的例子:
ABS_MT_SLOT 0
ABS_MT_TRACKING_ID 45
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID 46
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_REPORT
这里就以 ili210x 这个触摸驱动 IC 为例,看看是 Type B 类型 是 如 何 上 报 触 摸 点 坐 标 信 息 的 。 找 到 ili210x.c 这 个 驱 动 文 件,具体实力2机器人
static void ili210x_report_events(struct input_dev *input,const struct touchdata *touchdata)
{int i;bool touch;unsigned int x, y;const struct finger *finger;for (i = 0; i < MAX_TOUCHES; i++) {input_mt_slot(input, i);finger = &touchdata->finger[i];touch = touchdata->status & (1 << i);input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);if (touch) {x = finger->x_low | (finger->x_high << 8);y = finger->y_low | (finger->y_high << 8);input_report_abs(input, ABS_MT_POSITION_X, x);input_report_abs(input, ABS_MT_POSITION_Y, y);}}input_mt_report_pointer_emulation(input, false);input_sync(input);
}
调用 input_mt_slot 函数 上报 ABS_MT_SLOT 事 件 。 调用 input_mt_report_slot_state 函 数 上 报 ABS_MT_TRACKING_ID 事件,也就是给 SLOT 关联一个 ABS_MT_TRACKING_ID。使用 input_report_abs 函数上报触摸点对应的(X,Y)坐标值。 使用 input_sync 函数上报 SYN_REPORT 事件。
多点触摸所使用到的API函数
- input_mt_init_slots:用于初始化 MT 的输入 slots,编写 MT 驱动的时候必须先调用此函 数初始化 slots
- input_mt_slot:用于产生 ABS_MT_SLOT 事件,告诉内核当前上报的是哪个触摸点的坐标数据
- input_mt_report_slot_state:用于 Type B 类型,用于产生 ABS_MT_TRACKING_ID 和 ABS_MT_TOOL_TYPE 事 件 , ABS_MT_TRACKING_ID 事 件 给 slot 关 联 一 个 ABS_MT_TRACKING_ID , ABS_MT_TOOL_TYPE 事件指定触摸类型(是笔还是手指等)。
- input_report_abs:ype A 和 Type B 类型都使用此函数上报触摸点坐标信息,通过 ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 事件实现 X 和 Y 轴坐标信息上报
- input_mt_report_pointer_emulation:如果追踪到的触摸点数量多于当前上报的数量,驱动程序使用 BTN_TOOL_TAP 事件来通 知用户空间当前追踪到的触摸点总数量,然后调用 input_mt_report_pointer_emulation 函数将 use_count 参数设置为 false。否则的话将 use_count 参数设置为 true,表示当前的触摸点数量
驱动部分
驱动框图
编写驱动的框架如下:
①、多点电容触摸芯片的接口,一般都为 I2C 接口,因此驱动主框架肯定是 I2C。
②、linux 里面一般都是通过中断来上报触摸点坐标信息,因此需要用到中断框架。
③、多点电容触摸属于 input 子系统,因此还要用到 input 子系统框架。
④、在中断处理程序中按照 linux 的 MT 协议上报坐标信息。
具体见下图:
注意:中断没有使用 request_irq 函数申请中断,而是采用了 devm_request_threaded_irq 这个函数,并不是因为前者不能用,而是因为后者有更多的特点,比较适用于此场景。devm_request_threaded_irq具有如下特点:
- 用于申请中断,作用和 request_irq 函数类似。
- threaded的作用是中断线程化,硬件中断具有最高优先级,只要硬件中断发生,那么内核都会终止当前正在执行的操作,转而去执行中断处理程序。中断线程化以后任务的优先级可能比中断线程的优先级高,这样做的目的就是保证高优先级的任务能被优先处理。大家可能会疑问,不是说可以将比较耗时的中断放到下半部(bottom half) 处理吗?虽然下半部可以被延迟处理,但是依旧先于线程执行,中断线程化可以让这些比较耗时的下半部与进程进行公平竞争。
- 使用devm_前缀的函数申请到的资源可以由系统自动释放,不需要我们手动处理。
设备树节点修改
设备树节点的修改主要分为两个部分,一个是引脚的配置,一个是设备节点的配置
设备树引脚配置
如上图所示,该电容屏,主要用到四个引脚,其中两个是I2C的信号引脚,一个是触摸屏的中断引脚,还有一个是电容屏的复位引脚。
复位引脚:复位引脚用的是SNVS_TAMPER9,因此我们需要在&iomuxc_snvs下写入相关信息,具体如下:
&iomuxc_snvs {pinctrl-names = "default_snvs";pinctrl-0 = <&pinctrl_hog_2>;imx6ul-evk {pinctrl_tsc_reset: tsc_reset {fsl,pins = <MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x10B0>;};};
};
中断引脚:此处使用的是GPIO1_IO09,因此我们需要在节点&iomuxc下写入相关信息,具体如下:
&iomuxc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_hog_1>;imx6ul-evk {pinctrl_tsc: tscgrp {fsl,pins = <MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x79>;};};
};
I2C引脚:此处使用的是I2C2,UART5_TX和UART5_RX,因此需要同中断引脚一样,在节点&iomuxc下写入相关信息,具体如下:
&iomuxc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_hog_1>;imx6ul-evk {pinctrl_i2c2: i2c2grp {fsl,pins = <MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0>;};};
};
这里需要注意一个很容易犯的错误,我们在配置对应的引脚时一定要先看看这个引脚有没有被配置成其他的功能,如有有的话需要把其他的功能给屏蔽掉,不然会发生冲突。
设备节点配置
引脚配置好之后,需要我们配置相应的设备树节点信息,因为这个设备是挂载在I2C2上的,因此需要把对应的节点信息放在&i2c2上面,对应的注释我都写入代码里了,如下所示:
&i2c2 {clock_frequency = <100000>; //时钟频率pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c2>; //I2C引脚status = "okay"; //打开I2C2gt9147:gt9147@14 { //名称@设备地址compatible = "hbb,gt9147"; //熟悉值,用于匹配驱动reg = <0x14>; //寄存器地址pinctrl-names = "default"; pinctrl-0 = <&pinctrl_tsc //另外两个引脚&pinctrl_tsc_reset>;interrupt-parent = <&gpio1>; //配置中断interrupts = <9 0>; //配置中断IO序号,以及中断触发形式reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; //配置复位引脚,便于驱动直接从节点读取interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; //配置复位引脚,便于驱动直接从节点读取status = "okay";};
};
这里跟上面引脚定义一样,我们也需要避免出现冲突,防止同一个引脚被不同的驱动拿去使用,我们需要查看pinctrl-0、reset-gpios、interrupt-gpios也就是对应的四个引脚有没有被其他地方使用。
具体驱动开发
具体驱动开发本质上就是I2C,中断,input子系统的综合例程,=接下来我将分析如何搭建出一个框架
在驱动开发之前,需要注意以下两点:
- I2C框架中i2c_add_driver函数创建的驱动节点里面就包含了设备的相关信息,并且能实现I2C通信
- input子系统是在I2C总线上面开发的,之前开发ap3216设备时,我们直接用dev、class、device三步走的方式创建设备节点,而这次是需要开发一个input子系统的设备节点,因此我们需要借助input_register_device这个函数创建对应的设备节点。
I2C驱动框架
I2C驱动框架如下:
static const struct of_device_id gt9147_of_match[] = {{.compatible = "hbb,gt9147"},{ }
}; static const struct i2c_device_id gt9147_id[] = {{"gt9147",0},/* 我们用的是of_device_id,i2c_device_id可以写的不对,但是必须要有*/
};static struct i2c_driver gt9147_driver = {.probe = gt9147_probe,.remove = gt9147_remove,.driver = {.owner = THIS_MODULE,.name = "gt9147",.of_match_table = gt9147_of_match,},.id_table = gt9147_id,
};static int __init gt9147_init(void)
{return i2c_add_driver(>9147_driver);
}static void __exit gt9147_exit(void)
{i2c_del_driver(>9147_driver);
}
I2C框架内部实现
在I2C设备驱动节点创建好之后就可以进行I2C通信了,但是我们还需要input子系统和中断的配合,因此我们需要丰富一下.probe函数,下面是probe函数的具体内容,紧接着按照probe函数的顺序逐一讲解:
static int gt9147_probe(struct i2c_client *client, const struct i2c_device_id *id)
{int ret;u8 data;printk("gt9147_probe!!!\r\n");gt9147dev.client = client;// 1,获取设备树中的中断和复位引脚gt9147dev.irq_pin = of_get_named_gpio(client->dev.of_node, "interrupt-gpios", 0);gt9147dev.reset_pin = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);// 2,复位GT9147ret = gt9147_ts_reset(client, >9147dev);if(ret < 0) {goto fail;}// 3,初始化GT9147data = 0x02;gt9147_write_regs(>9147dev, GT_CTRL_REG, &data, 1); //软复位mdelay(100);data = 0x0;gt9147_write_regs(>9147dev, GT_CTRL_REG, &data, 1); //停止软复位mdelay(100);// 4,初始化GT9147,读取固件ret = gt9147_read_firmware(client, >9147dev);if(ret != 0) {printk("Fail !!! check !!\r\n");goto fail;}// 5,input设备注册 gt9147dev.input = devm_input_allocate_device(&client->dev);if (!gt9147dev.input) {ret = -ENOMEM;goto fail;}gt9147dev.input->name = client->name;gt9147dev.input->id.bustype = BUS_I2C;gt9147dev.input->dev.parent = &client->dev;__set_bit(EV_KEY, gt9147dev.input->evbit);__set_bit(EV_ABS, gt9147dev.input->evbit);__set_bit(BTN_TOUCH, gt9147dev.input->keybit);input_set_abs_params(gt9147dev.input, ABS_X, 0, gt9147dev.max_x, 0, 0);input_set_abs_params(gt9147dev.input, ABS_Y, 0, gt9147dev.max_y, 0, 0);input_set_abs_params(gt9147dev.input, ABS_MT_POSITION_X,0, gt9147dev.max_x, 0, 0);input_set_abs_params(gt9147dev.input, ABS_MT_POSITION_Y,0, gt9147dev.max_y, 0, 0); ret = input_mt_init_slots(gt9147dev.input, MAX_SUPPORT_POINTS, 0);if (ret) {goto fail;}ret = input_register_device(gt9147dev.input);if (ret)goto fail;// 6,最后初始化中断 ret = gt9147_ts_irq(client, >9147dev);if(ret < 0) {goto fail;}return 0;
fail:return ret;
}
-
由于设备不是通电就能使用,还需要进对复位引脚进行读写操作才行,因此需要先获取设备对应的IO引脚号后执行函数gt9147_ts_reset来实现复位GT9147电容屏幕
-
接着利用i2c通信来初始化GT9147,这里用到了gt9147_write_regs 函数,后续读取数据会用到对应的gt9147_read_regs函数,重点注意这个地方的寄存器地址是16位的,因此需要把地址写成两个字节分两次传输。利用函数gt9147_read_firmware来读取固件信息,配置对应的像素点等信息。
-
devm_input_allocate_device是input设备注册,方便我们上传电容屏数据给用户端,同时也需要配置好与input有关的初始化配置,具体见probe函数如何配置的。
-
配置引脚中断,利用函数gt9147_ts_irq配置引脚中断,这里我们用的是devm_request_threaded_irq函数,为啥不用request_irq前面已经讲解了,最后只需要在中断中上报input的MT数据即可
上面所有的子函数以及中断处理函数等直接参考最后的参考文献链接地址即可,代码都放入了对应的github仓库里面,这里不在一一展示。
需要特别说明一下的是正点原子提供的驱动只能实现单点触摸,本实验在网上找到了多点触摸的实现方法,通过touch_index和id配合实现,具体多点触摸代码如下:
static irqreturn_t gt9147_irq_handler(int irq, void *dev_id)
{int touch_num = 0;int input_x, input_y;int id = 0;int ret = 0;u8 data;u8 touch_data[BUFFER_SIZE];u16 touch_index = 0;int pos = 0;int report_num = 0;int i;static u16 last_index = 0;struct gt9147_dev *dev = dev_id;ret = gt9147_read_regs(dev, GT_GSTID_REG, &data, 1);if (data == 0x00) { // 没有触摸数据,直接返回goto fail;} else { //统计触摸点数据 touch_num = data & 0x0f;}if(touch_num) { //有触摸按下//读取具体的触摸寄存器gt9147_read_regs(dev, GT_TP1_REG, touch_data, BUFFER_SIZE);id = touch_data[0];touch_index |= (0x01<<id);for(i = 0;i < 5; i++){if(touch_index |= (0x01 << i)){input_x = touch_data[pos + 1] | (touch_data[pos + 2] << 8);input_y = touch_data[pos + 3] | (touch_data[pos + 4] << 8);input_mt_slot(dev->input, id); //产生ABS_MT_SLOT 事件 报告是哪个触摸点的坐标 input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, true); // 指定手指触摸 连续触摸input_report_abs(dev->input, ABS_MT_POSITION_X, input_x); // 上报触摸点坐标信息 input_report_abs(dev->input, ABS_MT_POSITION_Y, input_y); // 上报触摸点坐标信息report_num++;if(report_num < touch_num){pos += 8;id = touch_data[pos];touch_index |= (0x01<<id);}}else{input_mt_slot(dev->input, i);input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, false); // 关闭手指触摸 }}} else if(last_index){ // 触摸释放for(i = 0;i < 5; i++){if(last_index & (0x01 << i)){input_mt_slot(dev->input, i);input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, false);}}}last_index = touch_index;input_mt_report_pointer_emulation(dev->input, true);input_sync(dev->input);data = 0x00; //向0X814E寄存器写0gt9147_write_regs(dev, GT_GSTID_REG, &data, 1);fail:return IRQ_HANDLED;
}
下面这个是单点触摸实验代码,可以对比学习一下:
static irqreturn_t gt9147_irq_handler(int irq, void *dev_id)
{int touch_num = 0;int input_x, input_y;int id = 0;int ret = 0;u8 data;u8 touch_data[5];struct gt9147_dev *dev = dev_id;ret = gt9147_read_regs(dev, GT_GSTID_REG, &data, 1);if (data == 0x00) { // 没有触摸数据,直接返回goto fail;} else { //统计触摸点数据 touch_num = data & 0x0f;}// 由于GT9147没有硬件检测每个触摸点按下和抬起,因此每个触摸点的抬起和按// 下不好处理,尝试过一些方法,但是效果都不好,因此这里暂时使用单点触摸 if(touch_num) { //单点触摸按下gt9147_read_regs(dev, GT_TP1_REG, touch_data, 5);id = touch_data[0] & 0x0F;if(id == 0) {input_x = touch_data[1] | (touch_data[2] << 8);input_y = touch_data[3] | (touch_data[4] << 8);input_mt_slot(dev->input, id);input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, true);input_report_abs(dev->input, ABS_MT_POSITION_X, input_x);input_report_abs(dev->input, ABS_MT_POSITION_Y, input_y);}} else if(touch_num == 0){ // 单点触摸释放input_mt_slot(dev->input, id);input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, false);}input_mt_report_pointer_emulation(dev->input, true);input_sync(dev->input);data = 0x00; //向0X814E寄存器写0gt9147_write_regs(dev, GT_GSTID_REG, &data, 1);fail:return IRQ_HANDLED;
}
参考文献
- 个人专栏系列文章
- 正点原子嵌入式驱动开发指南
- 对代码有兴趣的同学可以查看链接https://github.com/NUAATRY/imx6ull_dev
相关文章:
嵌入式驱动开发详解15(电容触摸屏gt9147)
文章目录 前言电容触摸屏特点MT触摸消息电容触摸屏协议电容屏触摸时序Type A 触摸点信息上报时序Type B 触摸点信息上报时序 多点触摸所使用到的API函数 驱动部分驱动框图设备树节点修改设备树引脚配置设备节点配置 具体驱动开发I2C驱动框架I2C框架内部实现 参考文献 前言 随着…...
supervision - 好用的计算机视觉 AI 工具库
Supervision库是一款出色的Python计算机视觉低代码工具,其设计初衷在于为用户提供一个便捷且高效的接口,用以处理数据集以及直观地展示检测结果。简化了对象检测、分类、标注、跟踪等计算机视觉的开发流程。开发者仅需加载数据集和模型,就能轻…...
软件安装不成功,一直出现“chrome_elf.dll丢失”问题是什么原因?“chrome_elf.dll丢失”要怎么解决和预防?
软件安装遇阻:“chrome_elf.dll丢失”问题全解析与解决方案 在软件安装与运行的过程中,我们时常会遇到各式各样的错误提示,其中“chrome_elf.dll丢失”便是较为常见的一种。这个错误不仅阻碍了软件的正常安装,也给用户带来了不小…...
10篇--图像噪点消除
概念 何为噪点? 噪点:指图像收到的一些干扰因素,通常是由图像采集设备、传输信道等因素造成的,表现为图像中随机的亮度,也可以理解为有那么一些点的像素值与周围的像素值格格不入。 常见的噪声类型 高斯噪声&#…...
在 Vue 2 中,在 <el-table> 中为每一行动态插入对应的 echart 组件
更新数据结构:确保每一行数据都包含需要绘制图表的数据(例如 demandRespList 和 timeList),以便为每行生成不同的图表。 修改 getTableDataPreview 方法:在获取数据后,您需要为每一行创建对应的图表配置。 在 <el-table-column> 中使用 slot-scope:使用 slot-scop…...
protobuf c++开发快速上手指南
1、环境准备 在c环境使用 protobuf,需要安装protobuf runtime以及protobuf的编译器:protoc,其作用如下表格: 需要安装的环境作用protoc将proto文件编译成c源码protobuf runtime编译c源码需要链接到protobuf库 注意:…...
【HTML】HTML动画时钟
今天分享一个比较有趣的HTML动画时钟,感兴趣的小伙伴可以自行上手体验一番,操作也非常简单,如下: 1. 实操 实践操作步骤: 创建一个文本文件 clock.txt将上述代码粘贴到 clock.txt 中。修改文件后缀,将文…...
2024年全国仿真创新应用大赛 | MWORKS助力“复杂系统数字仿真”赛道,获奖名单公布
2024年全国仿真创新应用大赛全国总决赛于近日圆满落幕。大赛由工业和信息化部人才交流中心主办,以“创新引领,铸就未来”为主题,来自全国的参赛院校、企业、医学科学单位、军事科学单位及仿真领域的科研院所共计422家、近1300余人参加了此次总…...
ionic V6 安装ios所需
npm install capacitor/ios添加ios平台 ruby要求3.0以上 rvm use ruby-3.1.0 --default npx cap add ios打开xcode看看创建的项目 npx cap open ios没有capacitor指定的位置, 估计之前pod(cocoapods)安装搞得Ruby环境很乱了......cocoapods整的我麻了... App/App/capacitor…...
Docker Compose 多应用部署 一键部署
介绍 Docker Compose通过一个单独的docker-compose.yml模板文件(YAML格式)来定义一组相关联的应用容器,帮助我们实现多个相互关联的Docker容器的快速部署。 如:springbootmysqlnginx 如果一个个去部署他会非常的麻烦,这时候可以选择Docker …...
ubuntu20.04安装qt creator
以上三种,选择其一安装即可 回答1: 您可以按照以下步骤在ubuntu 20.04上安装Qt Creator: 打开终端并输入以下命令以更新软件包列表: sudo apt update 安装Qt Creator和Qt库: sudo apt install qtcreator qt5-def…...
经典NLP案例 | 推文评论情绪分析:从数据预处理到模型构建的全面指南
NLP经典案例:推文评论情绪提取 项目背景 “My ridiculous dog is amazing.” [sentiment: positive] 由于所有推文每秒都在传播,很难判断特定推文背后的情绪是否会影响一家公司或一个人的品牌,因为它的病毒式传播(积极࿰…...
蓝卓生态说 | 捷创技术李恺和:把精细管理和精益生产做到极致
成功的产品离不开开放式创新和生态协同的力量。近年来,蓝卓坚持“平台生态"战略,不断加码生态,提出三个层次的开源开放生态计划,举办"春风行动”、“生态沙龙"等系列活动,与生态伙伴共生、共创、共同推…...
启发式搜索算法和优化算法的区别
启发式搜索算法和优化算法在计算机科学中都有广泛的应用,但它们之间存在一些明显的区别。 一、定义与核心思想 启发式搜索算法 定义:启发式搜索算法是一类基于经验和直觉的问题求解方法,通过观察问题的特点,并根据某种指…...
生成树协议STP工作步骤
第一步:选择根桥 优先级比较:首先比较优先级,优先级值越小的是根桥MAC地址比较:如果优先级相同,则比较MAC地址。MAC地址小的是根桥。 MAC地址比较的时候从左往右,一位一位去比 第二步:所有非根…...
批量合并多个Excel到一个文件
工作中,我们经常需要将多个Excel的数据进行合并,很多插件都可以做这个功能。但是今天我们将介绍一个完全免费的独立软件【非插件】,来更加方便的实现这个功能。 准备Excel 这里我们准备了两张待合并的Excel文件 的卢易表 打开的卢易表软件…...
如何在vue中实现父子通信
1.需要用到的组件 父组件 <template><div id"app"><BaseCount :count"count" changeCount"cahngeCount"></BaseCount></div> </template><script> import BaseCount from ./components/BaseCount.v…...
强化学习Q-learning及其在机器人路径规划系统中的应用研究,matlab代码
一、Q-learning 算法概述 Q-learning 是一种无模型的强化学习算法,它允许智能体(agent)在没有环境模型的情况下通过与环境的交互来学习最优策略。Q-learning的核心是学习一个动作价值函数(Q-function),该函…...
【算法】EWMA指数加权移动平均绘制平滑曲线
EWMA(Exponentially Weighted Moving Average,指数加权移动平均)是一种常用的时间序列平滑技术,特别适用于对过去数据给予不同的权重。以下是对EWMA算法的详细介绍: 一、核心思想 EWMA算法的核心思想是通过指数衰减来…...
jenkins harbor安装
Harbor是一个企业级Docker镜像仓库。 文章目录 1. 什么是Docker私有仓库2. Docker有哪些私有仓库3. Harbor简介4. Harbor安装 1. 什么是Docker私有仓库 Docker私有仓库是用于存储和管理Docker镜像的私有存储库。Docker默认会有一个公共的仓库Docker Hub,而与Dock…...
行为树详解(4)——节点参数配置化
【分析】 行为树是否足够灵活强大依赖于足够丰富的各类条件节点和动作节点,在实现这些节点时,不可避免的,节点本身需要有一些参数供配置。 这些参数可以分为静态的固定值的参数以及动态读取设置的参数。 静态参数直接设置为Public即可&…...
在数字孪生开发领域threejs现在的最新版本已经更新到多少了?
在数字孪生开发领域three.js现在的最新版本已经更新到多少了? 在数字孪生开发领域,three.js作为一款强大的JavaScript 3D库,广泛应用于Web3D可视化、智慧城市、智慧园区、数字孪生等多个领域。随着技术的不断进步和需求的日益增长࿰…...
UE材质常用节点
Desaturation 去色 饱和度控制 Panner 贴图流动 快捷键P Append 附加 合并 TexCoord UV平铺大小 快捷键U CustomRotator 旋转贴图 Power 幂 色阶 Mask 遮罩 Lerp 线性插值 快捷键L Abs 绝对值 Sin / Cos 正弦/余弦 Saturate 约束在0-1之间 Add 相加 快捷键A Subtra…...
burp(2)利用java安装burpsuite
BurpSuite安装 burpsuite 2024.10专业版,已经内置java环境,可以直接使用, 支持Windows linux macOS!!! 内置jre环境,无需安装java即可使用!!! bp2024.10下载…...
33.攻防世界upload1
进入场景 看看让上传什么类型的文件 传个木马 把txt后缀改为png 在bp里把png改为php 上传成功 用蚁剑连接 在里面找flag 得到...
17、ConvMixer模型原理及其PyTorch逐行实现
文章目录 1. 重点2. 思维导图 1. 重点 patch embedding : 将图形分割成不重叠的块作为图片样本特征depth wise point wise new conv2d : 将传统的卷积转换成通道隔离卷积和像素空间隔离两个部分,在保证精度下降不多的情况下大大减少参数量 2. 思维导图 后续再整…...
【软件工程】一篇入门UML建模图(状态图、活动图、构件图、部署图)
🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀软件开发必练内功_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前…...
C# winfrom 异步加载数据不影响窗体UI
文章目录 前言一、背景介绍二、使用BackgroundWorker组件实现异步加载数据2.1 添加BackgroundWorker组件2.2 处理DoWork事件 三、延伸内容3.1 错误处理和进度报告3.2 线程安全 结束语优质源码分享 C# winfrom 异步加载数据不影响窗体UI,在 WinForms 应用程序中&…...
Flutter Navigator2.0的原理和Web端实践
01 背景与动机 在Navigator 2.0推出之前,Flutter主要通过Navigator 1.0和其提供的 API(如push(), pop(), pushNamed()等)来管理页面路由。然而,Navigator 1.0存在一些局限性,如难以实现复杂的页面操作(如移…...
latex设置引用顺序
在 LaTeX 中,引用的顺序通常是由所选择的 参考文献样式(bibliographystyle) 决定的。如果你希望根据引用的顺序排列参考文献,可以选择合适的参考文献样式,并按照以下步骤进行设置。 常见的几种引用顺序设置方式有&…...
有效的括号(字节面试题 最优解)
题目来源 20. 有效的括号 - 力扣(LeetCode) 题目描述 给定一个只包括 (,),{,},[,] 的字符串 s ,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号…...
短视频矩阵源码开发部署全流程解析
在当今的数字化时代,短视频已成为人们娱乐、学习和社交的重要方式。短视频矩阵系统的开发与部署,对于希望在这一领域脱颖而出的企业和个人而言,至关重要。本文将详细阐述短视频矩阵源码的开发与部署流程,并附上部分源代码示例&…...
iOS 环境搭建教程
本文档将详细介绍如何在 macOS 上搭建 iOS 开发环境,以便进行 React Native 开发。(为了保证环境一致 全部在网络通畅的情况下运行) 1. 安装 Homebrew Homebrew 是 macOS 的包管理工具,我们将通过它来安装开发所需的工具。 安装…...
element-ui实现table表格的嵌套(table表格嵌套)功能实现
最近在做电商类型的官网,希望实现的布局如下:有表头和表身,所以我首先想到的就是table表格组件。 表格组件中常见的就是:标题和内容一一对应: 像效果图中的效果,只用基础的表格布局是不行的,因…...
如何使mysql数据库ID从0开始编号——以BiCorpus为例
BiCorpus是北京语言大学韩林涛老师研制一款在线语料库网站,可以通过上传tmx文件,实现在线检索功能,程序在github上开源免费,深受广大网友的喜欢。 在使用过程中,我发现我上传的语言资产经历修改后,mysql的…...
亮相AICon,火山引擎边缘云揭秘边缘AI Agent探索与实践
12月13-14日,AICon 全球人工智能开发与应用大会在北京成功举办。火山引擎边缘智能技术负责人谢皓受邀出席大会,以《AI Agent 在边缘云的探索与实践》为主题,与全球 AI 领域的资深专家,共同深入探讨大模型落地、具身智能、多模态大…...
让文案生成更具灵活性/chatGPT新功能canvas画布编辑
OpenAI最近在2024年12月发布了canvas画布编辑功能,这是一项用途广泛的创新工具,专为需要高效创作文案的用户设计。 无论是职场人士、学生还是创作者,这项功能都能帮助快速生成、优化和编辑文案,提升效率的同时提高内容质量…...
朗致面试---IOS/安卓/Java/架构师
朗致面试---IOS/安卓/Java/架构师 一、面试概况二、总结三、算法题目参考答案 一、面试概况 一共三轮面试: 第一轮是逻辑行测,25道题目,类似于公务员考试题目,要求90分钟内完成。第二轮是技术面试,主要是做一些数据结…...
windows C#-实现具有自动实现属性的轻型类
下面演示如何创建一个不可变的轻型类,该类仅用于封装一组自动实现的属性。 当你必须使用引用类型语义时,请使用此种构造而不是结构。 可通过以下方法来实现不可变的属性: 仅声明 get 访问器,使属性除了能在该类型的构造函数中可…...
深度学习之Autoencoders GANs for Anomaly Detection 视频异常检测
在视频异常检测(Video Anomaly Detection)任务中,Autoencoders(自编码器) 和 GANs(生成对抗网络) 是常用的深度学习模型,它们在检测视频中的异常事件(如入侵、破坏、非法行为等)方面发挥着重要作用。通过分析视频帧的时空特征,这些模型能够识别出与正常行为模式不同…...
实现按键按下(低电平)检测到下降沿
按照流程进行编程 步骤1: 初始化函数 包括时基工作参数配置 输入通道配置 更新中断使能 使能捕获、捕获中断及计数器 HAL_TIM_IC_Init(&ic_handle) //时基参数配置 HAL_TIM_IC_ConfigChannel(&ic_handle,&ic_config,TIM_CHANNEL_2) //输…...
【21天学习AI底层概念】day5 机器学习的三大类型不能解决哪些问题?
机器学习的三大类型——监督学习、无监督学习和强化学习,虽然可以应用于许多问题,但并非所有问题都能通过这些方法有效解决。每种类型的机器学习都有其局限性,具体如下: 1. 监督学习 (Supervised Learning) 监督学习是通过训练数…...
八股—Java基础(一)
目录 一、Java概述 1、Java语言有哪些特点? 2、JVM、JDK、JRE有什么区别? 3、什么是跨平台性?原理是什么 4、Java和C有什么关系,它们有什么区别? 5、JVM、JRE和JDK的关系是什么? 6、什么是字节码? …...
PWM调节DCDC参数计算原理
1、动态电压频率调整DVFS SOC芯片的核电压、GPU电压、NPU电压、GPU电压等,都会根据性能和实际应用场景来进行电压和频率的调整。 即动态电压频率调整DVFS(Dynamic Voltage and Frequency scaling),优化性能和功耗。 比如某SOC在…...
设计一个基础JWT的多开发语言分布式电商系统
在设计一个分布式电商系统时,保证系统的可扩展性、性能以及跨语言的兼容性是至关重要的。随着微服务架构的流行,越来越多的电商系统需要在多个服务间共享信息,并且保证服务的安全性。在这样的场景下,JSON Web Token(JW…...
基础开发工具-编辑器vim
vim操作键盘图 下图是比较基础的vim操作键盘图 (IDE例子) vi/vim的区别简单点来说,它们都是多模式编辑器,不同的是vim是vi的升级版本,它不仅兼容vi的所有指令,⽽且还有⼀些新的特性在⾥⾯。例如语法加亮&a…...
C#速成(文件读、写操作)
导包 using System.IO;1、写入文件(重要) StreamWriter sw new StreamWriter("C:\Users\29674\Desktop\volumn.txt");//创建一个TXT的文件 sw.WriteLine(textBox2.Text);//写入文件的内容 sw.Close();//关闭2、读取文件(不重要&…...
11、多态
1、多态介绍 1.1、认识多态 “一个接口,多种状态”。 接口在运行期间,根据传入的参数来决定具体调用的函数,最终采取不同的执行策略。 比如:一个系统的后台,管理员登录后进入的界面和普通用户进入的界面是不一样的。 …...
bain.js(十二):RNN神经网络实战教程 - 音乐乐谱生成 -人人都是作曲家~
系列文章: (一):可以在浏览器运行的、默认GPU加速的神经网络库概要介绍(二):项目集成方式详解(三):手把手教你配置和训练神经网络(四)…...
嵌入式硬件-- 元器件焊接
1.锡膏的使用 锡膏要保存在冰箱里。 焊接排线端子;138度的低温锡(锡膏), 第一次使用,直接拿东西挑一点涂在引脚上,不知道多少合适,加热台加热到260左右,放在上面观察锡融化&#…...