USB转多路串口 - USB CDC设备枚举

先上参考资料:
ST社区的: <<USB CDC类入门培训.pdf>>
STM32 USB如何配置多个CDC设备
状态与枚举过程
CDC串口之从认识到认知

USB CDC 类基础

CDC(Communication Device Class)类是 USB2.0 标准下的一个子类,定义了通信相关设备的抽象集合。它与USB2.0标准以
及其下的子类的相互关系如下图所示:

CDC-PSTN之间的关系

USB2.0标准下定义了很多子类,有音频类,CDC类,HID类等,通信类CDC下面,又有一些子类,这里我们主要使用PSTN(Public Switched Telephone Network)。从 PSTN官方标准文档来看,PSTN子类是一个与电信相关的子类,而这里,我们只是将它作为一个普通的通信设备使用,并没有使用到它的一些电话特性。PSTN定义了三种模型:DLM(Direct Line Mode),ACM(Abstract Control Model)和 TCM(Telephone Control Model). 一般选择ACM模型,个人估计是该模型控制接口传输的高层指令支持比如设置、获取波特率,设置获取与通信相关的参数,与串口控制,数据传输比较接近。
USB转串口,根据设备类型主要分为USB VCP串口、USB转CDC串口、HID转串口。USB HID从Win2000版本起内置驱动,是真正意义上的免驱,CDC串口驱动从Win10系统版本才开始内置,因CDC协议的用途定位,串口功能较其他方式并不完整。VCP串口驱动只需安装一次也可以联网自动安装,且有部分操作系统会内置厂商VCP驱动。根据实际使用情况,做了下对比汇总:

CDC_HID_VCP类对比

基于CDC-ACM协议开发纯USB传输应用还是十分方便的,工程师只需要关注USB设备本身的开发工作,驱动软件甚至是应用软件均不用开发。
VCP串口主要是指使用厂商专用USB转串口驱动和通信协议实现的串口,该方式也最接近16C450/16C550等原生串口。HID转串口USB传输速度没有CDC和VCP快,不适合较高波特率通讯,且不兼容串口应用软件。

USB设备、接口、端点描述符

USB 协议已规定好支持的设备,主机系统中也准备好了许多对应设备的驱动程序。USB 设备第一次连接到主机时, 主机要知道是哪一类的USB设备才能指派对应的驱动。要知道占用多少资源、使用了哪些传输方式以及传输的数据量等,才能真正开始工作。这些信息是通过存储在设备中的USB描述符来体现的。
一个USB设备只有一个设备描述符,设备描述符里面定义了该设备有多少种配置,每种配置有对应的配置描述符;而在配置描述符中又定义了该配置里面有多少个接口,每个接口有对应的接口描述符;在接口描述符里面又定义了该接口有多少个端点,每个端点对应一个端点描述符;端点描述符定义了端点的大小,类型等等。由此我们可以看出,USB的描述符之间的关系是一层一层的,最上一层是设备描述符,下面是配置描述符,再下面是接口描述符,再下面是端点描述符。在获取描述符时,先获取设备描述符,然后再获取配置描述符,根据配置描述符中的配置集合长度,一次将配置描述符、接口描述符、端点描述符一起一次读回。其中可能还会有获取设备序列号,厂商字符串,产品字符串等。详细关系如下图所示:

描述符层级关系

这些描述符是以字节流的形式传输的,所以软件代码里一般是用数组或者结构体封装。根据协议,主机有询问设备描述和配置描述符的SETUP指令,接口和端点的描述符都包含在配置描述符里。标准的设备描述符如下:

OffsetFieldSizeValueDescription
0bLength1Number以字节为单位的描述符大小
1bDescriptorType1Constant设备描述符类型
2bcdUSB2BCDUSB规范版本号
4bDeviceClass1Class类码
5bDeviceSubClass1SubClass子类码
6bDeviceProtocol1Protocol协议码
7bMaxPacketSize01Number端点0的最大包大小
8idVendor2ID厂商ID
10idProduct2ID产品ID
12bcdDevice2BCD设备版本号
14iManufacturer1Index制造商字符串描述符索引
15iProduct1Index产品的字符串描述符索引
16iSerialNumber1Index设备序列号的字符串描述符索引
17bNumConfigurations1Number可能的配置数目

第1个是描述符长度,以字节为单位,第2个字节是类型,描述符基本是这样的开头,后面是该类型下描述符信息。配置描述符以及所包含的接口描述符,端点描述符定义如下:

配置描述符:

OffsetFieldSizeValueDescription
0bLength10x09本描述符长度
1bDescriptorType10x02CONFIGURATION 类型
2wTotalLength20x003b配置总长度,包括后面的接口和端点配置,2字节
4bNumInterfaces10x02接口个数
5bConfigurationValue10x01Set_Configuration命令所需要的参数值
6iConfiguration10x03描述该配置的字符串的索引值
7bmAttributes10xa0主机供电(0x80), 自己供电(0xC0)
8bMaxPower10x2d主机供电最大电流;0x32(100mA), 0xFA(500mA)

接口描述符:

OffsetFieldSizeValueDescription
0bLength10x09本描述符长度
1bDescriptorType10x04INTERFACE 类型
2bInterfaceNumber10x00当前接口index(编号)
3bAlternateSetting10x00
4bNumEndpoints10x01该接口的端点个数
5bInterfaceClass10x03接口通信类别,0x03代表HID设备
6bInterfaceSubClass10x01子类别
7bInterfaceProtocol10x01这里定义为键盘(Keyboard)
8iInterface10x02本描述符长度

端点描述符:

OffsetFieldSizeValueDescription
0bLength10x07本描述符长度
1bDescriptorType10x05ENDPOINT 类型
2bEndpointAddress10x81端点地址,最高bit=1代表IN方向的端点
3bmAttributes10x03中断传输(0x03), 批量传输(0x02)
4wMaxPacketSize20x0008传输的数据报文最大长度
6bInterval10x0A

CDC类设备
CDC类设备与其他标准USB设备枚举过程的并没有什么特殊的地方。在设备描述符内可以使用DeviceClass=0x00,
SubClass=0x00, Protocol=0x00 表示此类信息在接口描述符内给出;或者也可以使用0x02,0x00,0x00;来表明该设备为
CDC类设备。或者使用0xef, 0x02,0x01表示当前为复合设备。 USB CDC类配置描述符的结构:

CDC类描述符结构

如上图所示,CDC类的配置描述符(1个串口)一般包含两个接口(Interface 0),一个控制接口,另外一个是数据接口(Interface 1), 除此之外,还有一个虚线指向的IAD(Interface Association Description),这个表示这个是不是可选的,得根据实际情况来确定其是否真实存在。

USB设备状态与枚举过程

USB协议规定USB可见设备状态分为连接(Attached), 上电(Powered),默认(Default),地址(Address),配置(Configured)和挂起(Suspended)6个状态。所谓可见,即USB系统和主机可见的状态,其它状态属于USB设备内部状态。

  • 接入态(Attached):设备接入主机后,主机通过检测信号线上的电平变化来发现设备的接入;
  • 供电态(Powered):就是给设备供电,分为设备接入时的默认供电值,配置阶段后的供电值(按数据中要求的最大值,可通过编程设置)
  • 缺省态(Default):USB在被配置之前,通过缺省地址0与主机进行通信;
  • 地址态(Address):经过了配置,USB设备被复位后,就可以按主机分配给它的唯一地址来与主机通信,这种状态就是地址态;
  • 配置态(Configured):通过各种标准的USB请求命令来获取设备的各种信息,并对设备的某此信息进行改变或设置。
  • 挂起态(Suspended):USB总线处于空闲状态的话,该设备就要自动进入挂起状态,在进入挂起状态后,总的电流功耗不超过280UA。
    USB主机在检测到USB设备插入后,就要对设备进行枚举了。Host根据Device所报告上来的参数,获得一些信息,知道设备是什么样的设备,如何进行通信,这样主机就可以根据这些信息来加载合适的驱动程序。

     

    枚举过程

     

    如上图,USB CDC类的通信部分主要包含三部分:枚举过程、虚拟串口操作和数据通信。其中虚拟串口操作部分并不一定强制需要,因为若跳过这些虚拟串口的操作,实际上USB依然是可以通信的,这也就是为什么上图中,在操作虚拟串口之前会有两条数据通信的数据。之所以会有虚拟串口操作,主要是我们通常使用PC作为Host端,在PC端使用一个串口工具来与其进行通信,PC端的对应驱动将其虚拟成一个普通串口,这样一来,可以方便PC端软件通过操作串口的方式来与其进行通信,但实际上,Host端与Device端物理上是通过USB总线来进行通信的,与串口没有关系,这一虚拟化过程,起决定性作用的是对应驱动,包含如何将每一条具体的虚拟串口操作对应到实际上的USB操作。这里需要注意地是,Host端与Device端的USB通信速率并不受所谓的串口波特率影响,它就是标准的USB2.0全速(12Mbps)速度,实际速率取决于总线的实际使用率、驱动访问USB外设有效速率(两边)以及外部环境对通信本身造成的干扰率等等因素组成。

USB2.0协议CDC类设备枚举过程详解

检测电压变化,报告主机
首先,USB设备上电后,一直监测USB设备接口电平变化HUB检测到有电压变化,将利用自己的中断端点将信息反馈给主控制器有设备连接。

Host了解连接的设备
每个hub利用它自己的中断端点向主机报告它的各个端口的状态(对于这个过程,设备是看不到的,也不必关心),报告的内容只是hub端口的设备连接/断开的事件。如果有连接/断开事件发生,那么host会发送一个 Get_Port_Status请求(request)给hub以了解此次状态改变的确切含义。Get_Port_Status等请求属于所有hub都要求支持的hub类标准请求(standard hub-class requests)。

Hub检测所插入的设备是高速还是低速设备
hub通过检测USB总线空闲(Idle)时差分线的高低电压来判断所连接设备的速度类型,当host发来Get_Port_Status请求时,hub就可以将此设备的速度类型信息回复给host。USB 2.0规范要求速度检测要先于复位(Reset)操作。

hub复位设备
主机一旦得知新设备已连上以后,它至少等待100ms以使得插入操作的完成以及设备电源稳定工作。然后主机控制器就向hub发出一个 Set_Port_Feature请求让hub复位其管理的端口(刚才设备插上的端口)。hub通过驱动数据线到复位状态(D+和D-全为低电平 ),并持续至少10ms。当然,hub不会把这样的复位信号发送给其他已有设备连接的端口,所以其他连在该hub上的设备自然看不到复位信号,不受影响。

Host检测所连接的全速设备是否是支持高速模式
因为根据USB 2.0协议,高速(High Speed)设备在初始时是默认全速(Full Speed )状态运行,所以对于一个支持USB 2.0的高速hub,当它发现它的端口连接的是一个全速设备时,会进行高速检测,看看目前这个设备是否还支持高速传输,如果是,那就切到高速信号模式,否则就一直在全速状态下工作。
同样的,从设备的角度来看,如果是一个高速设备,在刚连接bub或上电时只能用全速信号模式运行(根据USB 2.0协议,高速设备必须向下兼容USB 1.1的全速模式)。随后hub会进行高速检测,之后这个设备才会切换到高速模式下工作。假如所连接的hub不支持USB 2.0,即不是高速hub,不能进行高速检测,设备将一直以全速工作。

Hub建立设备和主机之间的信息通道
主机不停地向hub发送Get_Port_Status请求,以查询设备是否复位成功。Hub返回的报告信息中有专门的一位用来标志设备的复位状态。
当hub撤销了复位信号,设备就处于默认/空闲状态(Default state),准备接收主机发来的请求。设备和主机之间的通信通过控制传输,默认地址0,端点号0进行。此时,设备能从总线上得到的最大电流是100mA。(所有的USB设备在总线复位后其地址都为0,这样主机就可以跟那些刚刚插入的设备通过地址0通信。)

主机发送Get_Descriptor请求获取默认管道的最大包长度
默认管道(Default Pipe)在设备一端来看就是端点0。主机此时发送的请求是默认地址0,端点0,虽然所有未分配地址的设备都是通过地址0来获取主机发来的请求,但由于枚举过程不是多个设备并行处理,而是一次枚举一个设备的方式进行,所以不会发生多个设备同时响应主机发来的请求。
设备描述符的第8字节代表设备端点0的最大包大小。虽然说设备所返回的设备描述符(Device Descriptor)长度只有18字节,但系统也不在乎,此时,描述符的长度信息对它来说是最重要的,其他的瞄一眼就过了。当完成第一次的控制传输后,也就是完成控制传输的状态阶段,系统会要求hub对设备进行再一次的复位操作(USB规范里面可没这要求)。再次复位的目的是使设备进入一个确定的状态。

主机给设备分配一个地址
主机控制器通过Set_Address请求向设备分配一个唯一的地址。在完成这次传输之后,设备进入地址状态(Address state),之后就启用新地址继续与主机通信。设备在,地址在;设备消失(被拔出,复位,系统重启),地址被收回。同一个设备当再次被枚举后得到的地址不一定是上次那个了。

主机获取设备的信息
主机发送 Get_Descriptor请求到新地址读取设备描述符,这次主机发送Get_Descriptor请求可算是诚心,它会认真解析设备描述符的内容。设备描述符内信息包括端点0的最大包长度,设备所支持的配置(Configuration)个数,设备类型,VID(Vendor ID,由USB-IF分配), PID(Product ID,由厂商自己定制)等信息。

接着说到描述符。总的来讲描述符就是USB设备之间通信的规范。当一个新的USB设备接入时,他的默认地址为0,此时主设备通过描述符识别从设备,并与其通信,来获得更多关于从设备的信息。并为从设备在1到127找到一个没有分配的地址。并将该地址赋给这个从设备,这样,这个从设备就可以使用新获得的地址和主设备通信了。

GET_INTERFACE(取获取接口)
这个请求向指定接口返回选中的备用设备。

一些USB设备有接口设置互斥的配置。这个请求允许主机确定当前选定的备用设置。如果wValue或者wLength的值与上面指定的不一致,那么设备的行为没有定义;如果指定的接口不存在,那么设备将用请求错误响应。

USB CDC 描述符实例

设备描述符:

const uint8_t  MyDevDescr[] =
{0x12,       // bLength0x01,       // bDescriptorType (Device)0x00, 0x02, // bcdUSB 2.0  //    0x10, 0x01, bcdUSB 1.100x00,       // bDeviceClass 以为是: 0xEF 0x02 0x01 实际是:0x00 0x00 0x000x00,       // bDeviceSubClass 0x00,       // bDeviceProtocol DEF_USBD_UEP0_SIZE,   // bMaxPacketSize, 64(uint8_t)DEF_USB_VID, (uint8_t)(DEF_USB_VID >> 8), (uint8_t)DEF_USB_PID, (uint8_t)(DEF_USB_PID >> 8),0x00, 0x02, //0x00, DEF_IC_PRG_VER, // bcdDevice 2.00x01,       // iManufacturer (String Index)0x02,       // iProduct (String Index)0x03,       // iSerialNumber (String Index)0x01,       // bNumConfigurations 1
};

设备描述符定义了USB 2.0设备;指明类别在接口描述符中给出;端点0的最大报文长度;USB 设备的PID, VID;
本项目是模拟了7个串口,配置描述符比较大,还是用数组直接写会非常长。在github上参考了别人的代码,用宏定义了串口描述,数组定义就简洁了许多。宏定义如下:

/*** @brief macro to help generate CDC ACM USB descriptors* @param desc CdcDeviceDesc 对象* */
#define CDC_DESCRIPTOR(desc) \/*Interface Association Descriptor */ \0x08,                                            /* bLength: Interface Association Descriptor size */ \0x0B,                                            /* bDescriptorType: Interface Association */ \desc.CmdInterface,                               /* bFirstInterface: First Interface of Association, 第一个接口的序号 */ \0x02,                                            /* bInterfaceCount: quantity of interfaces in association, 本IDA的接口数量 */ \0x02,                                            /* bFunctionClass: Communication Interface Class, CDC设备 */ \0x02,                                            /* bFunctionSubClass: Abstract Control Model */ \0x01,                                            /* bFunctionProtocol: Common AT commands */ \0x00,                                            /* iInterface */ \\/*Interface Descriptor */ \0x09,                                            /* bLength: Interface Descriptor size */ \0x04,                                            /* bDescriptorType: Interface */ \desc.CmdInterface,                               /* bInterfaceNumber: Number of Interface, 接口编号 */ \0x00,                                            /* bAlternateSetting: Alternate setting */ \0x01,                                            /* bNumEndpoints: One endpoints used */ \0x02,                                            /* bInterfaceClass: Communication Interface Class */ \0x02,                                            /* bInterfaceSubClass: Abstract Control Model */ \0x01,                                            /* bInterfaceProtocol: Common AT commands */ \0x00,                                            /* iInterface */ \\/*Header Functional Descriptor*/ \0x05,                                            /* bLength: Endpoint Descriptor size */ \0x24,                                            /* bDescriptorType: CS_INTERFACE */ \0x00,                                            /* bDescriptorSubtype: Header Func Desc */ \0x10,                                            /* bcdCDC: spec release number */ \0x01, \\/*Call Management Functional Descriptor*/ \0x05,                                            /* bFunctionLength */ \0x24,                                            /* bDescriptorType: CS_INTERFACE */ \0x01,                                            /* bDescriptorSubtype: Call Management Func Desc */ \0x00,                                            /* bmCapabilities: D0+D1 */ \desc.DataInterface,                              /* bDataInterface */ \\/*ACM Functional Descriptor*/ \0x04,                                            /* bFunctionLength */ \0x24,                                            /* bDescriptorType: CS_INTERFACE */ \0x02,                                            /* bDescriptorSubtype: Abstract Control Management desc */ \0x02,                                            /* bmCapabilities */ \\/*Union Functional Descriptor*/ \0x05,                                            /* bFunctionLength */ \0x24,                                            /* bDescriptorType: CS_INTERFACE */ \0x06,                                            /* bDescriptorSubtype: Union func desc */ \desc.CmdInterface,                               /* bMasterInterface: Communication class interface */ \desc.DataInterface,                              /* bSlaveInterface0: Data Class Interface */ \\/* Command Endpoint Descriptor, 控制端点描述符(IN) */ \0x07,                                            /* bLength: Endpoint Descriptor size */ \0x05,                                            /* bDescriptorType: Endpoint */ \desc.CmdEndPoint,                                /* bEndpointAddress */ \0x03,                                            /* bmAttributes: Interrupt */ \0x40,                                            /* wMaxPacketSize: 报文最大字节数(低位)*/ \0x00, \0x10,                                            /* bInterval: */  \\/* Data class interface descriptor */ \0x09,                                            /* bLength: Endpoint Descriptor size */ \0x04,                                            /* bDescriptorType: */ \desc.DataInterface,                              /* bInterfaceNumber: Number of Interface */ \0x00,                                            /* bAlternateSetting: Alternate setting */ \0x02,                                            /* bNumEndpoints: Two endpoints used */ \0x0A,                                            /* bInterfaceClass: CDC */ \0x00,                                            /* bInterfaceSubClass: */ \0x00,                                            /* bInterfaceProtocol: */ \0x00,                                            /* iInterface: */ \\/* Data Endpoint OUT Descriptor, 数据端点描述符(OUT) */ \0x07,                                            /* bLength: Endpoint Descriptor size */ \0x05,                                            /* bDescriptorType: Endpoint */ \desc.DataOutEndPoint,                            /* bEndpointAddress */ \0x02,                                            /* bmAttributes: Bulk */ \0x40,                                            /* wMaxPacketSize: */ \0x00, \0x00,                                            /* bInterval: ignore for Bulk transfer */ \\/* Data Endpoint IN Descriptor, 数据端点描述符(IN) */ \0x07,                                            /* bLength: Endpoint Descriptor size */ \0x05,                                            /* bDescriptorType: Endpoint */ \desc.DataInEndPoint,                             /* bEndpointAddress */ \0x02,                                            /* bmAttributes: Bulk */ \0x40,                                            /* wMaxPacketSize: */ \0x00, \0x00                                             /* bInterval: ignore for Bulk transfer */// 每个控制接口号都是数据接口号 + 固定偏移
#define CMD_EP_OFFSET   (7)  // 从8改为7就没报 USBFS_UIS_TOKEN_IN 的 TOG error了,奇怪/*** @brief 定义CDC 设备描述符关键接口属性* */
struct CdcDeviceDesc
{uint8_t CmdInterface;    // 控制(命令)接口号uint8_t DataInterface;   // 数据接口号uint8_t CmdEndPoint;     // 控制端点uint8_t DataOutEndPoint; // 数据端点(OUT 方向)uint8_t DataInEndPoint;  // 数据端点(IN 方向)
};const static struct CdcDeviceDesc CDC_DEV_DESCs[USB_CDC_NUM] = 
{{0,  1,  0x81+CMD_EP_OFFSET, 0x01, 0x81}, // 通道0, 接口使用0和1, 端点:1{2,  3,  0x82+CMD_EP_OFFSET, 0x02, 0x82},{4,  5,  0x83+CMD_EP_OFFSET, 0x03, 0x83},{6,  7,  0x84+CMD_EP_OFFSET, 0x04, 0x84},{8,  9,  0x85+CMD_EP_OFFSET, 0x05, 0x85},{10, 11, 0x86+CMD_EP_OFFSET, 0x06, 0x86},{12, 13, 0x87+CMD_EP_OFFSET, 0x07, 0x87}
};/* Configure descriptor 配置描述 */
const uint8_t MyCfgDescr[] =
{0x09, // 长度,包括自已,下同0x02, // configuration0xD7, // 配置描述数组(MyCfgDescr)大小, 66 * 7 + 9 = 471 = 0x01D70x01,(uint8_t)(USB_CDC_NUM*2), // 接口大小,每个CDC有2个interface0x01, // configuration value0x00, // index of string descriptor describing the configuration0x80, // bmAttributes: 主机供电(0x80)。如果是自己供电这里配置为:0xC00xFA, // max power: 0x32->100mA, 0xFA->500mACDC_DESCRIPTOR(CDC_DEV_DESCs[0]), CDC_DESCRIPTOR(CDC_DEV_DESCs[1]), CDC_DESCRIPTOR(CDC_DEV_DESCs[2]), CDC_DESCRIPTOR(CDC_DEV_DESCs[3]), CDC_DESCRIPTOR(CDC_DEV_DESCs[4]), CDC_DESCRIPTOR(CDC_DEV_DESCs[5]), CDC_DESCRIPTOR(CDC_DEV_DESCs[6]),
};

看代码的注释即可,不再说明了。

(end)

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

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

相关文章

在Ubuntu上安装移远EC200M驱动

最近公司在做降本相关工作&#xff0c;考虑移远 EC20 4G模组成本较高&#xff0c;希望通过更低成本替换硬件&#xff0c;最后找到EC200M芯片&#xff0c;虽然EC200M速率(最大下行10M/s 最大上行5M/s)上低于EC20&#xff08;最大下行150M/s 最大上行50M/s&#xff09;,基本上可以…

tongue通lingual:灵根,舌也!

灵&#xff0c;指心灵、精神意识&#xff1b;灵根&#xff1a;汉语“灵根”&#xff0c;通常指人的舌头主。舌头是人心灵的表达根器&#xff0c;因此&#xff0c;灵根——指心灵外化的肉身凭据、可以像树根&#xff08;或一切植物根部&#xff09;一样延伸、像树根一样重要身体…

磁感应传感器 - 从零开始认识各种传感器【第十二期】

1、什么是磁感应传感器 磁感应传感器又叫做磁力计&#xff0c;是可以测量磁场大小或方向的设备。因为地球本质上是一个巨大的磁铁。磁力计可让您测量空间中某一点的磁场强度以及磁场方向。 图1 磁力计 磁力计已广泛应用于各种应用。它们用于测量地球磁场、地理测量、探测潜艇…

Python内存管理:引用计数与垃圾回收

✨ 内容&#xff1a; 在Python中&#xff0c;内存管理是一个重要且常常被忽视的话题。了解Python如何管理内存&#xff0c;不仅能帮助我们编写高效的代码&#xff0c;还能避免潜在的内存泄漏问题。今天&#xff0c;我们将通过一个实际案例&#xff0c;深入探讨Python的内存管理…

RabbitMQ:如何保证消息的可靠性?

RabbitMQ基础 RabbitMQ支持的消息模型 SpringBoot集成RabbitMQ 一、发送者的可靠性 消息从发送者发送消息&#xff0c;到消费者处理消息&#xff0c;需要经过的流程是这样的&#xff1a; 消息从生产者到消费者的每一步都有可能导致消息丢失&#xff1a; 发送消息时丢失&am…

Spring Boot 学习(10)——固基(Idea 配置 git 访问 gitee)

几转眼就过了两个月&#xff0c;其实也没有闲着&#xff0c;学也学了&#xff0c;只是繁杂事多&#xff0c;学的不如以前多&#xff0c;也没有做过笔记了。 以前做开发因条件受限&#xff0c;没有什么 git &#xff0c;也没有 gitee。现在出来混要跟上形势才行&#xff0c;学习…

掌握VR全景技术,需要具备哪些条件?

VR全景技术自从进入市场以来&#xff0c;就在各个行业领域尝试落地运用&#xff0c;包括但不限于广告宣传、学校教育、医疗、工业、农业等领域。随着5G 技术的不断普及&#xff0c;VR全景技术也逐渐被应用到日常生活中的各个方面&#xff0c;从地产中介到车企销售&#xff0c;从…

【数据结构】探索排序的奥秘

若有不懂地方&#xff0c;可查阅我之前文章哦&#xff01; 个人主页&#xff1a;小八哥向前冲~_csdn博客 所属专栏&#xff1a;数据结构_专栏 目录 排序的概念 几种排序方法介绍 冒泡排序 选择排序 插入排序 堆排序 向上调整建堆排序 向下调整建堆排序 希尔排序 快速…

快乐数-快慢指针法

题目描述&#xff1a; 个人题解&#xff1a; 通过反复调用 getNext(n) 得到的链是一个隐式的链表。隐式意味着我们没有实际的链表节点和指针&#xff0c;但数据仍然形成链表结构。起始数字是链表的头 “节点”&#xff0c;链中的所有其他数字都是节点。next 指针是通过调用 ge…

使用两种不同的方法估计几何布朗运动随机过程的参数

使用两种不同的方法估计几何布朗运动随机过程的参数 文章目录 一、说明二. 随机过程三、马尔可夫过程3.1. 维纳进程3.2. 广义维纳过程3.3. 伊藤进程 四、几何布朗运动 &#xff08;GBM&#xff09;五、用于估计GBM工艺参数的MLE方法5.1. 最大似然估计如何工作&#xff1f;5.2、…

2024全国青少年信息素养大赛图形化编程复赛真题大全

2024年全国青少年信息素养大赛图形化编程复赛全国结束了&#xff0c;经过了3次各个赛区&#xff08;7月6日、13日、20日&#xff09;图形化编程小低组、小高组整体来看&#xff0c;真题出的都比较有水平&#xff0c;2024年全国青少年信息素养大赛总决赛将在2024年8月16日~20日在…

MySQL面试篇章——MySQL索引

文章目录 MySQL 索引索引分类索引创建和删除索引的执行过程explain 查看执行计划explain 结果字段分析 索引的底层实现原理B-树B树哈希索引 聚集和非聚集索引MyISAM&#xff08;\*.MYD&#xff0c;*.MYI&#xff09;主键索引辅助索引&#xff08;二级索引&#xff09; InnoDB&a…

PRC gRPC 框架

概述 RPC主要目的在于让开发者&#xff0c;能够方便的调用远程服务器上的服务&#xff0c;而不需要关注底层的网络通信细节。其是一种进程间通信技术&#xff0c;允许程序在不同计算机上执行代码。 RPC技术主要用于分布式系统、微服务架构以及需要进行跨网络调用服务的应用中…

项目实战二 HIS项目

目标&#xff1a; 项目的操作流程&#xff1a; 开发体系 前端开发&#xff1a;负责页面的编写 HTML CSS JavaScript 后端开发&#xff1a;看不到 摸不着的功能 常用开发语言 PHP JAVA Python 框架 &#xff1a; 半成品 做好的功能模块 版本控制 Git 分布式版本控…

鼠标连点器:是什么?如何用?鼠标自动点击器好用吗?说明书详细版(国内外6款电脑鼠标连点器分享)值得收藏!

知识科普1&#xff1a;鼠标连点器是什么&#xff1f; ⭕答&#xff1a;鼠标连点器&#xff0c;又称为鼠标点击器或自动点击器&#xff0c;是一种能够模拟鼠标点击操作的计算机软件。 鼠标连点器可以根据用户设定的参数&#xff0c;自动进行连续的鼠标点击操作&#xff0c;从而…

SQL labs-SQL注入(三)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 引言&#xff1a; 盲注简述&#xff1a;是在没有回显得情况下采用的注入方式&#xff0c;分为布尔盲注和时间盲注。 布尔盲注&#xff1a;布尔仅有两种形式&#xff0c;ture&#…

【LLM】-05-提示工程-部署Langchain-Chat

目录 1、软硬件要求 1.1、软件要求 1.2、硬件要求 1.3、个人配置参考 2、创建cuda环境 3、下载源码及模型 4、配置文件修改 5、初始化知识库 5.1、训练自己的知识库 6、启动 7、API接口调用 7.1、使用openai 参考官方wiki&#xff0c;本文以Ubuntu20.04_x64&#xf…

微信小程序数组绑定使用案例(二)

一、数组事件绑定&#xff0c;事件传递数据 1.wxml <text>姓名&#xff1a;{{name}} </text> <block wx:for"{{list}}"><button bind:tap"nameClick2" data-name"{{item}}">修改:{{item}}</button> </block&…

想学习Python爬虫的宝子们可以看过来,从基础开始看这一篇文章就够了!

1. 预备知识 学习者需要预先掌握Python的数字类型、字符串类型、分支、循环、函数、列表类型、字典类型、文件和第三方库使用等概念和编程方法。 2. Python爬虫基本流程 a. 发送请求 使用http库向目标站点发起请求&#xff0c;即发送一个Request&#xff0c;Request包含&am…

单调栈(随缘复习到了,顺手刷了)

也是不知道为什么突然又复习到单调栈了&#xff0c;所以顺手刷了三道题&#xff0c;总结一下 P6503 [COCI2010-2011#3] DIFERENCIJA 思路&#xff1a;这题是要求每个子区间里面的最大值和最小值的差&#xff0c;我们一开始想的必然是纯暴力呀&#xff0c;但是一看这数据&#…