Linux学习第13天:嵌入式LinuxLED驱动开发:一字一符总见情
在正式写这篇笔记前,有一个事情必须要说一下。昨天更新的基于API函数的字符设备驱动开发按照正常的教程来说应该在本笔记后一天更新才对。但是由于我一时的疏忽,跳过了本笔记。在昨天学习基于API函数的时候造成了一定程度的困扰。今天重翻教程的时候才发现昨天漏了一节,今天补上。从这件小小的事情上我也明白了一个道理,学习不可一蹴而,都要一步一个脚印按部就班的去学习,按照教程原本的顺序一点一点去查缺补漏。想着提高速度而跳过某些章节,而你忽略的这些问题肯定会以其他各种各样的形式迸发出来。算是正式笔记前的一个小小说明吧。
这篇笔记主要介绍了嵌入式ARMLinuxLED驱动开发。LED灯的驱动作为第一个要学习的外设,也是第一个字符设备,主要内容包括LED灯驱动原理、驱动程序及测试程序的编写以及运行测试。
本笔记的思维导图如下:

一、Linux下LED灯驱动原理
Linux下的任何外设驱动,最终都是要配置相应的硬件寄存器。本节要驱动的LED,对应的IO口为GPIO1_IO03.
1.地址映射
MMU:内存管理单元。主要功能有两点:
a.完成虚拟空间到物理空间的映射;
b.内存保护,设置好存储器的访问权限,设置虚拟存储空间的缓冲特性。
关于a,可以用下图进行说明:

物理内存和虚拟内存之间的相互转换的两个函数为ioremap和iounmap.
1)、ioremap函数
ioremap函数用于获取指定物理地址空间对应的虚拟地址空间。其定义如下:
1 #define ioremap(cookie,size) __arm_ioremap((cookie), (size),
MT_DEVICE)
2
3
void __iomem * __arm_ioremap(phys_addr_t phys_addr, size_t size,
unsigned int mtype)
4 {
5 return arch_ioremap_caller(phys_addr, size, mtype,
__builtin_return_address(0));
6 }
上述代码真正起作用的是函数_arm_ioremap,其参数及返回值含义如下:
phys_addr:要映射给的物理起始地址。
size:要映射的内存空间大小。
mtype:ioremap的类型,选择MT_DEVICE.
返回值:_iomem类型的指针,指向映射后的虚拟空间首地址。
假设要获取I.MX6ULL的IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03寄存器对应的虚拟地址,使用如下代码:
#define SW_MUX_GPIO1_IO03_BASE (0X020E0068)//物理地址
static void __iomem* SW_MUX_GPIO1_IO03;//虚拟地址
SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);//32位----4字节
2)、iounmap函数
卸载驱动的时候,使用iounmap函数释放掉ioremap函数所做的映射,其函数原型如下:
void iounmap (volatile void __iomem *addr)
addr为要取消的虚拟地址空间首地址。
假设要取消I.MX6ULL的IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03寄存器对应的地址映射,使用如下代码:
iounmap(SW_MUX_GPIO1_IO03);
2.I/O内存访问函数
当外部寄存器或内存映射到IO空间时,称为I/O端口。【ARM下没有这个概念】
当外部寄存器或内存映射到内存空间时,称为I/O内存。
Linux内核建议使用一组操作函数来对映射后的内存进行读写操作,而不是直接通过指针访问这些地址。
1)、读操作函数
读操作函数有如下几个:
1 u8 readb(const volatile void __iomem *addr)
2 u16 readw(const volatile void __iomem *addr)
3 u32 readl(const volatile void __iomem *addr)
以上三个函数分别对应8bit、16bit、32bit读操作。
addr就是要读取写内存地址。
返回值就是读取到的数据。
2)、写操作函数
写操作函数有如下几个:
1 void writeb(u8 value, volatile void __iomem *addr)
2 void writew(u16 value, volatile void __iomem *addr)
3 void writel(u32 value, volatile void __iomem *addr)
以上三个函数分别对应8bit、16bit、32bit读操作。
value是要写入的数值。
addr就是要写入的地址。
二、程序编写
1.实验程序编写
通过控制开发板上I.MX6ULL的GPIO1_IO03引脚,从而控制LED灯的亮灭。
1)、LED灯驱动程序编写
1 #include <linux/types.h>
2 #include <linux/kernel.h>
3 #include <linux/delay.h>
4 #include <linux/ide.h>
5 #include <linux/init.h>
6 #include <linux/module.h>
7 #include <linux/errno.h>
8 #include <linux/gpio.h>
9 #include <asm/mach/map.h>
10 #include <asm/uaccess.h>
11 #include <asm/io.h>
12 /***************************************************************
13 Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
14 文件名 : led.c
15 作者 : 左忠凯
16 版本 : V1.0
17 描述 : LED 驱动文件。
18 其他 : 无
19 论坛 : www.openedv.com
20 日志 : 初版 V1.0 2019/1/30 左忠凯创建
21 ***************************************************************/
22 #define LED_MAJOR 200 /* 主设备号 */
23 #define LED_NAME "led" /* 设备名字 */
24
25 #define LEDOFF 0 /* 关灯 */
26 #define LEDON 1 /* 开灯 */
27
28 /* 寄存器物理地址 */
29 #define CCM_CCGR1_BASE (0X020C406C)
30 #define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
31 #define SW_PAD_GPIO1_IO03_BASE (0X020E02F4)
32 #define GPIO1_DR_BASE (0X0209C000)
33 #define GPIO1_GDIR_BASE (0X0209C004)
34
35 /* 映射后的寄存器虚拟地址指针 */
36 static void __iomem *IMX6U_CCM_CCGR1;
37 static void __iomem *SW_MUX_GPIO1_IO03;
38 static void __iomem *SW_PAD_GPIO1_IO03;
39 static void __iomem *GPIO1_DR;
40 static void __iomem *GPIO1_GDIR;
41
42 /*
43 * @description : LED 打开/关闭
44 * @param - sta : LEDON(0) 打开 LED, LEDOFF(1) 关闭 LED
45 * @return : 无
46 */
47 void led_switch(u8 sta)
48 {
49 u32 val = 0;
50 if(sta == LEDON) {
51 val = readl(GPIO1_DR);
52 val &= ~(1 << 3);
53 writel(val, GPIO1_DR);
54 }else if(sta == LEDOFF) {
55 val = readl(GPIO1_DR);
56 val|= (1 << 3);
57 writel(val, GPIO1_DR);
58 }
59 }
60
61 /*
62 * @description : 打开设备
63 * @param – inode : 传递给驱动的 inode
64 * @param - filp : 设备文件, file 结构体有个叫做 private_data 的成员变量
65 * 一般在 open 的时候将 private_data 指向设备结构体。
66 * @return : 0 成功;其他 失败
67 */
68 static int led_open(struct inode *inode, struct file *filp)
69 {
70 return 0;
71 }
72
73 /*
74 * @description : 从设备读取数据
75 * @param - filp : 要打开的设备文件(文件描述符)
76 * @param - buf : 返回给用户空间的数据缓冲区
77 * @param - cnt : 要读取的数据长度
78 * @param - offt : 相对于文件首地址的偏移
79 * @return : 读取的字节数,如果为负值,表示读取失败
80 */
81 static ssize_t led_read(struct file *filp, char __user *buf,
size_t cnt, loff_t *offt)
82 {
83 return 0;
84 }
85
86 /*
87 * @description : 向设备写数据
88 * @param - filp : 设备文件,表示打开的文件描述符
89 * @param - buf : 要写给设备写入的数据
90 * @param - cnt : 要写入的数据长度
91 * @param - offt : 相对于文件首地址的偏移
92 * @return : 写入的字节数,如果为负值,表示写入失败
93 */
94 static ssize_t led_write(struct file *filp, const char __user *buf,
size_t cnt, loff_t *offt)
95 {
96 int retvalue;
97 unsigned char databuf[1];
98 unsigned char ledstat;
99
100 retvalue = copy_from_user(databuf, buf, cnt);
101 if(retvalue < 0) {
102 printk("kernel write failed!\r\n");
103 return -EFAULT;
104 }
105
106 ledstat = databuf[0]; /* 获取状态值 */
107
108 if(ledstat == LEDON) {
109 led_switch(LEDON); /* 打开 LED 灯 */
110 } else if(ledstat == LEDOFF) {
111 led_switch(LEDOFF); /* 关闭 LED 灯 */
112 }
113 return 0;
114 }
115
116 /*
117 * @description : 关闭/释放设备
118 * @param – filp : 要关闭的设备文件(文件描述符)
119 * @return : 0 成功;其他 失败
120 */
121 static int led_release(struct inode *inode, struct file *filp)
122 {
123 return 0;
124 }
125
126 /* 设备操作函数 */
127 static struct file_operations led_fops = {
128 .owner = THIS_MODULE,
129 .open = led_open,
130 .read = led_read,
131 .write = led_write,
132 .release = led_release,
133 };
134
135 /*
136 * @description : 驱动出口函数
137 * @param : 无
138 * @return : 无
139 */
140 static int __init led_init(void)
141 {
142 int retvalue = 0;
143 u32 val = 0;
144
145 /* 初始化 LED */
146 /* 1、寄存器地址映射 */
147 IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);
148 SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);
149 SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);
150 GPIO1_DR = ioremap(GPIO1_DR_BASE, 4);
151 GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE, 4);
152
153 /* 2、使能 GPIO1 时钟 */
154 val = readl(IMX6U_CCM_CCGR1);
155 val &= ~(3 << 26); /* 清除以前的设置 */
156 val |= (3 << 26); /* 设置新值 */
157 writel(val, IMX6U_CCM_CCGR1);
158
159 /* 3、设置 GPIO1_IO03 的复用功能,将其复用为
160 * GPIO1_IO03,最后设置 IO 属性。
161 */
162 writel(5, SW_MUX_GPIO1_IO03);
163
164 /* 寄存器 SW_PAD_GPIO1_IO03 设置 IO 属性 */
165 writel(0x10B0, SW_PAD_GPIO1_IO03);
166
167 /* 4、设置 GPIO1_IO03 为输出功能 */
168 val = readl(GPIO1_GDIR);
169 val &= ~(1 << 3); /* 清除以前的设置 */
170 val |= (1 << 3); /* 设置为输出 */
171 writel(val, GPIO1_GDIR);
172
173 /* 5、默认关闭 LED */
174 val = readl(GPIO1_DR);
175 val |= (1 << 3);
176 writel(val, GPIO1_DR);
177
178 /* 6、注册字符设备驱动 */
179 retvalue = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
180 if(retvalue < 0){
181 printk("register chrdev failed!\r\n");
182 return -EIO;
183 }
184 return 0;
185 }
186
187 /*
188 * @description : 驱动出口函数
189 * @param : 无
190 * @return : 无
191 */
192 static void __exit led_exit(void)
193 {
194 /* 取消映射 */
195 iounmap(IMX6U_CCM_CCGR1);
196 iounmap(SW_MUX_GPIO1_IO03);
197 iounmap(SW_PAD_GPIO1_IO03);
198 iounmap(GPIO1_DR);
199 iounmap(GPIO1_GDIR);
200
201 /* 注销字符设备驱动 */
202 unregister_chrdev(LED_MAJOR, LED_NAME);
203 }
204
205 module_init(led_init);
206 module_exit(led_exit);
207 MODULE_LICENSE("GPL");
208 MODULE_AUTHOR("zuozhongkai");
在上述的代码中,关于LED初始化有以下几步:
(1)寄存器地址映射。
(2)使能GPIO1时钟。
(3)设置GPIO1_IO03复用功能。
(4)设置设置GPIO1_IO03输出功能。
(5)默认关闭LED。
(6)注册字符设备驱动。
2)、测试程序APP编写
led驱动加载成功以后,手动创建/dev/led节点,应用APP通过操作/dev/led文件来完成对LED设备的控制,向/dev/led写0表示关闭LED灯,写1表示打开LED灯。新建ledApp.c文件,其内容如下:
1 #include "stdio.h"
2 #include "unistd.h"
3 #include "sys/types.h"
4 #include "sys/stat.h"
5 #include "fcntl.h"
6 #include "stdlib.h"
7 #include "string.h"
8 /***************************************************************
9 Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
10 文件名 : ledApp.c
11 作者 : 左忠凯
12 版本 : V1.0
13 描述 : LED 驱测试 APP。
14 其他 : 无
15 使用方法 : ./ledtest /dev/led 0 关闭 LED
16 ./ledtest /dev/led 1 打开 LED
17 论坛 : www.openedv.com
18 日志 : 初版 V1.0 2019/1/30 左忠凯创建
19 ***************************************************************/
20
21 #define LEDOFF 0
22 #define LEDON 1
23
24 /*
25 * @description : main 主程序
26 * @param - argc : argv 数组元素个数
27 * @param - argv : 具体参数
28 * @return : 0 成功;其他 失败
29 */
30 int main(int argc, char *argv[])
31 {
32 int fd, retvalue;
33 char *filename;
34 unsigned char databuf[1];
35
36 if(argc != 3){
37 printf("Error Usage!\r\n");
38 return -1;
39 }
40
41 filename = argv[1];
42
43 /* 打开 led 驱动 */
44 fd = open(filename, O_RDWR);
45 if(fd < 0){
46 printf("file %s open failed!\r\n", argv[1]);
47 return -1;
48 }
49
50 databuf[0] = atoi(argv[2]); /* 要执行的操作:打开或关闭 */
51
52 /* 向/dev/led 文件写入数据 */
53 retvalue = write(fd, databuf, sizeof(databuf));
54 if(retvalue < 0){
55 printf("LED Control Failed!\r\n");
56 close(fd);
57 return -1;
58 }
59
60 retvalue = close(fd); /* 关闭文件 */
61 if(retvalue < 0){
62 printf("file %s close failed!\r\n", argv[1]);
63 return -1;
64 }
65 return 0;
66 }
上述内容是对led的驱动文件最基本的打开、关闭、写操作等。
三、运行测试
1.编译驱动程序和测试程序
1)、编译驱动程序
用到的Makefile文件内容如下:
1 KERNELDIR := /home/zuozhongkai/linux/IMX6ULL/linux/temp/linux-imxrel_imx_4.1.15_2.1.0_ga_alientek
......
4 obj-m := led.o
......
11 clean:
12 $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
输入如下指令生成.ko模块文件。
make -j32
2)、编译测试程序
用到如下指令:
arm-linux-gnueabihf-gcc ledApp.c -o ledApp
编译成功以后会得到ledApp这个应用程序。
2.运行测试
将编译出来的led.ko和ledApp这两个文件拷贝到rootfs/lib/modules/4.1.15目录中,重启开发板,进入到rootfs/lib/modules/4.1.15目录,输入如下命令加载led.ko驱动模块:
depmod//第一次加载驱动时需要运行该命令
modprobe led.ko//加载驱动
创建/dev/led设备节点,命令如下:
mknod /dev/led c 200 0
之后,使用如下命令测试驱动是否正常:
./ledAPP /dev/led 1 //打开LED灯./ledAPP /dev/led 0//关闭LED灯
观察LED的亮暗变化,判断驱动程序是否正常。
最后一步,驱动卸载,使用如下指令:
rmmod led.ko
四、总结
总结一下,本笔记主要学习了ARMLinuxLED驱动开发的方式方法,介绍了通过类似裸机开发,通过控制寄存器从而使LED打开或关闭的方法。
Linux版本号4.1.15 芯片MX6ULL
本文为参考正点原子开发板配套教程整理而得,仅用于学习交流使用,不得用于商业用途。
相关文章:
Linux学习第13天:嵌入式LinuxLED驱动开发:一字一符总见情
在正式写这篇笔记前,有一个事情必须要说一下。昨天更新的基于API函数的字符设备驱动开发按照正常的教程来说应该在本笔记后一天更新才对。但是由于我一时的疏忽,跳过了本笔记。在昨天学习基于API函数的时候造成了一定程度的困扰。今天重翻教程的时候才发…...
ModuleNotFoundError: No module named ‘omni‘
install isaac sim on linux open the isaac sim folder in /home//.local/share/ov/pkg/isaac_sim-2022.1.1 source setup_python_env.sh ./python.sh standalone_examples/replicator/offline_generation.pyNo module named ‘omni.isaac’...
题解:ABC320B - Longest Palindrome
题解:ABC320B - Longest Palindrome 题目 链接:Atcoder。 链接:洛谷。 难度 算法难度:C。 思维难度:C。 调码难度:C。 综合评价:入门。 算法 字符串处理。 思路 通过双层循环分别枚…...
大模型从入门到应用——LangChain:代理(Agents)-[代理执行器(Agent Executor):结合使用Agent和VectorStore]
分类目录:《大模型从入门到应用》总目录 代理执行器接受一个代理和工具,并使用代理来决定调用哪些工具以及以何种顺序调用。本文将参数如何结合使用Agent和VectorStore。这种用法是将数据加载到VectorStore中,并希望以Agent的方式与之进行交互…...
【算法题】100040. 让所有学生保持开心的分组方法数
题目: 给你一个下标从 0 开始、长度为 n 的整数数组 nums ,其中 n 是班级中学生的总数。班主任希望能够在让所有学生保持开心的情况下选出一组学生: 如果能够满足下述两个条件之一,则认为第 i 位学生将会保持开心: …...
TrOCR – 基于 Transformer 的 OCR 入门
一、TrOCR 架构 近些年,光学字符识别 (OCR) 出现了多项创新。它对零售、医疗保健、银行和许多其他行业的影响是巨大的。与深度学习的许多其他领域一样,OCR领域也看到了Transformer 神经网络的重要性和影响。如今,出现了像TrOCR(Transformer OCR)这样的模型,它在准确性方面…...
单例模式优缺点
单例模式是一种创建型设计模式,其主要目的是确保类只有一个实例,并提供全局访问点来获取该实例。单例模式具有一些优点和缺点,下面我将列出它们: **优点:** 1. **全局唯一性**:单例模式确保在应用程序中只…...
【Java 基础篇】Java 字节流详解:从入门到精通
Java中的字节流是处理二进制数据的关键工具之一。无论是文件操作、网络通信还是数据处理,字节流都发挥着重要作用。本文将从基础概念开始,深入探讨Java字节流的使用,旨在帮助初学者理解和掌握这一重要主题。 什么是字节流? 在Ja…...
Vue记录(下篇)
Vuex getters配置项 *Count.vue <template><div><h1>当前求和为:{{$store.state.sum}}</h1><h3>当前求和的10倍为:{{$store.getters.bigSum}}</h3><select v-model.number"n"><option value&q…...
【测试开发】概念篇 · 测试相关基础概念 · 常见开发模型 · 常见测试模型
【测试开发】概念篇 文章目录 【测试开发】概念篇1. 什么是需求1.1 需求的定义1.2 为什么有需求1.3 测试人员眼里的需求1.4 如何深入了解需求 2. 什么是测试用例2.1 为什么有测试用例2.2 练习>手机打电话 3. 什么是bug4. 开发模型和测试模型4.1 软件生命周期4.2 开发模型4.3…...
1. 快速体验 VSCode 和 CMake 创建 C/C++项目
1. 快速体验 VSCode 和 CMake 创建 C/C项目 本章的全部代码和markdown文件地址: CMake_Tutorial,欢迎互相交流. 此次介绍的内容都是针对于 Linux 操作系统上的开发过程. 1.1 安装开发工具 VSCode: 自行下载安装, 然后安装插件 Cmake:在 Ubuntu 系统上, 可以采用 ap…...
【JAVA-Day18】用大白话讲解 Java 中的内存机制
标题 用大白话讲解 Java 中的内存机制摘要引言一、Java 内存机制1.1 栈内存1.2 堆内存 二、Java 如何管理内存三、合理管理内存的必要性与其他方式相比优势劣势建议四、总结参考资料 博主 默语带您 Go to New World. ✍ 个人主页—— 默语 的博客👦🏻 《…...
[Hadoop] start-dfs.sh ssh报错
Permission denied (publickey 决解方案 相关命令 cd ~/.sshssh-keygen -t rsa -p""cat id_rsa.pub >> authorized_keyschmod 0600 authorized_keys 相关链接Hadoop: start-dfs.sh permission denied - Stack Overflow Java HotSpot(TM) Server VM warning…...
amlogic 多wifi 多bluetooh 兼容方案
WiFi部分: vendor/amlogic/common/wifi_bt/wifi/configs/wifi.mk 或者 hardware/amlogic/wifi/configs/wifi.mk ################################################################################## realtek wifi ifneq ($(filter rtl8188eu rtl8188ftv rtl8192eu rtl8…...
Apache Hive概述,模拟实现Hive功能,Hive基础架构
1、Apache Hive 概述 1.1、分布式SQL计算 对数据进行统计分析,SQL是目前最为方便的编程工具。 大数据体系中充斥着非常多的统计分析场景 所以,使用SQL去处理数据,在大数据中也是有极大的需求的。 MapReduce支持程序开发(Java…...
postgresql|数据库|centos7下基于postgresql-12的主从复制的pgpool-4.4的部署和使用
前言: postgresql数据库只用自身的一些配置是无法做到最优的优化的,需要通过一些外置插件(中间件)来提高服务器的整体性能,通俗的说就是数据库仅仅依靠自身是无法达到性能最优的,很多时候需要更改数据库的…...
python之pyQt5实例:PyQtGraph的应用
1、显示逻辑 "MainWindow": "这是主窗口,所有的其他组件都会被添加到这个窗口上。", "centralwidget": "这是主窗口的中心部件,它包含了其他的部件。","pushButton": "这是一个按钮,…...
Java——键盘输入的几种常见方式
Java——键盘输入的几种常见方式 文章目录: Java——键盘输入的几种常见方式一、IO流二、Scanner类三 、BufferedReader写入 一、IO流 在Java的输入中,是以输入流的形式进入程序,因此无法直接指定输入的类型,仅能读取键盘上的内容…...
Shell脚本中文英文多语言国际化和命令行批处理(bash sh cmd bat)中定义函数的简单写法
文章目录 命令行脚本参考 - bat命令行脚本参考 - bash值得学习的知识点1. 识别终端使用的语言2. 函数的编写3. 获取用户的输入4. bat文件老是乱码怎么办 有时候为了方便别人使用,我们会选择去编写各种各样的命令行脚本:给Windows用户编写.bat cmd批处理脚…...
stringBuffer.append(analyze);使用这个拼接时候如何在字符串参数字符串参数整数参数字符串数组参数内容之间添加空格
stringBuffer.append(analyze);使用这个拼接时候如何在字符串参数字符串参数整数参数字符串数组参数内容之间添加空格? 在添加参数到 StringBuffer 时,你可以在每次添加参数之后都添加一个空格,如下所示: StringBuffer stringBu…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
