news 2026/10/22 12:20:44

本地+远程双路温度采集:基于PIC32与单总线传感器的嵌入式温控方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
本地+远程双路温度采集:基于PIC32与单总线传感器的嵌入式温控方案

做嵌入式温控这么多年,我踩过的最大一个坑,就是盲目相信传感器读数。去年某HVAC项目现场调试,控制柜显示回风温度26.8℃,手摸出风口却明显偏凉,用热电偶一测实际只有24.9℃。差了近两度,整个PID都在瞎忙活。查到最后,问题出在温度采集点选得不对——把唯一的传感器贴在了控制器主板上,测到的是板子自身发热和机柜内的局部温度,根本代表不了远端风道的真实工况。

那次之后,我重新梳理了一套方案:用PJ85718DM这种单总线数字温度传感器,搭配PIC32MX470F512L单片机,把"本地温度"和"远程温度"分开采集、分开处理。本地传感器放控制器附近,负责监测控制柜内的环境;远程传感器沿总线延伸到末端风道、回风口或房间远端,负责测真正需要控温的位置。这样一套系统,既能用在同一块板上的嵌入式设备里,也能直接部署在HVAC的现场。

这篇就把我在这个项目里从硬件选型到1-Wire时序实现、从软件调度到现场抗干扰的完整过程写出来。做HVAC控制、嵌入式温控或者机房环境监控的朋友,可以直接照着抄作业。

1. 为什么非要"本地+远程"两个维度的温度数据

1.1 一次温差事故:单点采集的局限性

先说回开头那个案例。那套HVAC控制器的控制逻辑是标准的"回风温度反馈",但安装时施工方图省事,把温控器的感温探头直接捆扎在控制柜内。控制柜里有开关电源、继电器、驱动器,整体温度比车间平均气温高两到三度,于是系统始终认为"现场偏热",一直让压缩机满负荷跑,等我把探头移到回风管道里,压缩机才恢复正常启停。

这说明一个基本事实:单点温度数据在HVAC这种温度场分布不均匀的环境里,要么代表设备本身,要么代表某个局部区域,很难代表整个被控空间的真实状态。做本地与远程双路采集,本质上是把"设备温度"和"环境温度"分开,让控制决策有更完整的输入。

1.2 传感器选型:为什么是PJ85718DM,而不是NTC或者PT100

传统方案用NTC热敏电阻加ADC采样,成本确实低,但NTC的短板很明显:非线性严重、需要逐点标定、信号是模拟量容易受线缆压降干扰。PT100精度高,但需要配套调理电路和仪表放大器,成本和复杂度都上去了。

PJ85718DM这类单总线数字温度传感器的出现,正好卡在这个中间位置。它把测温、AD转换、校准、串行通信全部集成在一个TO-92或者SOIC封装里,MCU只需要一根GPIO就能挂载多颗传感器。12位分辨率下最小刻度0.0625℃,典型精度能做到±0.5℃,对HVAC这种对绝对精度要求并不苛刻的场景来说完全够用。

另一个关键特性是它内置唯一的64位序列号。这意味着总线上可以并联很多颗传感器,每个传感器的身份是独一无二的,系统上电后可以扫描总线、给每颗传感器建立档案,定位哪一个传感器装在哪个物理位置。这对远程多点监测来说几乎是量身定做的。

1.3 主控选型:PIC32MX470F512L的资源现状

PIC32MX470F512L是100引脚的MIPS架构MCU,512KB Flash、128KB RAM,主频最高80MHz。当初选它不是因为性能有多极致,而是因为接口和引脚数量非常富余——一路1-Wire总线只占一个GPIO,剩下的UART、SPI、I2C、定时器、DMA可以同时伺候人机交互屏、RS485通信、PWM风机输出和外扩EEPROM。

80MHz的CPU主频对1-Wire协议来说有个额外好处:微秒级时序的精度更容易保证。单总线协议很多地方要求微秒级别的信号宽度,主频太低的话,几条指令就消耗掉几十微秒,时序窗口会变得非常紧张。PIC32MX470F512L的处理速度足以在中断里从容完成位操作和时序控制。

2. 硬件搭建:传感器总线、引脚规划与外围防护

2.1 最小硬件连接:一根数据线加一个上拉电阻

硬件连接是全部项目里最简单也最容易被轻视的部分。我在项目里用RB14作为数据线,所有PJ85718DM的DQ引脚并联到同一根线上,再通过一个4.7kΩ电阻上拉到3.3V。

RB14 ──┬── 4.7kΩ ── 3.3V │ ├── DQ(PJ85718DM_1) ├── DQ(PJ85718DM_2) └── DQ(PJ85718DM_3)

这里有两个细节值得说。第一,PIC32MX470F512L的GPIO虽然可以配置成开漏输出,但1-Wire总线通常建议使用真正的开漏结构或者复用推挽模式。我在初始化代码里把RB14配成开漏并用外部上拉,这样主机拉低时是主动驱动低电平,释放时靠上拉电阻回到高电平,逻辑上完全兼容传感器的线或机制。

第二,PJ85718DM的数据线与地线之间要尽量减少寄生电容。很多人在面包板上测试没问题,一到现场几十米线缆就出问题,九成是寄生电容导致波形边沿塌陷。

2.2 供电模式:寄生供电的坑和外部供电的方案

PJ85718DM这类传感器支持寄生供电——两根线(DQ和GND)就能工作,数据线在高电平期间给内部电容充电。这个特性在PCB上省一根线很诱人,但在HVAC现场我强烈建议不要用。

原因有两个。一是远程传感器线缆长度超过几米后,线路电阻和寄生电容会显著拉长充电时间,高电平窗口内充不满电,传感器在温度转换阶段(典型需要几百毫秒的大电流工作)可能出现欠压复位,转换结果直接变成0x8500这种错值。二是现场有继电器、接触器、变频器,寄生供电方式下传感器电源完全跟着数据线波动,抗干扰余量太小。

所以项目里所有远程传感器全部采用外部供电:VDD接3.3V或者5V,GND与主控共地,DQ只负责通信。多颗传感器可以共用一组电源,但每颗传感器的VDD和GND之间就近放一个0.1μF去耦电容,长线远端再并一个10μF电解电容抗电源跌落。

2.3 长线网络的外围保护:TVS与RC滤波

HVAC现场不是干净实验室。我这条总线从控制柜走到末端风道,会经过变频器、接触器、电动阀这些强干扰源,所以总线入口处加了三级保护。

首先是100Ω串联电阻,限制异常浪涌电流。然后是TVS管对地钳位,把感应雷击或者电机启停造成的尖峰电压压到安全范围。最后是上拉电阻的位置——上拉必须放在主机侧,靠近MCU引脚,而不是放在远端传感器侧。这是因为远端如果先拉到高电平,长线等效电容会被提前充到干扰电平,主机再触发复位时序时,线缆上残余的高电平会影响时序判断。

对于屏蔽要求更高的场合,数据线用带屏蔽层的双绞线,屏蔽层在主机侧单端接地。切记不要在传感器侧再接一次地,否则会形成地环路,反而把共模干扰变成差模干扰灌进总线。

3. 1-Wire协议时序:最容易翻车的地方

3.1 从复位脉冲开始理解单总线的通信节奏

PJ85718DM的通信协议是严格的时隙制,所有操作都由主机发起,传感器从不主动说话。一次完整的温度读取流程分三步:复位、发送ROM命令、发送功能命令并读取数据。

第一步复位是整个通信的握手。主机把总线拉低480μs以上然后释放,上拉电阻会把总线拉回高电平,这时传感器检测到上升沿,会等待一段时间后主动把总线拉低60~240μs,产生一个"存在脉冲"。主机在释放总线后的60~240μs窗口内检测这个低电平,就能确认总线上的传感器在线。

这个低电平检测窗口是整个协议里最容易出问题的地方。我用一个示波器实测过,不同批次的传感器响应时间有差异,老批次的存在脉冲来得更早、持续更短,如果主机的采样窗口设置过窄,会误判为总线无设备。

3.2 写时隙和读时隙的时序参数对照

单总线的读写是以"时隙"为单位进行的。每个时隙至少拉低1μs,然后根据要写的数据,决定何时释放总线:

写1时隙:拉低总线 → 延时约6~15μs → 释放总线 → 保持约60μs 写0时隙:拉低总线 → 保持约60μs → 释放总线 → 保持约2μs 读时隙: 拉低总线 → 延时约1μs → 释放总线 → 在15μs内采样电平

关键点在于,写1时隙和读时隙在波形上看起来很像,都是"拉低一小会儿然后释放",但主机释放后的行为完全不同:写1时隙释放后主机不再动总线,总线被上拉变高,传感器读到1;读时隙释放后传感器会主动把总线拉低来表示0,所以主机必须在一个很窄的窗口内完成采样。

操作主机拉低时间释放后状态采样/写入时机
写11~15μs交给上拉电阻传感器在15~60μs窗口内检测高电平
写060~120μs保持低电平传感器检测整个时隙的电平
读01~15μs传感器拉低总线主机在释放后15μs内读电平
读11~15μs保持高电平主机在释放后15μs内读电平

这里最典型的失误是把读时隙的采样时间放在释放后的中间位置。正确的做法是卡在释放后15μs内尽早采样,越靠近传感器刚刚决定驱动总线的时间越好。我在代码里把采样点放到释放后约8μs,实测误码率最低。

3.3 PIC32MX470F512L上的GPIO开漏配置

PIC32系列GPIO的四组寄存器分工明确:TRIS控制方向、LAT控制输出电平、PORT读取引脚状态、ODC控制开漏。RB14作为1-Wire总线,初始化代码如下:

// RB14 -> 1-Wire Data void OW_GPIO_Init(void) { ANSELBbits.ANSELB14 = 0; // 关闭模拟功能 TRISBbits.TRISB14 = 0; // 初始设为输出 LATBbits.LATB14 = 1; // 输出高电平 ODCBbits.ODCB14 = 1; // 配置为开漏输出 }

开漏模式是1-Wire总线的关键。开漏输出意味着单片机只能主动拉低或者释放(高阻),不能主动驱动高电平,这样总线上任何一方拉低时,其他设备都能感知到电平变化。如果配置成推挽输出,主机想释放总线时会把总线强推到高电平,传感器想拉低总线就会发生电平冲突,轻则通信失败,重则损伤引脚。

XC32编译器里还提供了一个便捷的写电平接口,但底层还是要理解LAT和PORT的区别。写方向用LAT,读方向用PORT,这两个搞混了就会出现在线调试死活读不到电平的问题。

3.4 微秒级延时:__delay_us与临界区保护

1-Wire时序对延时的精度要求不苛刻——允许的误差范围通常在±10μs以内,不需要每秒百万次的定时器轮询。但怕的是中断打断,因为一旦在时隙中间被串口中断或定时器中断插一脚,时序窗口就会被拉长,传感器直接丢位。

我的做法是:所有1-Wire底层时序操作在关中断状态下执行,时隙之间再开中断。用XC32的__builtin_disable_interrupts()和__builtin_enable_interrupts()包住关键段,延时用__delay_us()宏:

uint8_t OW_Reset(void) { uint8_t presence; __builtin_disable_interrupts(); OW_LOW(); // 拉低总线 __delay_us(500); // 复位脉冲,>480μs OW_RELEASE(); // 释放总线 __delay_us(30); // 等待传感器响应窗口开始 presence = OW_READ_PIN(); // 读取存在脉冲(低有效) __builtin_enable_interrupts(); __delay_us(480); // 复位后延时,给传感器准备时间 return (presence == 0) ? 1 : 0; // 返回1表示检测到设备 }

有一点需要说明:__delay_us宏依赖系统初始化时配置的主频数值,如果后面改了时钟配置但没同步更新宏参数,所有时序会成比例漂移。我在板级初始化里用SYSTEMConfigPerformance(80000000)锁定主频,再配合这个宏就稳定了。

3.5 写时隙与读时隙的实现

void OW_WriteBit(uint8_t bit) { __builtin_disable_interrupts(); if (bit) { OW_LOW(); __delay_us(8); OW_RELEASE(); __delay_us(70); } else { OW_LOW(); __delay_us(70); OW_RELEASE(); __delay_us(10); } __builtin_enable_interrupts(); } uint8_t OW_ReadBit(void) { uint8_t bit; __builtin_disable_interrupts(); OW_LOW(); __delay_us(2); OW_RELEASE(); __delay_us(6); bit = OW_READ_PIN(); __delay_us(60); __builtin_enable_interrupts(); return bit; }

写时隙的要点是,写1和写0的区别不在"持续低电平的总时长",而在于释放的时间点。传感器在总线从低到高的上升沿之后的15~60μs窗口内采样,所以写1时必须在窗口前释放,写0时则要让总线在窗口内保持低电平。

整个字节传输就是把8个位从低位到高位依次发送,先发LSB。发送完一字节后总线回到高电平空闲状态。我建议把底层读写做成OW_WriteByte和OW_ReadByte两个函数,上层的命令解析完全不用关心时序细节,可读性好得多。

3.6 ROM搜索:总线上挂着的每一颗传感器都要有身份

PJ85718DM的64位序列号由8个字节组成,其中第1字节是家族代码,最后1字节是CRC校验。主机可以通过发送搜索ROM命令(0xF0)来枚举总线上所有传感器,读出每一颗的完整64位序列号。

枚举的逻辑本质上是一个二叉树遍历。总线上所有传感器同时响应,每一位上,每个传感器会先输出它这一位的数据,再输出这个数据的反码。如果总线上同时有0和1两种状态,传感器会拉低总线造成冲突。主机根据冲突位置判断分支,向下搜索。

实际项目中我要求每颗传感器在装配时记录安装位置,把64位序列号和房间/风道编号写进配置表。这样每次上电扫描总线,系统自动比对序列号清单,哪个传感器掉线了、哪个位置被误接成别的传感器,固件一跑就知道,不用拿万用表满现场捅线。

3.7 用CRC挡住线上噪声

长线上的干扰很多时候不表现为整包数据错误,而是随机翻转某一个比特。单总线的帧结构里,每个ROM字节和每个暂存器字节末尾都有CRC校验字节,读出来之后必须先做CRC校验再使用。

PIC32的CPU速度允许直接逐位计算CRC,查表法更快但没必要。核心验证代码如下:

uint8_t OW_CRC8(uint8_t *data, uint8_t len) { uint8_t crc = 0; while (len--) { uint8_t byte = *data++; for (int i = 0; i < 8; i++) { uint8_t mix = (crc ^ byte) & 0x01; crc >>= 1; if (mix) crc ^= 0x8C; byte >>= 1; } } return crc; }

多项式0x8C对应X8+X5+X4+1,这是这一类传感器通用的CRC算法。注意它是以LSB-first的顺序计算的,和Modbus的CRC习惯不同,别混用。我最初就是拿Modbus标准CRC函数直接算,结果校验永远失败,排查了一整天才发现方向反了。

4. 本地与远程温度采集的软件架构

4.1 温度转换与读取的时序调度

PJ85718DM在一次温度转换完成后,结果存放在暂存器的第0、1字节,分别是温度低字节和温度高字节。读取流程是:复位→发送跳过ROM命令(0xCC)或者匹配ROM命令(0x55)→发送读暂存器命令(0xBE)→连续读出9个字节。

关键在于转换命令(0x44)发出后,传感器需要一段时间完成AD转换。12位分辨率下典型转换时间约750ms。程序里如果发完转换命令就立刻去读,读到的是上次转换的旧值,或者读到还在转换中的半个结果。

更优的调度策略是"并发等待":先向所有传感器发出转换命令,让它们同时开始转换,然后MCU去处理显示、通信、按键等其他任务,等到750ms之后再回来逐颗读取。这样N颗传感器共用一个等待周期,而不是N倍等待时间。

void Temp_StartAllConversion(void) { OW_Reset(); OW_WriteByte(0xCC); // 跳过ROM,广播给全部传感器 OW_WriteByte(0x44); // 启动温度转换 } void Temp_ReadAll(void) { for (int i = 0; i < sensor_count; i++) { OW_Reset(); OW_WriteByte(0x55); // 匹配ROM for (int j = 0; j < 8; j++) { OW_WriteByte(sensor_rom[i].rom[j]); } OW_WriteByte(0xBE); // 读暂存器 uint8_t data[9]; for (int j = 0; j < 9; j++) { data[j] = OW_ReadByte(); } // CRC校验通过后解析温度 if (OW_CRC8(data, 8) == data[8]) { sensor_raw[i] = (data[1] << 8) | data[0]; } } }

这里有一个容易被忽略的细节:跳过ROM命令(0xCC)只能在总线上只有一颗传感器或者所有传感器一起做相同操作时使用。如果总线上挂了多颗且后续操作需要区分个体,必须先做匹配ROM。我见过有人在多传感器系统里靠跳过ROM广播温度转换命令,结果每次读取的所有传感器都返回同一份数据,原因就在读暂存器时没有做地址匹配。

4.2 从原始数据到实际温度:符号扩展

PJ85718DM的温度数据格式是12位有符号定点数,LSB代表0.0625℃。读取出来的16位原始值里,低4位是小数部分,高5位是符号位,中间是整数部分。

以0x0550为例,二进制0000 0101 0101 0000,去掉后4位和符号位,整数部分是85,小数部是0×0.0625=0.0,所以温度是85℃。负温度时,比如-0.5℃,原始值是0xFFF8,需要按12位有符号数先符号扩展到16位再做浮点换算。

代码实现:

float Temp_ConvertToCelsius(int16_t raw) { if (raw & 0x0800) { // 检查第12位符号位 raw |= 0xF000; // 符号扩展到16位 } return (float)raw * 0.0625f; }

HVAC场景里我在这一步做了个额外的平滑处理:内存里存最近5次换算后的温度值,取中值滤波后再输出。这样做的好处是抗单点脉冲干扰,比如总线被电磁噪声打出一个异常尖峰时,中值滤波能让这个尖峰在输出序列里只占一个位置,不会引起PID的大幅震荡。

4.3 HVAC联动逻辑:用双路温度做更聪明的控制

当本地和远程温度都准备好之后,控制逻辑的设计才是这批工作区别于简单读温度的地方。

我的项目里有两种工作模式。第一种是"温差跟踪模式":远程传感器装在风道末端,本地传感器装在控制柜内,系统计算两者的温差,当温差超过设定阈值时,判定末端风道存在冷量衰减或风道泄漏,触发报警而不是直接拉高频。第二种是"分时调度模式":远程传感器负责主导PID调节,本地传感器负责设备过热保护,主控检测到本地温度超过70℃时立即降频,防止控制柜内元件老化。

温度报警阈值用PJ85718DM内置的TH和TL寄存器实现了一部分。这两个寄存器存的是带符号的整数报警值,精度是1℃。我的固件在每次上电初始化时,直接把阈值写入各传感器内部EEPROM,这样即使主控掉电重启、在传感器扫描完成之前,现场温度的硬件级报警依然有效。

需要留意的是,TH/TL报警要配合报警搜索命令(0xEC)使用。主机发出报警搜索后,只有温度超限的传感器才会响应。这套机制可以用在主控轮询的空闲期,一旦有超限设备主动上报,主控立刻切换工作模式,反应速度比软件轮询快得多。

4.4 传感器掉线的特征值识别

现场运行最大的意外是传感器断线。总线断线时,读取存在脉冲失败,所有命令无响应;但如果只有某一颗断线时,如果代码里不做地址校验,读出来的是全部0xFF。

更隐蔽的问题是传感器在转换中途掉电重启,暂存器数据会变成0x8500。这个特征值我特别提一下:0x8500对应的摄氏温度是负数,而且数值上等于"设备未正确初始化"的默认上电值。在实际代码里,我先把每次读取的原始值与0x8500做比对,再检查符号位,防止把非法数据送进滤波器和控制链路。

另外,上电后第一次扫描总线时必须做完整的ROM枚举,而不是直接读缓存。我试过系统运行几个月后,原来在第5个位置的传感器因为接触不良被重新识别,ROM顺序发生变化,如果固件按固定序号解析设备,就会把5号位置的读数当成3号位置来用,HVAC的控温区域直接错乱。每次扫描后重新校验一次序列号清单,这个开销换来的稳定性非常值得。

5. 现场实测:波形、干扰与几个真实翻车案例

5.1 变频器现场的总线波形陷阱

在实验室里用短杜邦线连接传感器,1-Wire总线波形干净漂亮。到了车间现场,数据线靠近变频器出线侧,示波器上能看到明显的振铃叠加在空闲高电平上。最严重的一次,总线明明处于释放状态,示波器却显示低电平毛刺——这是变频器输出PWM的dv/dt通过空间耦合到数据线上,把总线电平冲下来了。

处理办法从三方面同时下手:一是把总线远离动力线,原方案的线槽里数据线与380V动力线挨着走,重排后保持至少20cm间距;二是总线入口的100Ω电阻和TVS不能省;三是把上拉电阻从4.7kΩ降到2.2kΩ,增强总线抗低电平干扰的能力。

改动后波形在高电平方仍然有轻微振铃,但不再跌破VIH阈值,通信误码率从千分之一降到完全消失。

5.2 上拉电阻和线缆长度的匹配

总线长度对上拉电阻的要求是反直觉的:线越长,等效电容越大,为了在规定的时隙内把总线充到高电平,上拉电阻反而要更小。

我在项目里实测的数据是:线缆长度5米以内用4.7kΩ没问题;长度到30米,4.7kΩ下上升沿已经明显变缓,读时隙里的采样点偶尔读到低电平,换2.2kΩ后恢复正常;再长的布线我试过1kΩ,但此时静态功耗会增加,而且可能会超出传感器的拉低能力。1-Wire规范上最大总线上电容是几百皮法,超过这个量级就必须拆分总线或者用更强驱动的中继方案。

判断上拉电阻是否合适的最快方法不是看眼图,而是连续读取500次温度,统计CRC错误率。错误率超过1%就说明时序余量不足,要么换电阻,要么放慢采样点。

5.3 传感器自热:风道里的小火炉

这是最容易忽略的一个误差源。传感器自身工作时会有功耗,如果安装位置空气不流通,热耗散不出去,读数会比真实环境温度偏高。

我在空调风道里做过一次对比测试:传感器贴在风道内壁贴近保温棉的位置,和悬空在气流中心的位置,两点温差有1.2℃。贴在管壁上的那颗明显受管壁温度影响,悬空的那颗更接近真实气温。

所以远程传感器的安装方式,我总结三条经验:一是传感器探头要尽量放在被测气流的中心区域,不要贴着管壁;二是传感器本体不要紧靠大功率发热元件;三是如果传感器封装是TO-92,安装时引脚朝下、外壳迎风,这样散热条件最差也能均匀受热。

5.4 我在这套系统里踩过的五个具体代码错误

把GPIO配成推挽而不是开漏。症状是通信时好时坏,用示波器看波形,释放状态高电平台阶上有明显的毛刺。改TRIS和ODC后消失。

用寄存器延时表来写微秒延时,却忘了在系统时钟切换后更新延时倍率。症状是所有传感器读出来的温度在所有数值上整体偏移。后来干脆统一改用__delay_us并锁定主频配置。

发送完温度转换命令后立刻读暂存器,读到的全是上电默认值而不是当前值。加上750ms等待后正常。

在读取一段温度数据的9个字节过程中打开了中断,UART中断把读时隙打断,导致偶发CRC错误。把底层位时序全部包在临界区后问题消失。

把跳过ROM当成万能命令,在多传感器系统里不做ROM匹配就发读暂存器命令,读回来N份相同数据。改成按序列号匹配后正确。

这些错误在单传感器开发板上根本不会暴露,到了系统整合和现场部署阶段才一个个显现。写出来算是给做类似项目的朋友提个醒,尤其是中断优先级和时序保护之间的关系,几乎每个1-Wire项目都会在这里栽一次。

最后再分享一个我自己常用的调试手段:在PIC32上做一个隐形调试通道,用一个空闲的UART把每次1-Wire通信的CRC错误计数、总线扫描到的ROM数量和每颗传感器的原始值实时打出来。现场出问题时,不用连调试器,直接看串口日志就能定位是干扰导致CRC错误、某颗传感器掉线还是时序配置漂移。这个通道在正式交付的固件里可以留着,只读不写,对HVAC这类要长期无人值守运行的场景尤其有用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 12:20:44

PJ85718DM+R7FA2L1AB2DFP温测方案:高精度低功耗工业温度传感设计

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

作者头像 李华
网站建设 2026/10/22 12:18:34

EEG情绪检测实战:DEAP与SEED-IV数据库的SVM分类路线

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

作者头像 李华
网站建设 2026/10/22 12:18:33

工业级热电偶温度采集系统设计:PJ85718DM+MK64FN1M0VDC12实战指南

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

作者头像 李华
网站建设 2026/10/22 12:18:32

数据库系统概论答案:关系模型、SQL与范式设计核心解析

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

作者头像 李华
网站建设 2026/10/22 12:15:53

PIC18F87J50与PJ85718DM双通道温度监测系统设计实战

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

作者头像 李华
网站建设 2026/10/22 12:15:49

UML关联多重度与交互图解析:顺序图、协作图的应用与避坑

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

作者头像 李华