项目标题摆在眼前串口不够用想用STM32做USB主机再接一堆CH340出来当虚拟串口用。这方向一听就很“嵌入式痛点”——我自己的调试台也是一样三路串口打底外设再挂几个经常拔来拔去。后来我把STM32的OTG口改成Host模式外接一个USB HUB下面挂了四五个CH340转串口小板主控一次性多出好几路“虚拟串口”用起来就像在用普通UART一样。这套路踩了不少坑这篇把选型、原理、驱动实现和排查方法一次讲透。STM32做USB Host这件事最容易被忽视的地方是不是所有STM32都能当主机。很多朋友拿着F103最小板就想做结果USB外设根本不支持Host模式只能当Device。所以开篇先花点篇幅搞清楚硬件底子后面才不至于白忙。1. 方案选型与整体设计1.1 为什么需要STM32自己当USB主机常规思路里CH340这种USB转串口芯片都是插电脑、插树莓派用的让单片机去“反向”读取它听起来有点绕。但实际项目里这个需求很真实主控板串口外设数量有限UART不够了要么换大封装MCU要么外扩多路UART芯片要么就用一套“USB Host CH340阵列”的通用方案。后者的好处很明显CH340模块便宜、随处能买、电平可调而且一个USB口能通过HUB引出4路、7路甚至更多串口硬件改动只是一根USB线加一个小HUB比重新画板子优雅得多。STM32在这里的角色是“带键盘的小电脑”负责枚举USB设备、管理传输端点、把CH340的数据变成几个独立的串口数据流供业务代码直接读写。适合参考这个方案的人一般是手上已经有带OTG的STM32板子又需要快速扩串口的开发者或者正准备做一版“多串口采集/转发盒子”的朋友。核心不是让你死磕USB协议而是把一套可复用的Host驱动框架跑起来后续换USB键盘、U盘、网卡都能沿用。1.2 硬件选型不是所有STM32都能当Host这点必须放在最前面说因为我见过太多人拿F103C8T6一个劲猛搞最后查手册才发现芯片上的USB只有一个Device模式根本没法枚举外部设备。做一个简单的硬件能力表芯片系列USB外设类型是否可作Host备注STM32F103系列USB Device only不支持只能模拟串口、HID这类设备STM32F105/107系列OTG_FS支持需要外接ID/上拉电路协议栈自己写STM32F405/407系列OTG_FS / OTG_HS支持最推荐的起步选择F407可Host可DeviceSTM32F7/H7系列OTG_FS / OTG_HS支持性能更强可跑高速USB HostSTM32F1 CH376/MAX3421E外置Host控制器支持折中方案但等于再加一颗芯片我的建议是直接用带OTG_FS的芯片比如F407引脚不多外部加一个最小系统就能搞定。注意OTG_FS的DP/DM引脚一般是PA11/PA12F4系列Host模式下需要把OTG_FS配置成“全速主机”并且加上VBUS供电控制引脚通常是PC5或PA9不同板子不一样。如果用F407同时还想做“上位机虚拟串口”的功能最好选带OTG_HS的型号如F407ZG/F429它有两个USB口一个口做Host接CH340另一个口做Device模拟成虚拟串口给电脑用这样主机和设备的角色能同时存在。1.3 软件方案ST官方Host库与TinyUSB的抉择软件选型是整个项目的分水岭。ST官方提供了一套USB Host库CubeMX里勾选“USB_HOST”就能生成支持HID、MSC、CDC等类设备。但坑就在这官方Host库对“HUB扩展”支持很弱很多版本根本没有现成的HUB类驱动。你要是想接一个4口USB HUB再插4个CH340用官方库会非常痛苦——枚举HUB这一关就够折腾。相比之下TinyUSB这个开源库在Host模式上做得更灵活。它本身支持Device/Host双模式0.16版本之后加入了HUB class支持而且Vendor类设备CH340就是典型的Vendor类可以自己写很简单的批量收发逻辑不用套标准类协议。所以我最终选择的是“STM32裸机初始化 FreeRTOS TinyUSB Host模式”这套组合。两者对比方案ST官方USB Host库TinyUSB Host模式HUB支持很弱多数版本没有有实验性HUB class可用自定义Vendor设备驱动需要自己扒库接口繁琐原生API清晰直接操作端点学习和调试成本中等较低灵活性受限于库内封装高适合折腾社区资料官方文档多但杂GitHub例子多活跃度好如果你只是接一个CH340不用HUB那ST官方库也能忍但只要标题里带“多个”HUB支持就是刚需我强烈建议直接用TinyUSB。2. USB Host开发的核心细节拆解光有硬件和库还不够得知道USB在底层到底干了什么否则写代码就是猜。这里我用尽量通俗的方式把整个链路拆开。2.1 USB设备是如何被识别的枚举过程USB主机的第一步是“枚举”。你可以把这个过程理解成主机新认识一个陌生人先问名字、再问职业、再问联系方式然后按照该人的能力分配一个“工号”。具体到USB协议枚举大致分这么几步主机检测到设备接入给USB总线复位信号。设备响应一个“设备描述符”里面包含VID、PID、类代码等信息。主机给设备分配一个唯一的7位地址。主机再次读取“配置描述符”、“接口描述符”、“端点描述符”。主机发送“设置配置”请求设备进入工作状态。描述符这东西可以理解成一张“能力说明书”。CH340的说明书上会写着我是多少设备地址我有几个接口接口下有几个端点端点是批量传输还是中断传输数据方向是IN还是OUT。在STM32 Host端这些描述符会以二进制结构体传递TinyUSB已经封装好了你只需要在挂载回调里读取并解析即可。关键是知道枚举成功后所有真正的数据通信都是通过“端点”进行的不是直接读写一串“串口数据”。2.2 CH340在USB总线上到底是什么样子CH340是南京沁恒的USB转串口芯片市面上最常见的CH340G、CH340C模块USB枚举信息一般如下VID0x1A86PID0x7523部分批次可能是0x5523或0x5502以实际枚举为准接口类Vendor类0xFF不是标准的CDC/ACM类接口数一般是1个接口带2~3个端点通信方式上CH340的数据走的是批量端点Bulk Transfer。常见配置是一个批量IN端点设备给主机发数据地址通常是0x82一个批量OUT端点主机给设备发数据地址通常是0x02。有些版本的CH340还会有个中断端点做状态通知但业务数据主要在批量端点上。这里有个很关键的坑CH340的波特率设置、DTR/RTS控制都是通过“厂商自定义控制请求”完成的而不是USB标准类请求。也就是说你在STM32上不能靠“标准CDC初始化”去配波特率必须自己写控制传输向CH340的控制端点发特定的Vendor指令。不同批次的CH340厂商指令的细节可能不一样。网上开源驱动比如Linux内核里的ch341.c、ch34x.c以及各种CH340逆向工程基本把路趟平了你直接参考它们不需要自己抓USB包硬猜。核心逻辑无非是向控制端点发一组字节里面包含波特率分频系数、数据位、停止位等参数再发一组字节设置DTR/RTS电平。2.3 USB HUB扩展多路的原理USB HUB的存在让一个物理口能挂多个设备。插上HUB后主机先枚举HUB本身然后每个下游端口再接设备时HUB会向主机报告“我某个端口有设备接入”主机再对那个端口做一次复位和枚举。理论上一共有两层设备第一层是HUB第二层是HUB下游的CH340们。主机的角色更像个管家它要知道每个CH340挂在哪个端口、拥有哪个USB地址、用哪个端点收发数据。这给我们带来的选择是如果只是简单扩路数选4口或7口USB HUB模块即可但要注意HUB有“总线供电”和“自供电”两种。我们接4个CH340模块时总线供电可能不够稳定尤其CH340模块上如果还带电源指示灯、转接芯片电流会大一些。我这边踩过的坑就是USB HUB用总线供电四个CH340同时插满枚举老是失败后来换成带DC供电的自供电HUB就好了。带宽也要提前算。USB全速12Mbps下一个1ms的帧批量传输大约能传1200字节左右这是理论值实际受协议开销影响会更少。每路串口115200bps实际有效数据约11.5KB/s四路同时全速也就是46KB/s左右远小于1MB/s的理论上限所以每路常用波特率下完全没问题。但如果每路都跑到921600bps以上四路加起来接近甚至超过带宽上限就会丢包。这个在方案阶段就要心里有数。2.4 多路虚拟串口的资源管理多个CH340接入后不能每路都用一个独立的任务去“死等”数据那样CPU会忙死。我的做法是Host库在后台跑一个USB任务负责轮询/中断处理批量端点每个CH340的收数据回调里把收到的字节塞进一个环形缓冲区应用层任务只需要从环形缓冲区取数据。本质上就是把每个CH340映射成一个“串口句柄”底层是USB端点上层是标准读写接口。代码里可以定义这样一个结构体typedef struct { uint8_t dev_addr; // USB设备地址 uint8_t ep_in; // 批量IN端点地址 uint8_t ep_out; // 批量OUT端点地址 uint16_t ep_in_size; // IN端点最大包长 uint16_t ep_out_size; // OUT端点最大包长 volatile uint8_t connected; // 是否已连接 ringbuf_t rx; // 接收环形缓冲区 uint32_t baud; // 当前波特率 } ch340_port_t;然后用一个数组ch340_ports[]存多路状态。每次有新CH340插入就给它分配一个数组元素拔出时释放。这个思路和操作系统管理文件描述符差不多非常管用。3. 从CubeMX到代码完整实操流程下面进入“照着做”的部分。我以STM32F407 FreeRTOS TinyUSB Host为例给出可落地的全流程。3.1 CubeMX配置USB_HOST与FreeRTOS打开STM32CubeMX选择芯片型号我这里用F407VGT6。按下面的步骤配置配置时钟外部高速晶振HSE系统时钟设为168MHz。USB OTG FS外设的时钟源通常是48MHzCubeMX会自动派生但要注意时钟树里USBCLK必须来自HSE或PLLQ不能乱设。配置USB_OTG_FSMode选择“Host_Only”。使能VBUS sensing有些板子没有VBUS检测脚就要禁用VBUS sensing否则卡枚举。配置FreeRTOS找一个任务优先级分配方案。TinyUSB的tuh_task()最好放在默认任务或一个专用USB任务里优先级不要太高但也不能太低否则USB事件处理不及时。生成工程后手动添加TinyUSB代码或者直接用TinyUSB的CMake/Makefile方式编译。CubeMX不能直接生成TinyUSB的Host代码所以CubeMX在这里只负责时钟、引脚、FreeRTOS配置USB协议栈交给TinyUSB去做。这一步很多人会困惑觉得CubeMX里选了USB_HOST就应该自动生成全套实际上那生成的是ST官方库不是我们要的TinyUSB。3.2 TinyUSB工程集成与配置TinyUSB源码克隆下来后把src目录加入编译路径。关键的配置文件是tusb_config.h里面有几个宏必须开#ifndef TUSB_CONFIG_H #define TUSB_CONFIG_H #define CFG_TUSB_ENABLED 1 #define CFG_TUSB_OS OPT_OS_FREERTOS #define CFG_TUSB_MCU OPT_MCU_STM32F4 // Host模式 #define CFG_TUH_ENABLED 1 #define CFG_TUH_MAX_DEVICE 8 #define CFG_TUH_HUB 1 // 启用HUB class #define CFG_TUH_MAX_HUB_PORT 4 #endif如果你不启用CFG_TUH_HUB接一个CH340也能用但要多路HUB必须开。CFG_TUH_MAX_DEVICE要大于1比如8表示最多支持8个设备其中有一个HUB和若干CH340自己按实际路数调整。TinyUSB的回调函数里有三个最关键void tuh_mount_cb(uint8_t dev_addr) { // 设备枚举完成可以读取设备描述符、配置描述符 } void tuh_umount_cb(uint8_t dev_addr) { // 设备拔出释放资源 } void tuh_hub_port_connect_cb(uint8_t hub_addr, uint8_t port) { // 某HUB端口有新设备连接等待枚举完成 }这些回调会在tuh_task()中被调用。所以主循环或RTOS任务里必须周期调用tuh_task()。3.3 编写CH340的USB类驱动这是整个项目最核心的部分。思路是在tuh_mount_cb回调里拿到设备地址后读取配置描述符找到Vendor接口下的批量IN/OUT端点地址然后打开端点启动接收。我这里给出一个简化但能说明原理的框架#include tusb.h #define CH340_VID 0x1A86 #define CH340_PID 0x7523 extern ch340_port_t ch340_ports[8]; static void ch340_open_endpoints(uint8_t dev_addr) { // 1. 获取设备描述符查看VID/PID确认是CH340 tusb_desc_device_t desc_dev; tuh_descriptor_get_device(dev_addr, desc_dev, sizeof(desc_dev), 0, NULL); if (desc_dev.idVendor ! CH340_VID) { return; // 非CH340设备忽略 } // 2. 获取配置描述符遍历接口和端点 // TinyUSB的Host API里可以用 tuh_descriptor_get_configuration 获取完整配置块 // 然后手动解析bInterfaceClass、bNumEndpoints、bEndpointAddress。 uint8_t cfg_buf[512]; // 实际使用时要先请求配置描述符总长度再根据长度读取完整数据 // 这里为了简洁直接假设已经拿到 cfg_buf // 3. 找到第一个Vendor接口下的批量端点 uint8_t ep_in 0, ep_out 0; uint16_t ep_in_size 0, ep_out_size 0; // ... 遍历cfg_buf过程省略遇到0xFF类接口记录端点地址和wMaxPacketSize // 4. 打开两个批量端点 tusb_edpt_open(dev_addr, ep_in, TUSB_XFER_BULK, ep_in_size, NULL); tusb_edpt_open(dev_addr, ep_out, TUSB_XFER_BULK, ep_out_size, NULL); // 5. 初始化CH340的串口参数发送厂商控制请求 ch340_set_baudrate(dev_addr, 115200); ch340_set_dtr_rts(dev_addr, true, true); // 6. 启动批量IN传输准备接收串口数据 tuh_xfer_t xfer { .daddr dev_addr, .ep_addr ep_in, .buflen 128, .buffer rx_buffer, .complete_cb ch340_rx_complete_cb, }; tuh_xfer(xfer); }这段代码的重点是端点地址、端点大小要仔细解析IN/OUT方向不能搞反。CH340的批量端点通常是0x82和0x02但不同批次可能不同写代码时一定要根据描述符解析出来再使用不要硬编码。波特率设置函数ch340_set_baudrate()不是标准USB类请求而是厂商自定义控制请求。实现参照Linux下的ch341.c驱动核心就两步static void ch340_set_baudrate(uint8_t dev_addr, uint32_t baud) { // 根据ch341.c驱动源码计算分频系数 // 向控制端点0发送Vendor请求请求号为0xA1/0x9A等具体值随芯片版本变化 // 发送前最好有USB抓包工具验证 uint16_t divisor ch340_calc_divisor(baud); uint8_t buf[4] {0}; tuh_control_xfer(dev_addr, 0x40, CH340_SET_BAUD, divisor, 0, buf, sizeof(buf), NULL); }注意这里我没有给出具体的请求号因为CH340不同型号差异太大。网上一些文章直接贴死一个十六进制指令照抄之后在某个型号上可能连枚举都过不去。更稳妥的做法是找一份你手头CH340型号对应的开源驱动源码照着适配。3.4 使用USB Hub管理多个CH340TinyUSB开了CFG_TUH_HUB之后HUB枚举和端口管理由库自动处理。我们要做的是在端口连接回调里等待设备地址分配完成。通常逻辑是void tuh_hub_port_connect_cb(uint8_t hub_addr, uint8_t port) { // HUB端口有设备接入TinyUSB会继续后续枚举 // 真正的业务处理在tuh_mount_cb里做这里只需要记录端口状态 }HUB接上后tuh_mount_cb可能被调用两次第一次是HUB设备本身枚举完成第二次是每个下游CH340设备枚举完成。判断是HUB还是CH340就靠VID/PID。如果是HUB的VID/PID不去初始化成串口如果是CH340就走ch340_open_endpoints流程。HUB还有一个老坑有些HUB芯片的端口电源默认是关的主机必须发送“设置端口特性(set port feature)”请求打开电源。TinyUSB的HUB class会处理这个动作但使用某些“硬线配置”的HUB模块可能不需要主机额外开电。面板上的“电源灯”不代表“可枚举”真正的标准是看tuh_hub_port_connect_cb有没有被触发。多路管理上我维护一个“空闲槽位表”。每个CH340插入后就在ch340_ports[]里找一个connected为0的槽位写入dev_addr和端点信息拔出后置0。业务代码只要遍历这个数组就能发现串口增减。3.5 把数据交给应用层FreeRTOS任务调度数据从CH340收上来后最简单的交付方式是“回调进环形缓冲区 任务消费”。我在ch340_rx_complete_cb里做这几件事static void ch340_rx_complete_cb(tuh_xfer_t* xfer) { uint8_t dev_addr xfer-daddr; uint8_t ep_addr xfer-ep_addr; uint16_t len xfer-xfered_bytes; // 把收到的len个字节写入对应串口槽位的环形缓冲区 ch340_port_t* p find_port_by_dev_addr(dev_addr); if (p len 0) { ringbuf_write(p-rx, xfer-buffer, len); // 通知应用层任务有数据到达 xSemaphoreGiveFromISR(p-rx_sem, NULL); } // 继续启动下一次接收保证数据不断流 tuh_xfer_t next *xfer; next.buflen sizeof(rx_buffer); tuh_xfer(next); }应用层某个任务想读某一路串口数据就阻塞在对应的信号量上void uart_reader_task(void* arg) { ch340_port_t* p ch340_ports[0]; // 举例第一路CH340 uint8_t buf[256]; while (1) { xSemaphoreTake(p-rx_sem, portMAX_DELAY); uint16_t n ringbuf_read(p-rx, buf, sizeof(buf)); // 把n个字节交给业务处理 } }这样四路CH340就是四个独立的“虚拟串口”业务层只看到串口编号和字节流完全不用关心底层USB细节。4. 常见问题与排查技巧实录这里整理的是我个人在这套方案上真正遇到过的问题不是抄文档。每一项我都给过排查方法直接照做能省不少时间。4.1 设备反复枚举失败USB头无法识别现象STM32的USB Host接上CH340后tuh_mount_cb偶尔触发一次然后就再也不动了或者枚举到一半就超时。排查步骤先检查USB线缆和CH340模块是不是好的把CH340插到电脑上装好驱动看看能不能枚举出串口。如果电脑都识别不了那就是模块本身的问题。检查OTG_FS的VBUS检测F4系列Host模式下如果使能了VBUS sensing但VDATA引脚没有接对设备就检测不到插拔。很多最小系统板上VBUS sensing脚没有引出来直接把CubeMX里的“VBUS sensing”关掉试试。查DP/DM走线USB的数据线要短最好不要飞线超过10厘米。CH340模块上的USB座如果焊接不良也会导致反复枚举失败。4.2 CH340识别到但收不到数据现象tuh_mount_cb能触发VID/PID也对但往CH340发数据没反应或者读不到外部串口发来的数据。这个90%是初始化序列没做全。CH340不是一个“插上就能用”的USB设备必须先完成发送厂商控制请求设置波特率。发送厂商控制请求设置DTR/RTS等Modem信号。有些CH340版本还要先读取一个版本号寄存器才能进入数据模式。调试方法先把CH340插到电脑上用USB抓包工具比如免费的WiresharkUSBPcap或逻辑分析仪看电脑插入CH340时发了哪些控制请求再模拟这些请求到STM32端。一套下来底层问题基本能定位。4.3 多CH340同时工作互相干扰/丢包现象单独插一路CH340很稳定插满四路后某一路频繁丢字节甚至所有路都卡死。原因多半是USB带宽耗尽或者HUB供电不稳。先算带宽如果每路波特率都超过921600四路同时满速全速USB基本扛不住。这时候有两个方向降低串口波特率到115200或460800满足项目需求即可。如果必须高波特率满速换支持USB高速480Mbps的OTG_HS主机并把HUB和CH340都换成高速设备。不过CH340本身是全速设备所以实际总带宽还是受限于单设备全速这个要意识到。供电问题更好排查换自供电HUB或者给HUB外加5V电源不带负载再看是否复现。4.4 硬件12M带宽计算的经验我习惯在项目初期把每路串口的极限吞吐折算成USB带宽。按CH340全速设备来算批量传输在1ms内大约能传1200字节1.2MByte/s。115200波特率串口有效数据率约11.5KB/s算上校验位停止位也不超过15KB/s四路才60KB/s带宽余量充足。但如果是921600波特率一路就要92KB/s四路接近368KB/s再加协议开销已经快到极限了。维护一张“波特率-每路带宽-最大路数”估算表能避免后期改方案。4.5 STM32既当Host又当Device的扩展问题如果你想让这台设备既接多个CH340又能被电脑当成虚拟串口一个USB口做不到同时Host和Device。F407有两个USB口OTG_FS和OTG_HS。可以配置一个作Host一个作Device。注意OTG_HS如果不用外部PHY只能以全速12Mbps工作和OTG_FS性能相同要跑480Mbps得外接USB PHY芯片比如USB3300。这个扩展方案我已在第二版板子上跑通了代码上其实就是两套独立的TinyUSB实例或者一套ST库一套TinyUSB互不干扰。4.6 不要忽视电源与地回路CH340模块如果分别供电每个模块的地和STM32的GND必须连在一起。USB线上的GND不是万能的模块和主机可能产生地电位差导致数据错乱甚至烧芯片。我习惯在USB线中间加一个小共模电感同时保证所有模块共用同一个5V电源和GND平面。自供电HUB的电源地和STM32板子的地也建议单点相连。5. 写在最后这套玩法还能往哪走USB Host这条路走通之后你会发现STM32不再只是一个“外设控制单片机”它已经变成了一个能主动连接外部USB设备的“小主机”。CH340阵列只是第一步后续可以挂USB键盘鼠标做输入设备挂U盘做数据记录器甚至挂4G上网卡做联网透传。核心的枚举、端点管理、HUB调度全是一套逻辑学一遍受用很久。我个人体会是做这种多路串口扩展最花时间的其实不是代码量而是对USB协议的耐心。先理解枚举再理解类设备和Vendor设备最后再把HUB和带宽控制住剩下的就是体力活。如果你拿到这个标题第一反应是“直接在单片机上加几个串口芯片”也不是不行但灵活性和成本都不会比USB Host方案好。建议先拿一块F407开发板买一个4口USB HUB和四个CH340模块按上面的步骤走一遍把log打印出来看到四路数据同时刷新的时候那种成就感相当值。
企业数字化 ERP 产品动态
相关推荐
FPGA实战问答:UART/LVDS/布局布线卡点解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 3:25:42
在 Ubuntu 上安装 FerretDB:PostgreSQL / SQLite 后端部署完整指南 后端数据库文档数据库 【免费下载链接】FerretDB A truly Open Source MongoDB alternative 项目地址: https://gitcode.com/gh_mirrors/fe/FerretDB 点击查看 免费下载 FerretDB 是一款开源的文档数据库,它让 MongoDB 的语法与生态在 PostgreSQL&#… · 2026/9/24 3:25:36
ESP32开发板下载超时?三步配置国内镜像源加速安装 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 3:25:36
Windows镜像补丁集成:boot.wim与install.wim分级注入实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 4:06:13
Java大文件上传内存优化:分片与流式处理全解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 4:06:07
电流采样电阻PCB布局:三种开尔文接法对比与0.1%精度实现 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 4:05:42
Prisma CLI 数据导出实战:`prisma export` 命令详解与底层实现原理 后端数据库GraphQL 【免费下载链接】prisma1 💾 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL & MongoDB) [deprecated] 项目地址: https://gitcode.com/gh_mirrors/pr/prisma1 点击查看 免费下载 本文围绕 Prisma 1.x 的 … · 2026/9/24 4:05:18
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44