STM32 USBH CDC开发及应用

2023-11-09

USB,是英文 Universal Serial BUS (通用串行总线)的缩写,其是一个外部总线标准,用于规范USB主机与外部设备的连接和通讯。由于项目需要,需要开发基于STM32 USB主机(HOST)的CDC的开发,用于编队表演系统中底座跟无人机间的数据交互,同时通过usb接口给无人机充电。
在做usb主机开发之前,我们需要先了解一个概念,USB 设备是被动触发,USB主机掌握主动权,发送什么数据,什么时候发送,是给设备发送数据还是从设备请求数据,都是由USB主机完成的,USB设备只是配合主机完成设备的枚举、数据方向和大小。根据数据特性再决定该不该回复该如何回复、该不该接收该如何接收这些动作。
开发过程:
1.从ST官方提供的USB库将USB主机(HOST)库及CDC类代码加入到自己的工程中。
2.根据USB硬件修改usbh_conf中的初始化代码。
3.根据自己应用编写应用代码,由于开发是基于rtthread系统开发的,可以将usb当做一个serial设备,利用rtthread系统设备操作,实现应用与底层软件分离。
思路:
a:实现serial设备的操作方法,利用ringbuffer功能,将usb设备发送数据先写入到ringbuffer中,然后usb处理线程从ringbuffer中获取数据发送数据,实现与应用分离。usb数据接收到的数据写入serial封装的ringbuffer中。
usb数据发送操作封装:

static 	uint32_t usbh_vcp_send(uint8_t * Buf, uint32_t Len)
	{
		uint32_t len = 0;
		if(usbh_vcp_ringbuffer.buffer_ptr != RT_NULL)
		{
			len = rt_ringbuffer_put_force(&usbh_vcp_ringbuffer, Buf, Len);
		}
		return len;
	}
	
	uint32_t copy_data_to_usbh(uint8_t *usbh_buf, uint32_t size)
	{
		uint32_t len = 0;
		if(usbh_vcp_ringbuffer.buffer_ptr != RT_NULL)
		{
			len = rt_ringbuffer_get(&usbh_vcp_ringbuffer, usbh_buf, size);
		}
		return len;
	}
static int usbh_vcp_putc(struct rt_serial_device * serial, char c)
	{
		return usbh_vcp_send((uint8_t *) &c, 1);
	}
usb数据接收操作封装:
在这里插入代码片
uint32_t usbh_vcp_recv(uint8_t * Buf, uint32_t Len)
	{
		uint32_t size = 0;
		if(usbh_vcom_serial.serial_rx != RT_NULL)
		{
			size = rt_ringbuffer_put_force(& ((struct rt_serial_rx_virtual *) (usbh_vcom_serial.serial_rx))->ringbuffer, Buf,Len);
			rt_hw_serial_isr(&usbh_vcom_serial, RT_SERIAL_EVENT_RX_VIRTUALDONE);
		}
		return size;
	}
static rt_err_t usbh_vcp_configure(struct rt_serial_device * serial, struct serial_configure * cfg)
	{
		return RT_EOK;
	}

static rt_err_t usbh_vcp_control(struct rt_serial_device * serial, int cmd, void * arg)
	{
		return RT_EOK;
	}	static int usbh_vcp_getc(struct rt_serial_device * serial)
	{
		int result = -1;
		rt_uint8_t ch;
		if(serial->serial_rx != RT_NULL)
		{
			if(rt_ringbuffer_getchar(& ((struct rt_serial_rx_virtual *) (serial->serial_rx))->ringbuffer, &ch) != 0)
			{
				result  = ch;
			}
		}
		return result;
	}

rt_inline rt_size_t usbh_vcp_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction)
	{
		rt_size_t ret = 0;
		RT_ASSERT(serial != RT_NULL);
		if(direction == RT_SERIAL_VIRTUAL_TX)
		{
			return usbh_vcp_send(buf, size);
		}
		else if(direction == RT_SERIAL_VIRTUAL_RX)
		{
			if(serial->serial_rx != RT_NULL)
			{
				ret = rt_ringbuffer_get(&((struct rt_serial_rx_virtual *) (serial->serial_rx))->ringbuffer, (rt_uint8_t *) buf, size);
			}
		}
		return ret;
	}
static const struct rt_uart_ops usbh_vcp_ops =
{
	usbh_vcp_configure, 
	usbh_vcp_control, 
	usbh_vcp_putc, 
	usbh_vcp_getc, 
	usbh_vcp_transmit, 
};
b:为usb发送申请ringbuffer,注册usb serial设备
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT2;
if(usbh_vcp_send_buffer == RT_NULL)
{
	usbh_vcp_send_buffer = (uint8_t *)rt_malloc(TX_RINGBUFFER_SIZE);
	if(usbh_vcp_send_buffer != RT_NULL)
	{
		rt_ringbuffer_init(&usbh_vcp_ringbuffer, usbh_vcp_send_buffer, TX_RINGBUFFER_SIZE);
		}
	else
	{
		rt_kprintf("[usbh] malloc vcp tx_buffer failed\r\n");
	}
}
	
	/* init usbh_cdc_serial */
    usbh_vcom_serial.ops = &usbh_vcp_ops;
    usbh_vcom_serial.config = config;
	/* register virtual serial device */
    if(rt_hw_serial_register(&usbh_vcom_serial, "usbh_vcp", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_VIRTUAL_RX | RT_DEVICE_FLAG_VIRTUAL_TX, 0) == RT_EOK)
    {
        rt_kprintf("[usbh] usbh_vcom port registered.\n");
    }
c:初始化usbh,添加接口类,启动usb
	/* Init Host Library */
	USBH_Init(&usbh_cdc, USBH_UserProcess, 0);
	/* Add Supported Class */
	USBH_RegisterClass(&usbh_cdc, USBH_CDC_CLASS);
	/* Start Host Process */
	USBH_Start(&usbh_cdc);
d:修改cdc类发送接收
	extern uint32_t copy_data_to_usbh(uint8_t *usbh_buf, uint32_t size);
	static void CDC_ProcessTransmission(USBH_HandleTypeDef *phost)
	{
	  CDC_HandleTypeDef *CDC_Handle = (CDC_HandleTypeDef*) phost->pActiveClass->pData;
	  USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
	  static uint32_t send_len = 0;
	  switch (CDC_Handle->data_tx_state)
	  {
	  case CDC_SEND_DATA:
		  //从缓冲区拿数据(最大为端点数据输出大小),如果有数据则发送数据
		if((URB_Status == USBH_URB_IDLE) || (URB_Status == USBH_URB_DONE))
		{
			send_len = copy_data_to_usbh(CDC_Handle->pTxData, CDC_Handle->DataItf.OutEpSize);
		}
		if(send_len > 0)
		{
			USBH_BulkSendData(phost,CDC_Handle->pTxData, send_len, CDC_Handle->DataItf.OutPipe, 1U);
			CDC_Handle->data_tx_state = CDC_SEND_DATA_WAIT;
		}
		break;

	  case CDC_SEND_DATA_WAIT:

		URB_Status = USBH_LL_GetURBState(phost, CDC_Handle->DataItf.OutPipe);

		/* Check the status done for transmission */
		if (URB_Status == USBH_URB_DONE)
		{
			CDC_Handle->data_tx_state = CDC_SEND_DATA;
		}
		else
		{
		  if (URB_Status == USBH_URB_NOTREADY)
		  {
			 CDC_Handle->data_tx_state = CDC_SEND_DATA;
		  }
		}
		break;
	  default:
		break;
	  }
	}
	
	extern uint32_t usbh_vcp_send(uint8_t * Buf, uint32_t Len);
	extern uint32_t usbh_vcp_recv(uint8_t * Buf, uint32_t Len);
	static void CDC_ProcessReception(USBH_HandleTypeDef *phost)
	{
	  CDC_HandleTypeDef *CDC_Handle =  (CDC_HandleTypeDef*) phost->pActiveClass->pData;
	  USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
	  uint32_t length;

	  switch(CDC_Handle->data_rx_state)
	  {

	  case CDC_RECEIVE_DATA:

		USBH_BulkReceiveData (phost,
							  CDC_Handle->pRxData,
							  CDC_Handle->DataItf.InEpSize,
							  CDC_Handle->DataItf.InPipe);

		CDC_Handle->data_rx_state = CDC_RECEIVE_DATA_WAIT;

		break;

	  case CDC_RECEIVE_DATA_WAIT:

		URB_Status = USBH_LL_GetURBState(phost, CDC_Handle->DataItf.InPipe);

		/*Check the status done for reception*/
		if(URB_Status == USBH_URB_DONE)
		{
		  length = USBH_LL_GetLastXferSize(phost, CDC_Handle->DataItf.InPipe);
		  if(length > 0)
		  {
			usbh_vcp_recv(CDC_Handle->pRxData, length);
		  }
		  CDC_Handle->data_rx_state = CDC_RECEIVE_DATA;
		}
		break;
	  default:
		break;
	  }
	}
e:usbh识别device及数据处理
while (1)
{
	/* USB Host Background task */
	USBH_Process(&usbh_cdc);
	rt_thread_delay(10);
}
e:利用rtthread系统系统的设备操作操作函数进行具体应用通讯。操作函数有:
rt_thread_find(.....)
rt_thread_read(.....)
rt_thread_write(.....)

进行stm32 usbh移植修改后,我们来了解一下usb主机识别usb设备过程
1:usbh等待设备连接中断,当设备接入中断产生,延迟200ms发送复位信号到usb设备。
2:等待usbh端口使能中断发生,当端口使能后,延迟获取从设备通讯速度,为端点0申请pipe,打开端点0的发送接收pipe,进入枚举状态。
3:枚举过程:
a:usbh通过端点0获取设备描述符前8字节数据,拿到端点0的最大传输包大小,修改端点0的发送接收pipe信息。
b:获取usb设备的全部描述信息,然后解析描述符内容。
c:设置从机的通讯地址,修改端点0的地址pipe信息。
d:获取配置描述前9字节的数据,拿到配置描述长度及配置描述符中支持的接口数。
f:获取全部配置描述符,解析数据得到接口描述符及端点描述符信息。
g:若有厂商,产品,序列号信息,则获取相对应的信息。
4:进入主机配置状态,发送设备配置信息到从设备。
5:设置usb设备属性。
6:校验usb接口类型,如果是注册的usb类,则初始化接口,打开通讯接口(通讯端点)及数据接口(数据输入输出端点)
7:发送类请求,处理接口类数据。

开发中遇到的疑问。
1.USB设备如何向USB主机发送数据?
理解:USB设备在主动发送给USB主机时,需要USB主机先发送一个IN令牌包,然后USB设备自动把之前保存在IN端点缓存区的数据发送给USB主机,然后USB主机再返回ACK;

问题:例如在USB转串口这类USB中,USB设备串口中断接收到数据,然后主动发送给USB主机,通讯过程是怎样的?IN令牌包是如何获取的?(主机怎么知道设备端写了数据,然后就下发IN包?)

答:host并不知道device上是不是有了数据,host发in包,是因为host上有程序在读设备。也就是说主机是间隔发送IN包(相当于轮询),主机根据设备的返回信号(NCK、STALL、DATAx)来确定接下来的动作,如果是DATA,就表示有数据,那么host的协议栈和OS会将数据传递给对应的app,表现出来就是程序调用的read读到了数据。如果是NAK,host会继续发in,app继续阻塞。如果是STALL,host会对app返回一个错误。

2.设备向EP缓冲写数据时,是要判断之前的数据是否已经被取走了的。只有主机下发了IN令牌,设备才能提交EP缓冲数据给HOST。

问题1:在低速与全速设备中,SOF每1ms发送一次,看了一些资料上面说的是用于同步;
疑惑点:SOF用于同步什么东西?SOF起到的作用是什么?SOF跟发送IN、OUT等指令有啥联系吗?

答:SOF目的是device和host之间的时间同步,如果你的USB设备里面没有用到同步传输和中断传输,可以忽略SOF。HOST广播发送SOF,挂起状态没有SOF。设备挂起由HOST控制,HOST停止给DEVICE发送SOF,3ms后设备就认为是挂起请求,进入挂起状态,设备不可自行进入挂起状态。

问题2:主机需要读数据的时候,会向设备发送IN指令,然后开始传输数据,
疑惑点:IN指令是什么时候发的?还是主机固定周期发?周期是SOF的1ms吗?
例如:设备有数据要发送,但是主机没有发送IN指令给设备。

答:每1ms称为一个Frame,其中INT,ISO,CTRL,BULK四种传输类型会有一个先后优先次序。1ms内可以发出很多个BULK端点的IN令牌。如果DEVICE要发送数据,必须等到IN令牌来了才能发出,否则不可以发出。可以理解为是HOST轮询收发的

STM32_usb_cdc开发问题
问题:CDC类开发时,无法从设备端向主机端发送64整数倍数据,最本质的原因就是,当发送数据长度恰好是DataIn端点的最大包长整数倍时,最后一包数据必须是零长度的数据包(ZLP)。这是由于在USB标准中,接收端并不是通过已经接收的数据长度来判断是否接收完成,且发送端也并没有给出将要发送多长的数据,因此,接收端在接收数据前,并不知道将要接收的数据是多少,那么,问题就来了,接收端又是如何判断当前的数据已经全部接收了呢?

分析:
1:若接收到的数据包长不足最大包长时,则认为当前传输完成
2:如接收到的数据包长为零时,则认为当前传输完成。
3:正式由于上述两种判断,当传输的数据刚好是端点的最大包长时,当发送完最后一包(比如64个字节)时,接收端无法判断是否传输结束,进而继续等待下一包数据。这个就是问题本质所在。

解决:
1:总的原则就是,在发送完最后一包数据后,判断发送的包长是否为端点最大包长的整数倍,如是,则补发一个零长度的数据包(ZLP)。

STM32_USB数据发送流程分析
在对USB CDC协议栈进行修改之前,我们先来梳理下USB发送的流程。
发送USB数据大概过程如下:
1: 填写DIEPTSIZ寄存器的发送包数(pakage count)和传输大小(transfer size)。
2: 使能发送端点的发送空中断(DIEPEMPMSK,利用发送空中断TXFE来将发送数据填充到DFIFO)。
3: 使能中断。
4:后续就是中断的事了。

后续将会有3次中断:
1> USB_OTG_DIEPINT_TXFE中断:在此中断处理中,程序将发送缓冲的数据分包填充到DFIFO(不能超过最大包长,只有最后一包数据才有可能小于最大包长)。
2> USB_OTG_DIEPINT_TXFE中断: 还是TXFE中断,上次TXFE填充的发送数据全部发送完了后,最终还是会继续触发TXFE中断,也就是这次中断,在这次FXFE中断中禁止FXFE。也就是说,后续不会再有TXFE中断,除非再次使能。
3> USB_OTG_DIEPINT_XFRC中断: 传输完成中断,表示到这次中断为止,传输完成。在这个中断中将回调HAL_PCD_DataInStageCallback()函数,就相当于发送中断一样。
这就是USB device cdc数据发送的流程,这里需要注意地是,对于端点0和非端点0来说,在具体流程实现上还是稍微有所差异的。究其原因,主要是端点0和非端点0的DIEPTSIZ寄存器的包大小和传输大小位宽是不一样的。

项目中遇到的问题:
1:当usb主机向从设备拿数据时,从设备没有数据,返回NAK给usb主机,usb主机会重新使能通道,再次发送IN牌包到usb设备,usb设备没有数据,仍然返回NAK给主机,一致循环下去,导致主机从机CPU占用率过高,导致很多任务无法运行。
调试现象:usb主机会一直进入到接收fifo非空中断,然而从fifo中又拿不到数据,信息是通道中断,usbh然后进入输入端点中断,处理NAK及HHC中断,不更改程序会发现进入fifo非空跟输入端点中断比较频繁。cpu一直处理中断,导致没时间处理其他任务。
解决思路:当usb主机收到NAK数据后,禁止通道接收发送,延迟后再开启通道接收发送使能,使得usb主机再次发送IN令牌包。
解决方法:
当收到通道停止中断后,并且状态是NAK状态,则不使能通道接收发送,通过sof中断定时使

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

STM32 USBH CDC开发及应用 的相关文章

  • ALSA 记录 - 了解内存映射

    我尝试使用 ALSA 从 USB 音频设备获取输入并将其作为一系列内容写入磁盘signed short价值观 我最终得到的是看似有效的数据块 其中散布着大块的零 我猜测我的缓冲区设置不正确并且没有正确使用内存映射 我正在尝试什么 采样率 8
  • 使用 DeviceWatcher 监视 USB 驱动器并检索设备信息?

    I m a WinForms开发人员和我已经知道如何使用 WMI 监视连接或断开连接的 USB 但不久前我发现了设备观察者 http msdn microsoft com en us library windows devices enum
  • adb 未检测到 micromax a111

    最近我购买了 micromax a111 Android 设备 我是安卓开发者 因此尝试使用该设备进行调试选项 但 adb 无法检测到该设备 我也更改了设置 但没有成功 如果有人有解决方案 请帮助我解决这个问题 micromax没有官方的P
  • Android 到 PC USB 读/写

    我在 PC 上有一个程序 从 USB 接收字符串输入 旧程序 我有一个 Android 4 X 平板电脑 需要向在 PC 上运行的程序提供 USB 上的字符串输入 当我在 Android 上使用示例代码时 以下代码给出了空的哈希图 PC 在
  • 在 Mac 上通过 USB 访问 iOS 设备

    我有一个移动应用程序需要将文件传输到数据库 然而 其规范之一是 如果用户没有设置无线网络 则应该能够将其插入 Mac 并将文件传输到数据库 然而 我遇到的问题是如何将上述文件从 iPad 上通过 USB 传输到计算机上 上周我研究了各种解决
  • 如何在 DriverKit 中将我的 dex 与 USB 设备匹配?

    我正在编写一个驱动程序包扩展 其目标是阻止 USB 设备 例如闪存驱动器 作为起点 我选择了示例项目https developer apple com documentation driverkit communicating Betwee
  • 在 Python 中将 USB 视频捕获设备友好名称与 OpenCV 端口号相关联

    我想在 Windows 平台上使用 Python 获取外部 USB 视频捕获设备的友好名称和 USB 端口号 我正在使用 OpenCV 从 USB 捕获设备捕获视频 OpenCV 将 USB 端口称为 1 找到的第一个工作摄像头 0 对我来
  • 如何查找USB盘符?

    我正在编写一个安装程序来将应用程序安装到 USB 驱动器 该应用程序只能从 USB 驱动器使用 因此它可以通过自动选择要安装的 USB 驱动器来为用户节省额外的步骤 我可能会尝试使用 Nullsoft 或 MSI 进行安装 但由于我最熟悉
  • Android USB_DEVICE_ATTACHED 持久权限

    如何让 Android 在每次重新连接 USB 设备时都不再请求权限 我想让它记住 USB 设备的 默认使用 复选标记 这样我就不必每次都向同一设备授予权限 我以编程方式检测 USB 设备 Android 手机 何时连接到我的主机设备 An
  • 获取已连接 USB 设备的端口名称

    当USB设备连接到计算机时 如何使用C 代码获取它所连接的端口名称 我找到了很多方法来查找 USB 何时连接 断开 驱动器号 路径 设备 ID 等 但没有找到任何明确的示例来说明如何知道它连接到哪个端口 我看到了一种可能的解释 但这涉及很多
  • Linux 源代码中的哪个位置会识别特定的 USB 设备?

    我有一个特定的 USB 设备 我想检查其 Linux 驱动程序源代码 我的理解是 USB 驱动程序执行的第一步是注册自己能够处理具有特定供应商 ID 和产品 ID 的设备 就我而言 供应商 ID 是0BDA产品 ID 是8187 有了这些信
  • iOS 中通过 USB 进行反向端口转发

    我在桌面上有一个 Web 套接字服务器 在 iPhone 设备上有一个客户端 我想使用 USB 而不是任何网络与他们通信 我已经使用 adb reverse 在 android 上实现了它 但无法找到适用于 iOS 的任何解决方案 我尝试使
  • Delphi - 如何获取 USB 可移动硬盘和记忆棒的列表?

    在我的应用程序 Delphi 中 我需要列出所有 USB 存储设备 这些可以是闪存棒or外部存储驱动器 有一个Jvcl成分JvDriveCombo 并且它有DriveType属性 问题是我是否选择DriveType Fixed那么除了外部驱
  • 有没有办法通过 WiFi 部署/调试 Cordova Android Ionic 应用程序? [关闭]

    Closed 这个问题是与编程或软件开发无关 help closed questions 目前不接受答案 这是一个双胞胎this https stackoverflow com questions 46596236 is there a w
  • USB编程

    我想对微控制器 AVR 进行编程 以通过 USB 控制一些 LED 它只是出于对如何构建和编程 USB 设备的兴趣 有一些 AVR 微控制器支持 USB 协议 或者我可以自己在另一个微控制器中实现 USB 协议 但我想知道用什么来在计算机上
  • 如何在Android上读取/写入外部USB存储设备?

    我目前正在制作一个应用程序 需要能够读取和写入通过 USB OTG 适配器连接的 USB 闪存驱动器 有没有一种简单的方法可以通过标准访问此存储Java io File蜜蜂 该应用程序只能在运行 Android 4 2 2 的已 root
  • 如何在 C# 中知道 PID 和 VID 来发现虚拟 COM 端口名称

    如果我知道 PID 和 VID 我会尝试找到查找 COM 端口名称的正确方法 到目前为止 我写了解决方法 但我不相信没有更优雅和正确的方法 顺便说一句 我知道我可以使用 REGEX 编写此代码只是为了测试解决方法 我知道还有很大的改进空间
  • 使用 Intel xHC 执行启用插槽命令后,如何确定 USB 设备连接在哪个根集线器端口上?

    我正在一个使用 UEFI 启动的小型业余爱好操作系统中为英特尔 xHC 编写一个小型驱动程序 重置所有根集线器端口后 我收到 2 个端口状态更改事件 这是因为我要求 QEMU 在命令行中模拟 USB 键盘和 USB 鼠标 每个设备的一个端口
  • Android USB Host 模式和 Accessory 模式

    我正在尝试学习 Android USB 主机 配件连接 我读到 Android 设备可以充当 USB 主机或 USB 配件 因此 我创建了两个项目 其中一个是 USB 主机项目 另一个是 USB 附件项目 我将这些项目安装到两个不同的 An
  • 未找到 Chrome 应用 USB DigitalPersona 指纹识别器

    我正在尝试开发 Google Chrome 应用程序 或扩展程序 不确定 以在 Windows 上使用 DigitalPersona 指纹识别器 下列的 https developer chrome com apps usb https d

随机推荐

  • 常用的运算放大器电路

    在线仿真网站 http scratch trtos com circuitjs html 一 反向比例放大电路 二 同向比例放大电路 三 电压跟随器 四 反向求和运算电路 五 同向求和运算电路 六 加减法运算放大器 七 差分放大器 八 积分
  • 关于自制CMSIS_DAP离线下载器下载算法的代码说明:“0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA“

    关于自制CMSIS DAP离线下载器下载算法的代码说明 0xE00ABE00 0x062D780D 0x24084068 0xD3000040 0x1E644058 0x1C49D1FA 在自制CMSIS DAP离线下载器的时候 利用FLM
  • Mysql篇-第2章,什么是脏读、幻读、不可重复读?如何处理?

    一 Mysql进行事务并发控制时经常遇到的问题 脏读 在事务进行中 读到了其他事务未提交的数据 举个例子 有一个table表 如果执行顺序如下 这种情况下左边查询的结果会是101 正是因为读取到了另一个事务未提交的数据 幻读 在一个事务中
  • selenium 获取cookie 并使用

    selenium 获取cookie 参数设置 以获取阿里云cookie范例 from selenium import webdriver import json url https account aliyun com login logi
  • 使用Python的方式理解Golang的结构体struct

    Go源码 package GoTools import fmt 定义结构体存储密码 type Config struct password string func InitConfig password string Config c ne
  • Vue用户进行页面切换(路由跳转)时,动态改变路由的动画(transition效果)

    当我们在使用Vue Router时 为了用户有更好的视觉效果及体验 我们通常需要实现基于路由的动态过渡效果 github https github com Rise Devin FullStack Product Transport Use
  • retinaface代码讲解_「干货」RetinaFace最强开源人脸识别算法

    看来最早商业化的人脸检测为目标检测算法 依然是各大CV方向AI公司的必争之地 那我们今天主角就是RetinaFace RetinaFace 是今年5月份出现的人脸检测算法 当时取得了state of the art 作者也开源了代码 过去了
  • 集合的知识

    集合 collection集合的常用方法 collection的特点 Collection代表单列集合 每个元素 数据 只包含一个值 Map代表双列集合 每个元素包含两个值 键值对 Collection集合特点 由于collection是一
  • gRpc指南

    本文翻译自官网 原文 https grpc io docs languages java quickstart 快速开始 下面通过一个简单的样例 让你快速上手基于java的gRpc的使用 前置条件 JDK7以上版本 获取示例代码 示例代码是
  • 斯坦福密码学课程-笔记-01-Introduction绪论

    斯坦福密码学课程笔记 01 绪论 Introduction Course Overview Cryptography is everywhere Secure communication Secure Sockets Layer TLS P
  • 使用thop库对yolo等深度学习模型的FLOPS进行计算

    据说yolov5原来的FLOPS计算脚本有bug 因此这个大神推荐使用thop库进行计算 代码如下 input torch randn 1 3 416 416 flops params thop profile model inputs i
  • 【华为OD机试真题 C++】寻找链表的中间结点

    前言 本专栏将持续更新华为OD机试题目 并进行详细的分析与解答 包含完整的代码实现 希望可以帮助到正在努力的你 关于OD机试流程 面经 面试指导等 如有任何疑问 欢迎联系我 wechat steven moda email nansun09
  • SuperMemo 【POJ - 3580】【Splay+懒标记递推想法】

    题目链接 可以说这道题很好的给我们讲述了在Splay树上的lazy标记的递推 跟线段树上类似 在这棵二叉搜索树上 我们一样的去递推懒标记 接下来说说在哪几处需要专门注意懒标记的使用 这里有几处需要注意的地方 就是一开始给你的元素不是已经排好
  • 四种常见的代码覆盖率测试

    您听说过 代码覆盖率 吗 在这篇文章中 我们将探讨什么是测试中的代码覆盖率 以及四种衡量它的常用方法 什么是代码覆盖率 代码覆盖率是衡量测试代码测试了源代码百分比多少的指标 它可以帮助您识别可能缺乏适当测试的代码区域 通常 覆盖率指标会这样
  • 大头小头 字节序

    http blog csdn net zjf82031913 article details 7245183 字节序的问题涉及硬件架构 目前主要是Motorola的PowerPC系列CPU和Intel的x86系列CPU PowerPC系列采
  • Kibana导入CVS数据

    导入CVS数据 下载数据源CVS文件2018 7 12月份地震数据 https www elastic co assets bltb0648a200c490f5e quakes data csv 导入Machine Learning gt
  • 压缩zip文件和解压zip文件(设置压缩密码)

    欢迎访问个人博客 德鲁大叔撸代码 说明 注意引入的依赖 否则一直报错 很不容易找到的错误 import net lingala zip4j core ZipFile import net lingala zip4j exception Zi
  • 搭建并部署Vue3+TypeScript+Vite+ElementPlus项目

    目录 前言 一 搭建Vue3项目 1 安装yarn命令 2 创建VUE项目 3 安装VUE依赖 4 启动VUE项目 5 访问VUE项目 6 打包VUE项目 带项目名 7 部署VUE项目 二 使用Visual Studio Code管理vue
  • CVPR2023 语义分割论文合集

    国际计算机视觉与模式识别会议 CVPR 是计算机科学领域中的顶级会议之一 也是图像处理 机器学习 人工智能等多个领域的交叉学科会议 每年的CVPR会议都会有大量的论文投稿和学术交流活动 其中涵盖了包括图像处理 计算机视觉 模式识别 机器学习
  • STM32 USBH CDC开发及应用

    USB 是英文 Universal Serial BUS 通用串行总线 的缩写 其是一个外部总线标准 用于规范USB主机与外部设备的连接和通讯 由于项目需要 需要开发基于STM32 USB主机 HOST 的CDC的开发 用于编队表演系统中底