嵌入式总线实战(一):RS-485土壤温湿度传感器通讯指南
#阿文的成长日记引言本文是嵌入式总线实战专栏的第一篇笔记重点说明基于STM32的USART硬件配合RS-485收发控制引脚完成土壤传感器的数据采集与解析然后在通过USB转串口将数据实时打印到电脑上完成实时监控。欢迎各位大佬私信留言RS-485概述什么是RS-485它是美国电子工业协会Electronic Industries AssociationEIA于1983年发布的串行通信接口标准是一种串行半双工异步的物理层总线。具有以下几大特点1.允许同一总线上并联多个设备最大可以支持32个2.传输信号时采用差分信号传输3.传输距离来说相对较远理论通讯距离可达1200米4.RS-485的速率可高达10Mbit/s5.接线简单只需两根数据线即可完成通信。Modbus协议RS-485理论上适配所有的串口协议常用的协议有Modbus协议Profibus协议等。Modbus协议在RS-485上绝对是最通用的“普通话”。根据SN-3000-TR-N01土壤温湿度传感器的通信协议文档该传感器采用Modbus-RTU协议这里我们就重点说一下Modbus-RTU。Modbus-RTURemote Terminal Unit是Modbus协议在串行链路上的一种传输模式采用16进制编码具有较高的传输效率和紧凑的帧结构。在RS-485网络中Modbus-RTU是最常用的实现方式。一个完整的Modbus-RTU帧由以下部分组成且帧与帧之间通过至少3.5个字符时间的空闲间隔来分隔。地址码1字节标识从站设备的地址范围0-2470为广播地址1-247为从站地址。功能码1字节指定要执行的操作类型如读寄存器、写寄存器等。数据N字节根据功能码不同包含寄存器地址、数据长度、寄存器值等信息。CRC校验2字节循环冗余校验用于检测传输错误采用CRC-16算法。Modbus-RTU定义了多种功能码本次土壤温湿度传感器主要使用读保持寄存器0x03功能码来读取土壤温度和湿度数据。我们了解了什么是RS-585和Modbus协议接下来我们进入实战环节。开发环境与工具首先是开发环境与工具的选择具体工具和版本如下所示。工具版本STM32CubeMXV6.18.0STM32CubeIDEV2.2.0ST-LINK/V2——SSCOM串口助手V5.13.1Saleae逻辑分析仪V2.3.18接口硬件电路设计配置好开发环境我们就要完成硬件电路的设计了我将从芯片选型RS-485,USB转串口模块土壤温湿度传感器的硬件连接这几个方面介绍。主控片的芯片选择采用STM32F407IGH6芯片该芯片是一款性能强劲、外设丰富的Cortex-M4微控制器。其高达168MHz的主频、1MB Flash、使其非常适合电机控制、工业自动化、人机界面、高端物联网网关等复杂应用。土壤温湿度芯片的选择采用SN-3000-TR-N01传感器该传感器适用于土壤温度以及水分的测量经与德国原装高精度传感器比较和土壤实际烘干称重法标定精度高响应快输出稳定。受土壤含盐量影响较小适用于各种土质。可长期埋入土壤中耐长期电解耐腐蚀抽真空灌封 完全防水。 该传感器广泛适用于科学实验、节水灌溉、温室大棚、花卉蔬菜、草地牧场、 土壤速测、植物培养、污水处理、粮食仓储及各种颗粒物含水量和温度的测量。RS-485的硬件连接RS-485芯片的RO端接在主控片的USART1_RXDI端接在USART1_TXRE,DE短接并且接入V5电压让芯片内部进行切换RS485A和B端接入土壤温湿度的RS485的A和B端口。土壤温湿度传感器的电气连接USB转串口硬件连接为了能够实时监测到传感器的数据接入了USB转串口模块将土壤温湿度的数据通过串口实时发送到电脑上我们采用UART6,硬件连接方式如上图所示。实物硬件连接图除此之外主控片需要外接电源时钟系统复位系统等这里我相信大家都只知道怎么去做就不罗嗦了。接下来我们就重点说以下软件代码是如何实现的系统软件设计我们做完硬件的实现接下来就是对功能的实现了到了考验我们代码能力的时候了土壤传感器数据帧格式该土壤传感器采用Modbus-RTU的数据帧格式上文已经说明了其帧的组成我们重点来看下该传感器的询问帧和应答帧的示例通过该示例我们发现读取该传感器的数据地址码为0x01并且先返回湿度值在返回温度值。温度计算当温度低于 0 ℃ 时温度数据以补码的形式上传。温度FF9F H(十六进制) -97 温度 -9.7℃湿度计算湿度1E6 H (十六进制) 486 湿度 48.6%RH查阅相关手册发现其波特率可设置成4800bit/s9600bit/s2400bit/s,本次我们采用4800bit/s且UART的数据帧结构如下所示下图是关于土壤传感器所用的UART1外设的初始化配置此外我们还需通过单片机的UART6外设将土壤传感器的数据通过USB转串口模块发送到串口助手上这样我们就可以实时监测到数据具体的初始化配置如下核心代码实现#include main.h #include usart.h #include gpio.h #include stdio.h #include mbcrc.h #define ADDRESS 0x01 //定义土壤传感器的的地址 #define FUNC_CODE 0X03//定义功能码 //定义问询帧 uint8_t send[8] {ADDRESS,FUNC_CODE,0x00,0x00,0x00,0x02,0x00,0x00}; //定义应答帧 uint8_t recv[9] {0}; short crc,temp;//定义返回的crc校验返回的变量以及中间变量 float humi,tem;//定义接收温度湿度的变量 //重定向 int _write(int file, char *ptr, int len) { HAL_UART_Transmit(huart6, (uint8_t*)ptr, len, HAL_MAX_DELAY); return len; // 返回发送的字节数 } int main(void) { HAL_Init();//HAL固件库的初始化 SystemClock_Config();//系统时钟的初始化 MX_GPIO_Init();//GPIO的初始化 MX_USART1_UART_Init();//UART1的初始化 MX_USART6_UART_Init();//UART6的初始化 while (1) { //1.构建问询数据帧 crc usMBCRC16(send, 6);//获取问询数据帧的校验码 send[6] crc0xff;//crc的低8位 send[7] (crc8)0xff;//crc的高8位 //2.发送问询帧 HAL_UART_Transmit(huart1, send, 8, 100); //3.判断是否是0x01地址的从设备返回的数据 HAL_UART_Receive(huart1, recv[0], 1, HAL_MAX_DELAY); if(recv[0] ! 0x01) { continue; }//重新接收 //4.接收剩余应答数据帧 HAL_UART_Receive(huart1, recv[1], 8, HAL_MAX_DELAY); crc 0; crc usMBCRC16(recv, 7); if(crc ! ((recv[8]8)|recv[7])) { continue; } //5.处理数据 //湿度值 temp (recv[3]8)|recv[4]; humi (float)temp/10; //温度值 temp 0; temp (recv[5]8)|recv[6]; tem (float)temp/10; printf(temp: %.2f,humi:%.2f\r\n,tem,humi); HAL_Delay(1000); } }#include mbcrc.h static const UCHAR aucCRCHi[] { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 }; static const UCHAR aucCRCLo[] { 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 }; //PUCFrame校验数组的首地址uslen:代表校验数组的长度 USHORT usMBCRC16( UCHAR * pucFrame, USHORT usLen ) { UCHAR ucCRCHi 0xFF; UCHAR ucCRCLo 0xFF; int iIndex; while( usLen-- ) { iIndex ucCRCLo ^ *( pucFrame ); ucCRCLo ( UCHAR )( ucCRCHi ^ aucCRCHi[iIndex] ); ucCRCHi aucCRCLo[iIndex]; } return ( USHORT )( ucCRCHi 8 | ucCRCLo ); }#ifndef _MB_CRC_H #define _MB_CRC_H typedef unsigned short USHORT; typedef unsigned char UCHAR; USHORT usMBCRC16( UCHAR * pucFrame, USHORT usLen ); #endif调试与验证程序编写完毕后将数据烧录到MCU中就要验收我们的成果了下面我们将对我们所写的程序进行调试与验证。物理层时序验证为了能够更加直观分析出数据的发送与接收我通过逻辑分析仪抓取了通信时的数字波形我们来分析下吧我们发现主机先按照Modbus-RTU格式将数据发送给从机之后过了大概10余ms的时间土壤温湿度传感器从机将数据也是按照Modbus-RTU的数据帧格式发送给主机然后主机又开始发送一次问询帧循环往复。应用层数据解析验证我们对该数据帧进行分析发现湿度为0%RH温度约为23.9℃通过串口我们发现获取的数据与数据帧相同。此时传感器处于干燥空气中湿度为0符合物理常识。至此软件解析逻辑与硬件收发链路全部验证通过。调试踩坑记录在初次上电后通过串口打印调试我发现串口并没有将数据实时发送到电脑上并且我利用逻辑分析仪抓取波形发现并没有捕捉到数据帧的波形。内心一度怀疑传感器是不是买到了坏件。冷静下来后没有急着改代码而是先用万用表排除了供电和虚焊问题最后回头翻看传感器数据手册才发现自己初始化USART时将UART的波特率设置成了115200bit/s传感器只需4800bit/s。修改UART波特率之后重新烧录波形瞬间跳了出来不得不说调Modbus通信时逻辑分析仪比串口助手靠谱一万倍。总结其实RS-485和RS-232都是依托于UART进行通信的他们都属于是物理层的电气标准。通过本次STM32驱动土壤温湿度传感器的项目实践我们成功实现了基于RS-485总线和Modbus-RTU协议的工业级传感器数据采集。后续将持续更新I2C,SPI,CAN总线的实战大家敬请期待

相关新闻

Unity低多边形植物包:性能优化与场景构建指南

Unity低多边形植物包:性能优化与场景构建指南

1. Unity低多边形植物包:轻量高效的场景构建利器低多边形(Low Poly)风格在游戏开发领域已经流行多年,这种用较少多边形构建的简约美学不仅视觉辨识度高,对性能也极为友好。最近在完成一个移动端项目时,我系…

2026/10/16 9:46:10 阅读更多 →
递归的隐藏代价:空间复杂度深度解析与时空权衡

递归的隐藏代价:空间复杂度深度解析与时空权衡

被低估的空间复杂度与递归的真实代价📌 核心要点 空间复杂度衡量的是算法运行所需的额外存储空间(不包括输入数据本身),同样用大 O 记法表示。"原地工作"意味着 S(n) O(1)——算法所需的额外空间是固定常量&#xff0c…

2026/10/17 4:45:44 阅读更多 →
vue基础(第四章 Pinia)

vue基础(第四章 Pinia)

1:Pinia 西班牙语:菠萝1.1:Pinia是什么?Pinia 是 Vue 官方新一代状态统一管理库,当数据需要在多个不相关的组件间共享的时候,需要使用Pinia,类似 Redis 集中缓存。专门为vue2和vue3设计,是Vuex 的替代方案。…

2026/10/17 4:32:41 阅读更多 →

最新新闻

BEN2-ONNX推理管线实战:基于BiRefNet的高质量背景移除

BEN2-ONNX推理管线实战:基于BiRefNet的高质量背景移除

最近在整理电商素材库的时候,我频繁遇到一个老问题:抠背景。钢笔勾路径、通道抠发丝、在线工具一张张传,碰到头发丝、玻璃杯、半透明纱裙,最后的效果总是差那么一口气。后来我把本地模型部署工具链重新翻了一遍,在一个…

2026/10/17 4:46:14 阅读更多 →
弹性伸缩实战:从伸缩组配置到负载均衡联动的避坑指南

弹性伸缩实战:从伸缩组配置到负载均衡联动的避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 4:46:14 阅读更多 →
MP2642GR-Z与STM32F401RB双串锂电池主动均衡实战

MP2642GR-Z与STM32F401RB双串锂电池主动均衡实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 4:46:14 阅读更多 →
superpowers技能包实战:让AI编程助手告别失忆与乱改代码

superpowers技能包实战:让AI编程助手告别失忆与乱改代码

1. superpowers 是什么:先把它从“玄学”拉回工程想聊 superpowers,我先说个真实场景。我自己的主力工具是 AI 编程助手,这几年换了好几轮,从补全工具一路用到能自主执行命令的 CLI 助手,工具越来越强,但有…

2026/10/17 4:46:14 阅读更多 →
H3C OSPF配置实战:从Router ID规划到双区域部署与排障

H3C OSPF配置实战:从Router ID规划到双区域部署与排障

做网络维护这些年,我接过不少“路由学不全、业务偶发中断”的工单,十有八九跟动态路由没配利索有关系。这里的OSPF配置,尤其是华三/H3C设备上的OSPF配置,看似就几条network命令,实际牵扯到Router ID规划、区域设计、认…

2026/10/17 4:46:14 阅读更多 →
微服务全链路蓝绿发布实战:Nepxion Discovery 路由机制与避坑指南

微服务全链路蓝绿发布实战:Nepxion Discovery 路由机制与避坑指南

1. 蓝绿发布为什么在微服务架构下变得如此棘手单体应用时代的蓝绿发布,本质上就是运维在负载均衡器上切一下流量,把新版本集群挂上去、老版本集群摘下来,出问题再切回去。整个过程对业务代码几乎零侵入,因为所有逻辑都跑在一个进程…

2026/10/17 4:45:14 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →