USB详解

2023-10-30

转载自http://blog.163.com/zhsh_email/blog/static/19786900200611259521640/

usb作为一种串行接口,应用日益广泛。如同每个工程设计人员必须掌握I2C,RS232这些接口一样,我们也必须掌握usb.

但是usb的接口协议实在有点费解,linux uhci驱动作者之一Alan Stern曾经就说过“The USB documentation is downright evil. Most    of it is just crap, written by a committee. You're better off ignoring most of it ”。

本文将从整体上介绍usb协议,包括usb host ,usb hub,usb function。希望能给读者一个总体上的了解。也因此,文章将分成相应的三部分讲解 。

一。usb function

1。初识usb.usb是一种串行接口协议,它靠d+,d-两条数据线构成的差分线来进行数据传输,这让我们非常感兴趣它到底和我们通常熟悉两线rs232/485有何区别。了解这种区别有助于我们对usb作一个深入的了解。那么让我们回想一下到底一个两线rs232的数据是如何传送的,如图一:

在这里我们的重点在于,我们发现要在串行口传送数据一个最体码的要求恐怕就是:要知道数据传输何时开始,何时结束。即如何delimit.那么rs232怎么做的。显然,在idle(空闲)时,即无数据传送时,数据线处于高电平,等到有数据开始传送,发送方首先拉低数据线(start),表示数据传输开始,接受端也因为这个“start”信号开始准备接受即将到来的数据,类似一次握手,随后,在两者之间的数据传送开始,结束后主方再次拉高数据线,表示结束传输,自此两者重新进入Idle状态。等待下一轮传送开始。

了解了rs232,那么我们自然想到usb如何做到这个呢,既然是串行位流传输,也理所当然的解决这个问题。没错,Usb协议必然要解决这个问题,让我们作一个类似rs232的比较吧!类似于rs232,usb的传输桢如图二:

(这里我们暂时忽略这个传输所代表的意义)为了说明问题,我们对一些问题简化,我们定义这样几个状态:
假设D+,D-分别表示usb信号线的电平信号。那么对于usb full speed function(high speed ,low speed是不同的),我们定义差分数据线上可能出现的四个状态:

Data J state:D+=1,D-=0;
Data K state:D+=0,D-=1;
SE0:D+=D-=0;
SE1:D+=D-=1;

那么上面的图中,相应的也可表示为图三:

这个对usb full speed function来说,idle状态将处于Data J state,se0表示一桢结束。看这个图是不是很像我们熟悉的rs232。没错!!!他们确实很相似。在无数据传输时,它们都处于Idle状态,当要开始传输数据时,先发一个sync(同步信号,rs232为start,usb为一sync字节,见协议说明)信号进行“握手”,而后开始传输,当传输要结束时,发一stop信号(usb为一个se0状态表示要结束传输),最后又进入idle态等待新的传输。不过,你可能更加注意到,他们还是不同的。不同在于usb是按"packet" 进行传输的,就是说它传输的最小单位是packet,而rs232是按字节传送的,也即它的最小传送单位是字节。既然是按pakcet传送,想想我们相较于rs232的按字节单位传输,我们可以得到哪些“好处”。想想看,pakcet的好处不就在于我们可以灵活的定义数据的传送格式,传送方式,从而可以适应各种各样的串行设备,这不就是所谓的“通用串行总线”吗?

简介:从本节开始,我们将介绍usb的传输机制。这节先介绍usb现有传输方式的背景知识,做为对下节将要展开的四种传输类型,描述符,等相关知识的一个导引。

2。usb传输。
我们在上一节中了解到了usb的“packet”的感念,了解到了usb传送一个packet总是以sync开始,以eop结束,这个称为delimiter,即标记packet的始末。有了packet,我们就可以在usb总线上传输数据了。但是这还不够,比如数据传送方向,即传回usb主机还是传下usb从机,数据传送的地址,数据传送的类型(这些后面我们将会知道)这些信息在传输之前是必须搞清楚的,那么这个信息如何得知呢,看来这就需要我们定一套基于packet的“协议”了。主机与从机在传输中均遵循这套“协议”,那么这些问题就可以迎刃而解。事实上,usb的一次数据传输总是遵循这样的“协议”的:

首先,主机发第1个packet给从机,声明数据传送方向,数据传输地址,数据传输类型。
其次,主机发第2个至第n个packet载有实际数据
最后,从机返回一个packet是一个ACK包,报告数据传输的结果,比如接受出错或成功等信息,这样主机就可以借此了解到这次传输情况,从而有可能来作出相应措施如决定是否重发

这里我们考虑的是主机发数据给从机的情况,那么从机发数据给主机时,是不是也可以这样呢?当然可以,比如从机要发数据给主机时,也可以采取同主机类似的方式:

首先,从机发第1个packet给主机,声明数据传送方向,数据传输地址,数据传输类型。
其次,从机发第2个至第n个packet载有实际数据
最后,主机返回一个packet是一个ACK包,报告数据传输的结果,比如接受出错或成功等信息,这样从机就可以借此了解到这次传输情况,从而有可能来作出相应措施如决定是否重发。

基本上可以归结为一个“三段式”传输

这里有人可能注意到了,对这样一个传输机制,从机和主机的功能将是一样的,因为这样的实现机制,从机可能在某一时刻是主机,某一时刻又可能是从机,因为他们要实现同样的功能。这样实现起来的复杂性也将是一样的。

注:这里概念或许容易混淆,其实,我们这里的主机(master)和从机(slaver)是一个transceiver,即可收可发。相应的,在某一时刻,master在发数据,我们称其为transmitter,在接受时我们称为receiver.对slaver同样。

我们可能还注意到了,usb这种按pakcet传输的方式在实现时已经很复杂了(至少比rs232要复杂多吧),至少我们目前看来主从机功能一样这样的实现方式似乎还是可行,但是后面我们谈到usb host时将会了解到host的功能是如何的复杂,以至于让一个usb function 也带上如此的功能成本和实现复杂性将陡然上升。作为面向广范应用的usb,这是我们不允许的。我们期望的是一个使用usb 的udisk,使用usb的光驱,使用usb的耳麦等等这些东西不要因为usb而变得昂贵,复杂。

正是因为这个原因,usb从机的传输发式便由上面的方式改成了下面的方式进行:

首先,主机发第1个packet给从机,声明数据传送方向,数据传输地址,数据传输类型。
其次,从机收到主机送来的第一个packet后,再发第2个至第n个packet载有实际数据
最后,主机返回一个packet是一个ACK包,报告数据传输的结果,比如接受出错或成功等信息,这样从机就可以借此了解到这次传输情况,从而有可能来作出相应措施如决定是否重发。

而对于usb 主机传输方式保持不变。


对于这样的改变,我们马上就有疑问了:这个改变的传输方式是和未改变之前的等价吗。当然,不全等价。问题在哪里?仔细观察一下便知,两者区别在于第一个packet是由谁发起的。未改变之前,第一个packet总是由要传送数据的一方发起,而改变之后的第一个Packet总是由主机发起。这样,就变成如果从机要发送数据给主机时,总是由主机发起(第一个packet),然后从机开始传送。
可能初次接触我们会感觉怪怪的,怎么从机要给主机发送数据前反而要主机先发packet给从机。   这样行吗,我们要说这样是可以的,因为通常一次传输交互的产生,并非无来由的产生,这些都是由程序员控制的,控制usb何时收,何时发,及发给谁!!!

这里我们就注意到了,usb function(总是作为从机)的功能一下从原来与主机具有相同功能的tranceiver变成了现在仅具发送(或接收)功能的transmitter(或Receiver)实现的复杂性及成本可想而知也就相应得减小了。

简介:本节介绍usb full speed function的四种传输类型。

 

 


上节中我们了解到了usb hostusb function 之间采用的是一种“非对称”的传输,也就是说,无论usb接受数据还是发送数据,都是由usb host首先发起。即传输的第一个packet总是由usb host发出的。这个packet将声明本次即将进行的数据传输方向,数据传输地址和数据传输类型。

 

Control Transfers)

: 或许你已经注意到了,一个usb host端口并不是仅仅支持一个Usb function.如图1,

通过usb hub,一个usb host端口可以连接usb鼠标,usb键盘,Usb写字板......。要连接这么多东西在同一个usb host上,我们通常会有一个基本问题,即usb host如何识别这些被连接在它的端口上的设备呢。正如通常的主从式通讯系统一样,如rs485多机通讯,我们通常是用一个特定的地址标志每一个从设备。对这里的usb,我们采用同样的方法,将为每个挂接在该usb host上的usb function指定一个特定地址,通过这个特定地址来识别每个usb function.看来这将是一个usb function在数据传输之前必须解决的问题--得到它的地址分配。

这个“地址指定”的过程需要usb host通知usb function才能完成,这个交互过程就是一个控制式传输。通过这个“控制式传输”,usb host将指定地址给usb function ,以为即将进行的正式通讯做好准备工作。这里细心的读者可能已经注意到了,既然usb host总要分配地址给usb function才能进行正式的数据传输工作,那么usb host将如何与一个初始时未分配地址的usb function进行交互来分配地址呢。这里,是这样解决的:usb协议保留了一个“通用地址”0,usb host 通过这个地址0来和初始未分配地址的usb function进行通讯,进行一些初始的准备工作,诸如这里的为它非配一个特定地址。后面我们就会了解到,usb除了配置地址外,还有一些其它参数需要事先主从双方达成共识。这些参数也都是通过控制式传输完成的。一个Usb 的控制式传输如图二示:

一个Usb的控制式传输总是分为两个或三个阶段进行传输:setup stage,data stage(视情况而定),status stage。

 

  1. 首先是setup stage,联系上节所说的Usb传输模式,usb Host总是先发起第一个packet--这里它
    1. 首先发起setup,
    2. 之后发起以data0为起始的setup data,
    3. 最后usb function回应ack结束一次交互。
  2. 其次如果有data stage,类似的,还是按照上节说的usb传输模式,
      1. usb host总是先发起第一个Packet--Out(或in),
      2. 之后usb host(或usb function)发起以data1为起始的payload data,
      3. 最后Usb fuction(或usb host)回应ack结束一次交互。
    1. 如果数据未传完,继续data stage,同上继续。
  3. 最后是status stage,类似的,
    1. usb host首先发起第一个Packet--in(或out),
    2. 之后usb function(或usb host)发起以data1为起始的Null data(0长度),
    3. 最后Usb host(或usb function)回应ack结束一次交互。

 


如此,整个控制式传输结束。 你或许有疑问,data stage为什么进行了多次而非一次完成?实际上,usb总是将一批大量的数据分成了许多小段来进行传输,称为一个pay load。这样传输的目的是容易对传输进行控制。既然一次大量的数据总是被分成一段一段来分次传输,那么这里就出现了一个需要事先确定的参数(wMaxPacketSize):即每次这个小段有多大。这个参数如地址指派一样,正式传输之前需要事先达成共识。通过控制式传输,现在我们已经完成了usb function的地址指定等参数的设置工作,下一步可以进行正式的数据传输了。

bulk Transactions

我们终于等到usb function 配置完成,现在我们的任务是要传送一批数据,这里可以使用批量数据传输(bulk Transactions)。 一个批量传输总是按照如图所示方式进行,

  1. 首先,usb host发起第一个Packet--in(或out),表示要开始数据传输了。
  2. 其次,usb function(或usb host)发起以data1(或data0)为起头的payload data,开始一次交互。
  3. 再其次,usb host(或Usb function)发起ack回应这次交互。 如果数据还为传完,继续上述过程,即:
    1. 首先,usb host再次发起一个Packet--in(或out),表示又要开始数据传输了。
    2. 其次,usb function(或usb host)发起以data0(或data1)为起头的payload data,开始又一次交互。
    3. 再次,usb host(或Usb function)发起ack回应这次交互。
    如此继续直至传输完成

这里的疑问依然是为什么一次可能传完的数据为什么分成多次进行传输,原因在上次介绍控制式传输式已经说明。后面我们就会明白,为什么这样可以方便控制传输过程。 仔细看看控制式的data stage采用的传输方式,是否就是批量传输方式呢?!注意,每次payload data的“牵头人”(preamble)在轮番掉换,最先是data1,接着data0,再是data1,......如此接替,只要有一次交互出现问题,这个接替规则就会被打破进而被Usb host识别而发现传输异常。所以这个交替的“牵头人”规则是可靠数据传输的所采取的措施之一。

 

Isochronous Transactions)和中断式传输(Interrupt Transactions

在批量数据传输中,触发一次批量数据传输总是“被动”的,就是说需要数据传输时Usb host并不会主动发起传输,而是需要得到你的指令。当你告诉它:“一切ok,让我们开始吧!” 这时它才开始数据传输。这种方式显然在某些情况下并不适合。比如音视频流,你无法要求它听从你的“指挥”,让它等你发指令给usb host,然后开始一次传输。我们需要的是一种“及时”传输。一个好的方案就是设置一个timer,按照tick发起usb传输。这个tick通常以1ms(usb full speed)为最小单位。这时,可以设置为每次1ms tick出现,usb host“自动”发起一次数据传输。那么这种方案具体如何来实现呢?看来最基本的要素便是一个发出tick的timer,而这个“timer”需要usb host和usb function(事实上还要包括usb hub)双方均能“看到”,从而协调工作,否则单方面的timer又有何意义?这个"timer"(或tick)在usb中使用一个特殊的packet实现,即是SOF。这个SOF由USB HOST 相当精确的以每1.00 ms ±0.0005 ms的时间周期发送给usb device,来在二者之间定时。从而usb function能够“及时”的了解到“现在时刻”。 现在我们在usb host和usb function之间建立起了“对时”机制。那么接下来看看刚才设想的“自动”传输如何实现。事实上,一旦usb host及usb function双方建立了一种时间机制,那么这种“自动”传输是很容易实现的。usb 实现同步式传输或中断式传输总是以一种类似于批量数据传输的方式进行的,唯一不同的是传输的触发不再是“被动”的,而是由SOF所建立的tick触发。

  1. 首先,时间到达,usb host发起第一个Packet--in(或out),表示要开始数据传输了。
  2. 其次,usb function(或usb host)发起以data1(或data0)为起头的payload data,开始一次交互。
  3. 再其次,如果是中断式传输,usb host(或Usb function)发起ack回应这次交互,如果是同步式传输,该步跳过。

如此重复上述步骤,即usb host等待下一个tick到达,并开始新一轮的交互。

这里我们注意到了,同步式传输和中断式传输二者虽然都是时间触发,但是中断式传输需要ack应答,而相反,同步式传输不需要。这个最大的区别决定了同步式传输是一种非可靠传输,但是因此换来了更多的usb传输时间。也因此,同步式传输的 payload data(对应wMaxPacketSize )通常相较于其他传输方式比较大,因为它消掉了ack所占有数据传输时间。这里还有一个地方值得注意的是tick的设定,这个tick也是需要事先usb host 和usb function达成共识的参数之一。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

USB详解 的相关文章

  • 如何记录数据库代码以查看数据库对象之间的依赖关系? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想为我的宠物项目编写文档 我的 PostgreSQL 数据库中有 30 个表 近 50 个视图和大约 30 个函数 存储过程 我想看
  • 使用 iTextSharp 5.3.3 和 USB 令牌签署 PDF

    我是 iTextSharp 和 StackOverFlow 的新手 我正在尝试使用外部 USB 令牌在 C 中签署 PDF 我尝试使用从互联网上挖掘的以下代码 Org BouncyCastle X509 X509CertificatePar
  • Matlab 图像数据的 hist 函数

    我是 Matlab 新手 我想制作自己的函数 与 imhist 显示图像数据的直方图 完成相同的工作 但我对此完全是新手 我不知道如何做开发这样的功能 我开始做一些东西 但它非常不完整 function output args myhist
  • Emacs Lisp 可以将 lambda 形式分配给像Scheme 这样的变量吗?

    在研究 Emacs Lisp 的符号单元时 我发现像这样的示例函数 defun a rest x x 我可以打电话 symbol function a 返回 lambda rest x x 如果我愿意的话我可以使用它 gt lambda r
  • 停止从标准输入读取

    我正在用 LInux C 编写一个简单的控制台应用程序 它接受来自命令行的用户输入 我在用std getline std cin std cin gt gt text在一个线程中 10 秒后 我想停止接受控制台输入并写一条短信 然后做其他事
  • 将 transaction.commit_manually() 升级到 Django > 1.6

    我继承了为 Django 1 4 编写的应用程序的一些代码 我们需要更新代码库以使用 Django 1 7 并最终更新到 1 8 作为下一个长期支持版本 在一些地方它使用旧风格 transaction commit manually and
  • JavaScript 测验在提出所有问题之前结束

    我现在正在学习 JavaScript 并且正在创建一个测验 我的测验运行正常 控制台中没有任何错误 但它会跳过问题 有时会在回答所有问题之前结束测验 即使给出正确答案 也会减少时间 我不太确定为什么它会这样做 因为在我看来它的编码是正确的
  • 如何将Scheme中的函数应用于另一个函数返回的参数列表?

    假设有两个函数 f 和 v 进一步假设 v 返回长度为 n 的列表 并且 f 需要恰好 n 个参数 我正在Scheme中寻找正确的语法 以将f应用于v返回的列表 如果我使用语法 f v v arguments 然后我收到一个关于 f 需要
  • 类方法作为 JavaScript 中的事件处理程序?

    JavaScript 中是否有最佳实践或通用方法将类成员作为事件处理程序 考虑以下简单示例
  • PLpgSQL 函数不返回匹配的标题

    当给定文本时 我试图返回电影名称以及演员和工作人员的数量 当我输入字符串并使用 ilike 时 我的查询返回不匹配的标题 我之前创建了一个视图 其中包含要在函数中输入的电影标题和工作人员数量 我的代码是 create or replace
  • 使用函数更改指针包含的地址

    如果我声明了一个指针p as int p 在主模块中 我可以更改包含的地址p通过分配p a where a是另一个已经声明的整型变量 我现在想通过使用以下函数来更改地址 void change adrs int q int newad q
  • PostgreSQL函数中sql语言和plpgsql语言的区别

    我很新数据库开发所以我对下面的例子有一些疑问 函数 f1 语言 SQL create or replace function f1 istr varchar returns text as select hello varchar istr
  • 有什么方法可以让 C/C++ 程序在 main() 之前崩溃吗?

    有什么办法可以让程序在 main 之前崩溃吗 使用 gcc 您可以使用以下标记函数构造函数属性 http gcc gnu org onlinedocs gcc Function Attributes html index g t 0040c
  • 内联还有用吗? [复制]

    这个问题在这里已经有答案了 我相信 inline已经过时了 因为我读过here https isocpp org wiki faq inline functions 无论您如何将函数指定为inline 这是允许编译器忽略的请求 编译器可能会
  • 如何在 kotlin 中检查 lambda 空值

    在 Kotlin 中如何检查 lambda 是否为空 例如 我有这样的签名 onError Throwable gt Unit 我如何区分它的默认值是应用于主体还是应用于此函数的值 您无法测试 lambda 的主体是否为空 因此它不包含源代
  • KDoc:插入代码片段

    如何在 Kotlin 的默认文档工具 KDoc 中插入代码片段 在 Java 中 我可以使用以下内容 Example usage pre code 64 JavaAnnotation public void foo Code code pr
  • 为不带引号的函数获取字符串参数

    我有一个函数 用于从 URL 下载文件并将其写入磁盘 并施加特定的文件扩展名 目前 它看起来像这样 import requests import os def getpml url filename psc requests get url
  • 函数内部变量的赋值会改变外部的赋值 - Python

    我从使用 Matlab 转向使用 Python 使用函数时的变量赋值让我感到困惑 我有一个代码如下 a 1 1 1 def keeps x y x y 1 2 return y def changes x y x y 1 2 return
  • SSRS 报告服务 - 字符串中的粗体字

    出版物 如何在字符串中加粗作者姓名 如果返回 1 个值 但它是一个字符串 情况会是这样的 iif Fields Author Value Parameters 5aAuthor Value Bold Normal 示例 作者 年份 标题 期
  • Doxygen:记录函数指针类型的参数 (ANSI-C)

    我的代码需要一些函数指针类型 例如 brief Callback function type foo typedef int foo int a int b 我想记录函数参数的语义 但是 param in out 旁边的 brief声明似乎

随机推荐

  • Power BI第三方图表

    KPI类 Bullet Chart 子弹图 用来展现目标完成率 可定义红 黄 绿区域 Bullet Chart by OKViz 以垂直或水平形式展现目标达成情况 同时可以显示多个指标 Card with States by OKViz 一
  • 钉钉开放平台查询宜搭表单实例数据

    本例结合钉钉开放平台相关api实现获取宜搭表单数据 可在faas中做实现 本例采用python编写 已在本地实现 对于免登获取数据 数据归档到本地能提供参考 faas具体实现请根据实际 参考使用 采用alibabacloud dingtal
  • 【16种重要流操作】

    文章目录 前言 一 16种重要流是什么 二 输入输出流模型化 1 输入流操作 2 输出流操作 三 16种输入输出流 代码通 总结 前言 输入输出流的使用已经非常的广泛 除过采用了不同的类操作 其方法大同小异 下文针对16种重要的流进行分解
  • openEuler-22.03-LTS 安装与配置笔记

    镜像下载与安装 openEuler下载页 镜像下载 下载镜像 wget c https repo openeuler org openEuler 22 03 LTS ISO x86 64 openEuler 22 03 LTS x86 64
  • Recall, Precision, AP, mAP的计算方法(看一次就懂系列)

    Recall Precision AP mAP的计算方法 看一次就懂系列 mAP全称是mean Average Precision 这里的Average Precision 是在不同recall下计算得到的 所以要知道什么是mAP 要先了解
  • Vue的动画和过渡效果详解

    产品中优雅的交互动画可以吸引更多用户留存使用 对于前端的动画实现要求也越来越高了 在Vue中提供了一些快捷 方便的标签和内置属性来更加优雅的实现动画和过渡效果 今天我们来一起学习一下 基础动画效果 公众号 Code程序人生 个人网站 htt
  • 视频生成: 基于Stable Diffusion的微调方法

    chatGPT带来了几个月的AIGC热度 文本图像生成模型大行其道 但AI在视频生成任务上尚没有较好的开源仓库 并受限于 缺那么几百块A100 的资源问题 大多数人无法展开视频生成的研究 好在目前有不少针对视频生成的相关paper 也有不少
  • python在with open()函数中,如何在文件名设置中引用变量

    用format 函数 name wz age 25 with open C Users 0 1 txt format name age w encoding utf 8 as f1 f1 write hellow world 则文件名为 w
  • C++ 模板函数、模板类:如果没有被使用就不会被实例化

    C 中如果一个模板函数没有使用过 那么其局部静态变量都不会被实例化 class A public A edward print A ctor template
  • 【2】浅析Vue组件

    组件的基本概念 Vue中有一个概念叫做组件化 就是把页面分成一个个小的部分 每个部分有自己的功能 且可以复用 最外层的组件即根组件 除此之外会有很多子组件 子组件分为两种 全局组件和局部组件 全局组件 用 Vue component 组件名
  • 基础学习——numpy与tensor张量的转换

    系列文章目录 Numpy学习 创建数组及常规操作 数组创建 切片 维度变换 索引 筛选 判断 广播 Tensor学习 创建张量及常规操作 创建 切片 索引 转换 维度变换 拼接 基础学习 numpy与tensor张量的转换 基础学习 关于l
  • 怎么用微信打开wifi连接到服务器,微信一键连wifi在哪里 微信一键连wifi怎么使用...

    类型 社交聊天大小 45 4M语言 中文 评分 5 0 标签 立即下载 微信这款软件使用可以不用流量了 这款软件推出了wifi一键连小程序 帮助用户走到哪里都有无线网 但是有很多伙伴不知道在哪里 怎么连接 想知道的伙伴可以在西西看看相关的教
  • fiddler设置网速模拟弱网络测试

    在测试过程中 经常会要求测试弱网络情况时的一些特殊情况 这时候IOS还好说 在开发者选项中调整网络模式即可 但android就只能通过别的方式了 这里整理了通过fiddler抓包工具来设置弱网模式 在fiddler可以设置自己想要的网速 或
  • CTF练题(3) jpg图片隐写 使用jphs05工具和stegslove

    题目一概述 解题过程 1 根据题目提示 判断为图片隐写 800度的眼镜 我理解为不同色通道下观看图片 由此打开stegslove分析该图片 2 点击右方向键调整不同的色通道 发现乱码隐约组成六个字 我好喜欢你 如图 可能这六个字为本题fla
  • java代码编译和运行在命令行中完成

    背景 集成开发环境用多了 最近想学一下 java 基础 用命令行来编译和运行一下 发现举步维艰 于是 创作这篇文章与大家共享 基础知识梳理 在写代码之前 我们先花点时间来了解一下 java 编译和运行的过程 如下图 里面涉及到 两个 命令符
  • CentOS安装PostgreSQL

    版本信息 CentOS版本 CentOS 7 x86 64 Minimal 1810 PostgreSQL版本 PostgreSQL 10 10 64 bit 第一部分 PostgresSQL的安装 1 安装rpm文件 yum instal
  • 华为云云耀云服务器L实例评测|轻松购买 快速使用 上云如此简单【详细版】

    华为云云耀云服务器L实例评测 轻松购买 快速使用 上云如此简单 详细版 轻量级云服务器 即开即用 轻松运维 开启简单上云第一步 文章目录 华为云云耀云服务器L实例评测 轻松购买 快速使用 上云如此简单 详细版 1 云耀云服务器介绍 2 购买
  • Stable Diffusion 硬核生存指南:WebUI 中的 GFPGAN

    本篇文章聊聊 Stable Diffusion WebUI 中的核心组件 强壮的人脸图像面部画面修复模型 GFPGAN 相关的事情 写在前面 本篇文章的主角是开源项目 TencentARC GFPGAN 和上一篇文章 Stable Diff
  • scrollview中使用recyclerview莫名自动上滑

    1 scrollview中加入 android descendantFocusability blocksDescendants 2 为scrollView中的根view加入android focusableInTouchMode true
  • USB详解

    转载自http blog 163 com zhsh email blog static 19786900200611259521640 usb作为一种串行接口 应用日益广泛 如同每个工程设计人员必须掌握I2C RS232这些接口一样 我们也