news 2026/10/11 1:15:27

基于PJ85718DM与PIC18F47Q10的嵌入式远程温度监测方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于PJ85718DM与PIC18F47Q10的嵌入式远程温度监测方案

1. 项目缘起与整体设计思路

嵌入式温度监测这个方向,看起来简单,实际上是个"深水区"。我接触过不少做 HVAC(暖通空调)控制器的团队,十个里面有八个在温度采样这一环踩过坑——要么是本地测温精度不够导致压缩机频繁启停,要么是远程温度数据传不回来,现场调试时抓瞎。这次要聊的这套方案,核心就是用PJ85718DM这颗 I2C 接口的远程温度传感器,配合PIC18F47Q10这颗带丰富外设的 8 位 MCU,搭一套能同时覆盖本地板载测温和远程探头测温的完整链路。

先说清楚这套东西是干什么的、适合谁看。PJ85718DM是一颗支持 I2C 总线的远程二极管温度传感器,它的特点是可以外接一个或多个分立三极管(或者 MCU 内部/外部的二极管结)作为感温元件,把探头放到离主控板很远的地方去测温,比如空调风管里、冷库的蒸发器旁边、机柜的进风口。而PIC18F47Q10是 Microchip 新一代的 8 位 MCU,带 12 位 ADC、多路 UART/SPI/I2C、还有充足的内存,非常适合做这种"本地采集 + 远程采集 + 通信上报"的小型控制器。两者搭配,正好覆盖了 HVAC 和工业嵌入式场景里最常见的需求:本地温度看板子周围环境,远程温度看关键点位,数据通过串口或总线往上送。

这套方案适合谁?如果你正在做空调控制器、新风系统、机房温控、冷链监控、或者任何需要"一个主机 + 多个远端测温点"的嵌入式项目,那这套组合基本可以直接抄作业。哪怕你是刚上手 PIC 系列的新手,只要跟着把 I2C 时序、寄存器配置、温度换算这几块啃下来,也能跑通。我下面会把选型逻辑、硬件连接、寄存器操作、温度换算、通信上报、以及实际调试中那些"文档里不写但一定会遇到"的坑,全部摊开讲。

整体设计上,我采用的是"双通道测温"架构:本地通道用 PIC18F47Q10 自带的 ADC 去采一个板载热敏电阻或者模拟温度传感器,成本低、响应快,用来监测主控板自身的工作环境温度;远程通道用 PJ85718DM 通过 I2C 挂载,外接远程二极管探头,负责采集那些离主板几米甚至十几米远的关键点位温度。两条通道的数据在 MCU 里做融合处理,再通过 UART 上报给上位机或者通过 I2C 从机模式被主控轮询。这样设计的好处是:本地测温不占用 I2C 带宽,远程测温精度高、抗干扰强,两者互不干扰,任何一路出问题都能被另一路交叉验证。

为什么不用 MCU 内部温度传感器直接测?因为 PIC18F47Q10 的内部温度传感器精度大概在 ±3℃ 到 ±5℃ 这个量级,而且受自身发热影响很大,做环境监测勉强够用,做 HVAC 控制就完全不够看了。HVAC 场景里,温度误差超过 1℃ 就可能让用户明显感觉到"空调不听话"。所以本地测温我宁愿外挂一个精度 ±0.5℃ 的模拟传感器走 ADC,也不直接用内部通道。远程测温就更不用说了,必须用专用的远程二极管传感器,因为二极管结的温漂特性经过校准后能做到 ±1℃ 以内,而且探头可以做得非常小,塞进风管或者贴到换热器表面都很方便。

2. 核心器件解析与选型考量

2.1 PJ85718DM 到底强在哪

PJ85718DM 这颗芯片,我第一次用的时候是被它的"远程二极管"架构吸引的。它不像常见的数字温度传感器那样把感温元件集成在封装里,而是通过两个引脚(D+ 和 D-)去驱动一个外部的三极管或者二极管,利用二极管正向压降随温度变化的特性来测温。这个原理其实很老,但 PJ85718DM 把它做得很精细:内部有自动校准、有串联电阻补偿、还有可编程的测温分辨率和报警阈值。

它的关键参数我列一下,方便你选型时对照:

参数项典型值说明
测温范围-40℃ ~ +125℃覆盖绝大多数 HVAC 和工业场景
远程测温精度±1℃(+60℃ ~ +100℃)经过校准后的典型值
本地测温精度±2℃芯片自身温度,可做冷端补偿
接口I2C,最高 400kHz标准模式/快速模式都支持
供电3.0V ~ 5.5V和 PIC18F47Q10 的 3.3V 系统兼容
分辨率可编程,最高 0.0625℃11 位有效数据
封装小型贴片节省板面空间

我选它的核心理由有三个:第一,远程探头可以做得非常小,一个 SOT-23 封装的三极管就能当探头,塞进狭窄的风道毫无压力;第二,抗干扰能力强,因为 D+ / D- 走的是差分信号,配合芯片内部的滤波,几米长的线缆也能稳定读数;第三,I2C 地址可配置,一条总线上可以挂多颗,方便扩展多路远程测温。

2.2 PIC18F47Q10 的角色定位

PIC18F47Q10 在这套方案里是"大脑"。它要干三件事:一是通过 I2C 去读 PJ85718DM 的远程温度;二是通过 ADC 去采本地模拟温度传感器;三是把两路数据打包,通过 UART 或者 I2C 从机模式上报。

这颗 MCU 我比较欣赏的地方是它的外设集成度。它有两个独立的 I2C 模块(MSSP1 和 MSSP2),这意味着我可以把 PJ85718DM 挂在 MSSP1 上,把上位机通信挂在 MSSP2 上,互不抢总线。ADC 是 12 位的,采热敏电阻分压完全够用。UART 也有多路,调试和上报可以分开。内存方面,128KB Flash、8KB RAM,跑这种温度监测任务绰绰有余,还能留出空间做数据滤波和报警逻辑。

还有一个细节:PIC18F47Q10 的 I/O 口支持 5V 容忍,而 PJ85718DM 是 3.3V 供电,所以电平匹配上不需要额外加转换芯片,直接连就行。这一点在布板的时候省了不少事。

2.3 为什么不用单芯片方案

有人可能会问:现在不是有很多 MCU 自带温度传感器吗,为什么还要外挂两颗芯片?这个问题我实际对比过。自带温度传感器的 MCU,测温点就在芯片内部,测的是芯片自己的温度,不是环境温度。芯片一跑起来自身发热,读数就偏高,而且响应很慢。HVAC 场景里,温度探头往往要放到离主板很远的地方,MCU 自带的传感器根本够不着。所以"MCU + 专用温度传感器"这个组合,在需要远程测温的场景里是绕不开的。PJ85718DM 负责"够得着、测得准",PIC18F47Q10 负责"算得快、传得稳",分工明确。

3. 硬件连接与关键电路设计

3.1 I2C 总线连接要点

PJ85718DM 和 PIC18F47Q10 之间的连接,核心就是 I2C 两根线:SDA 和 SCL。但这两根线怎么接,里面有不少讲究。

首先是上拉电阻。I2C 是开漏输出,必须加上拉电阻才能把电平拉高。阻值选多大?这取决于总线电容和通信速率。我一般用 4.7kΩ 作为起点,如果总线走线长、挂的设备多,电容大了,上升沿变缓,就得减小到 2.2kΩ 甚至 1.5kΩ。但阻值也不能太小,否则灌电流太大,器件扛不住。实测下来,3.3V 系统、400kHz 速率、总线电容 100pF 左右的情况下,4.7kΩ 是个很稳的选择。如果你把速率降到 100kHz,用 10kΩ 也没问题。

其次是走线。SDA 和 SCL 尽量并行走,远离高频开关信号(比如 PWM 驱动的风扇线)。如果实在避不开,中间加地线隔离。我见过一个案例,远程温度读数一直跳,最后查出来是 I2C 走线跟风扇 PWM 线捆在一起了,风扇一转,温度就抖。把线分开走,问题立刻消失。

第三是远程探头的连接。PJ85718DM 的 D+ 和 D- 到远程三极管之间的线,建议用双绞线,并且尽量远离电源线。如果距离超过 1 米,最好在 D+ 和 D- 之间并一个小电容(比如 100pF),滤掉高频干扰。但电容不能太大,否则会影响芯片的自动校准。

3.2 本地测温电路

本地测温我用的是一个 NTC 热敏电阻和一个精密电阻组成分压,接到 PIC18F47Q10 的 ADC 输入引脚。热敏电阻选 10kΩ B 值 3950 的常见型号,精密电阻用 10kΩ 1% 精度的。分压点电压送到 ADC,MCU 通过查表或者 Steinhart-Hart 公式反算出温度。

这里有个细节:ADC 参考电压。PIC18F47Q10 可以用 VDD 做参考,也可以用内部固定参考。如果用 VDD 做参考,VDD 的波动会直接影响测温精度。所以我在板子上加了一个 3.3V 的 LDO,并且 ADC 参考引脚旁边放了 0.1μF 和 10μF 的退耦电容。实测下来,这样处理之后,本地测温的稳定性可以做到 ±0.3℃ 以内。

3.3 供电与退耦

PJ85718DM 和 PIC18F47Q10 都是 3.3V 供电,可以共用一路 LDO。但要注意,PJ85718DM 的供电引脚旁边一定要放 0.1μF 的陶瓷电容,越近越好。这颗芯片内部有开关电容电路,供电噪声会影响测温精度。我在第一版板子上没注意这个,远程温度读数偶尔会跳 2℃,后来加了退耦电容,立刻就稳了。

另外,如果远程探头线很长,PJ85718DM 的 D+ / D- 引脚上可能会感应到干扰。除了前面说的双绞线和小电容,还可以在 D+ 和 D- 上各串一个 100Ω 的电阻,限制瞬态电流。这个电阻对测温精度影响很小,但对抗干扰帮助很大。

4. 固件实现:从寄存器到温度值

4.1 I2C 驱动层

PIC18F47Q10 的 I2C 外设用起来不算复杂,但初始化顺序要对。我一般按这个流程来:

// I2C 初始化(MSSP1,主模式,400kHz,3.3V) void I2C1_Init(void) { SSP1CON1 = 0x28; // SSPEN=1, I2C 主模式 SSP1CON2 = 0x00; SSP1ADD = 0x09; // 400kHz @ 16MHz Fosc SSP1STAT = 0x80; // slew rate 控制关闭 // 配置 SDA/SCL 引脚为输入 TRISCbits.TRISC3 = 1; // SCL TRISCbits.TRISC4 = 1; // SDA }

这里SSP1ADD的值怎么算?公式是SSP1ADD = (Fosc / (4 * Fscl)) - 1。假设系统时钟 16MHz,想要 400kHz,那就是(16M / (4 * 400k)) - 1 = 10 - 1 = 9。如果系统时钟不一样,这个值要重新算。我见过有人直接抄别人的代码,结果时钟不匹配,I2C 死活不通,查了半天才发现是这里的问题。

读写函数我封装成两个:

// 向 PJ85718DM 写一个字节 uint8_t PJ85718_Write(uint8_t reg, uint8_t data) { I2C1_Start(); if (I2C1_WriteByte(PJ85718_ADDR << 1)) return 1; // 地址+写 if (I2C1_WriteByte(reg)) return 2; // 寄存器地址 if (I2C1_WriteByte(data)) return 3; // 数据 I2C1_Stop(); return 0; } // 从 PJ85718DM 读一个字节 uint8_t PJ85718_Read(uint8_t reg, uint8_t *data) { I2C1_Start(); if (I2C1_WriteByte(PJ85718_ADDR << 1)) return 1; if (I2C1_WriteByte(reg)) return 2; I2C1_Start(); // 重复起始 if (I2C1_WriteByte((PJ85718_ADDR << 1) | 1)) return 3; *data = I2C1_ReadByte(0); // NACK I2C1_Stop(); return 0; }

注意那个重复起始条件,读寄存器时必须先写寄存器地址,再发重复起始,再发读地址。这个顺序错了,读出来的就是垃圾数据。

4.2 PJ85718DM 寄存器配置

PJ85718DM 内部有几个关键寄存器,我挑最重要的几个说:

  • 配置寄存器:设置测温分辨率、报警模式、单次/连续转换。
  • 远程温度寄存器:高字节和低字节,组合起来是 11 位温度数据。
  • 本地温度寄存器:芯片自身温度。
  • 状态寄存器:报警标志、忙标志。

初始化的时候,我一般这样配:

// 配置 PJ85718DM PJ85718_Write(0x09, 0x00); // 配置寄存器:连续转换,11位分辨率 PJ85718_Write(0x0A, 0x00); // 远程温度高限,先清零 PJ85718_Write(0x0B, 0x00); // 远程温度低限,先清零

分辨率的选择有个权衡:11 位分辨率对应 0.125℃,转换时间大概 100ms 左右;如果降到 9 位,转换时间缩短到 30ms,但分辨率变成 0.5℃。HVAC 场景里温度变化很慢,我一般用 11 位,追求精度。如果你做的是快速响应的场景,可以降到 10 位折中。

4.3 温度数据换算

PJ85718DM 的远程温度数据是 11 位,高字节是整数部分,低字节的高 3 位是小数部分。换算公式:

float PJ85718_GetRemoteTemp(void) { uint8_t high, low; int16_t raw; float temp; PJ85718_Read(0x01, &high); // 远程温度高字节 PJ85718_Read(0x10, &low); // 远程温度低字节(部分型号) raw = (int16_t)((high << 3) | (low >> 5)); if (raw & 0x400) { // 负数判断 raw |= 0xF800; } temp = raw * 0.125f; return temp; }

这里有个坑:负温度的处理。11 位数据里,最高位是符号位。如果温度是负的,直接按无符号数算会得到一个大正数。必须先判断符号位,再做符号扩展。我第一次写的时候没注意,冬天测试时远程温度显示 120℃,查了半天才发现是负数没处理。

本地测温的换算用 Steinhart-Hart 公式:

float GetLocalTemp(void) { uint16_t adc_val; float resistance, temp_k, temp_c; adc_val = ADC_Read(0); // 读 ADC 通道 0 resistance = 10000.0f * adc_val / (4095.0f - adc_val); // Steinhart-Hart 简化公式(B 值法) temp_k = 1.0f / (1.0f/298.15f + log(resistance/10000.0f)/3950.0f); temp_c = temp_k - 273.15f; return temp_c; }

这个公式里的log是自然对数,需要包含math.h。如果 MCU 资源紧张,可以用查表法代替,把温度-阻值对应关系做成数组,用二分查找。查表法速度快,但精度取决于表的密度。我一般用 1℃ 间隔的表,中间用线性插值,精度足够。

4.4 数据滤波与上报

原始温度数据肯定有噪声,直接上报会看到小数点后几位乱跳。我一般做两级滤波:第一级是滑动平均,取最近 8 次采样的平均值;第二级是限幅滤波,如果本次采样和上次的差值超过 2℃,就认为是个异常值,丢弃不用。

#define FILTER_SIZE 8 float temp_buffer[FILTER_SIZE]; uint8_t buf_index = 0; float FilterTemp(float new_temp) { float sum = 0; static float last_temp = 0; // 限幅:变化超过 2℃ 丢弃 if (fabs(new_temp - last_temp) > 2.0f && last_temp != 0) { return last_temp; } temp_buffer[buf_index] = new_temp; buf_index = (buf_index + 1) % FILTER_SIZE; for (int i = 0; i < FILTER_SIZE; i++) { sum += temp_buffer[i]; } last_temp = sum / FILTER_SIZE; return last_temp; }

上报格式我一般用简单的 ASCII 协议,比如T1:25.3,T2:48.7\r\n,T1 是本地温度,T2 是远程温度。这种格式人眼可读,上位机解析也简单。如果带宽紧张,可以改成二进制协议,两个字节一个温度值,但调试起来麻烦一些。

5. 实操调试与常见问题排查

5.1 I2C 通信失败排查

I2C 不通是最常见的问题,我总结了一个排查顺序:

现象可能原因排查方法
完全无应答地址错误、供电缺失用示波器看 SDA/SCL 是否有波形,确认器件供电
偶尔应答上拉电阻过大、总线电容大减小上拉电阻,缩短走线
读数据全 0xFF寄存器地址错误核对数据手册的寄存器映射
读数据全 0x00器件未初始化检查配置寄存器是否写入成功
温度值跳变电源噪声、探头干扰加退耦电容,探头线双绞

我印象最深的一次调试,是远程温度一直读 0x7FF(也就是最大值)。查了半天,发现是 D+ 和 D- 接反了。PJ85718DM 的 D+ 要接三极管的基极和集电极(短接),D- 接发射极。接反了芯片就认为探头开路,输出最大值。这个错误很隐蔽,因为 I2C 通信完全正常,只是温度数据不对。

5.2 温度精度校准

PJ85718DM 出厂时已经校准过,但实际使用中,探头三极管的个体差异、走线电阻都会带来误差。我一般做一次单点校准:把探头放到冰水混合物里(0℃),读一个值,算出偏移量,写到 MCU 的 EEPROM 里,后续所有读数都减去这个偏移。

// 校准偏移量,存在 EEPROM int8_t temp_offset = 0; float GetCalibratedTemp(void) { float raw = PJ85718_GetRemoteTemp(); return raw - temp_offset; }

如果要求更高,可以做两点校准:0℃ 和 100℃ 各测一次,算出增益和偏移。但 HVAC 场景一般单点就够了,因为温度范围不宽,线性度很好。

5.3 长线缆下的稳定性

远程探头线超过 3 米之后,读数可能会周期性跳动。这通常是工频干扰或者地环路引起的。解决办法:一是用屏蔽双绞线,屏蔽层单端接地;二是在 D+ / D- 上各串 100Ω 电阻,再并 100pF 电容到地;三是软件上做中值滤波,连续采 5 次,取中间值。

我实测过 10 米线缆的情况,不加任何措施时,温度跳动 ±3℃;加了双绞线 + 100Ω 串阻 + 100pF 电容后,跳动降到 ±0.5℃ 以内;再加上软件中值滤波,基本稳定在 ±0.2℃。这个效果对于 HVAC 控制来说完全够用了。

5.4 低功耗考虑

如果这套系统是电池供电的,功耗就要精打细算。PJ85718DM 在连续转换模式下大概 300μA,PIC18F47Q10 跑 16MHz 时大概 5mA。要省电,可以让 MCU 大部分时间休眠,定时唤醒读温度。PJ85718DM 也支持单次转换模式,读完就自动进入低功耗状态。

// 单次转换模式 PJ85718_Write(0x09, 0x60); // 配置为单次转换 delay_ms(200); // 等待转换完成 float temp = PJ85718_GetRemoteTemp(); // 然后 MCU 进入休眠 Sleep();

这样平均功耗可以降到 100μA 以下,用两节 AA 电池能撑一年以上。

6. 应用场景延展与经验总结

6.1 HVAC 风管测温实战

在空调风管测温场景里,探头要伸进风管内部,测量送风温度。风管里风速高、灰尘多,探头不能太大,否则影响气流。我用 SOT-23 封装的三极管做探头,焊在一根细长的 PCB 条上,外面套热缩管,只露出感温部分。线缆用屏蔽双绞线,从风管检修口引出来,接到主板上的 PJ85718DM。

这个场景有个特殊问题:风管内外温差大,探头引线会形成热桥,把风管外的温度传到探头。解决办法是让探头引线在风管内多绕几圈,增加热阻,或者用导热硅脂把探头贴紧管壁。我试过前者,效果不错,读数能真实反映风管内温度。

6.2 多路远程测温扩展

PJ85718DM 的 I2C 地址可以通过 ADDR 引脚配置,一般支持 4 到 8 个不同地址。如果一条总线上挂多颗,每颗接一个远程探头,就能实现多点测温。比如一个机房,可以在冷通道、热通道、回风口各放一个探头,同时监测。

多路扩展时要注意总线负载。每颗器件的 I2C 输入电容大概 10pF,挂 8 颗就是 80pF,加上走线电容,很容易超过 400pF 的上限。这时候要么降低通信速率到 100kHz,要么加 I2C 缓冲器。我一般控制在 4 颗以内,超过就加缓冲。

6.3 报警逻辑设计

温度监测最终要落到报警上。我在固件里设了三级报警:预警(超过阈值 2℃)、报警(超过阈值 5℃)、紧急(超过阈值 10℃)。每级报警对应不同的上报频率和动作。预警时正常上报,报警时提高上报频率,紧急时直接拉一个 GPIO 去驱动蜂鸣器或者继电器。

阈值不能写死,要能通过上位机配置。我一般把阈值存在 EEPROM 里,上电时读出来。这样现场调试时不用重新烧固件,用串口发个命令就能改。

6.4 我踩过的几个坑

第一个坑是I2C 时钟拉伸。PJ85718DM 在转换期间会拉低 SCL,如果 MCU 的 I2C 外设不支持时钟拉伸,通信就会失败。PIC18F47Q10 的 MSSP 模块是支持时钟拉伸的,但初始化时要确保相关配置位正确。我一开始没注意,读温度时偶尔超时,后来查手册才发现是这个问题。

第二个坑是电源时序。如果 PJ85718DM 和 MCU 共用 3.3V,但 MCU 先上电、传感器后上电,MCU 初始化 I2C 时传感器还没准备好,第一次通信就会失败。解决办法是在初始化 I2C 之前加 100ms 延时,或者检测传感器应答后再继续。

第三个坑是EEPROM 写入寿命。校准偏移量如果频繁写入 EEPROM,会缩短寿命。我改成只在校准模式下才写,正常运行时只读,这样 EEPROM 基本不会被磨损。

这套 PJ85718DM + PIC18F47Q10 的组合,我从第一版打样到现在,前后改了三次板子,固件迭代了十几个版本,目前在一台模拟的 HVAC 控制器上连续跑了半年多,温度读数稳定,通信没出过问题。如果你也在做类似的项目,我建议先把 I2C 通信和温度换算这两块吃透,剩下的就是按部就班地加滤波、加报警、加上报。真正花时间的往往不是核心功能,而是那些边边角角的干扰和异常处理。

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

基于Hadoop的电影推荐系统:数据清洗到ALS落地全流程

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

作者头像 李华
网站建设 2026/10/11 1:13:15

YOLO目标检测实战:飞机鸟类无人机数据集训练与PyQt5界面部署

简介&#xff1a;本资源面向计算机视觉学习者与目标检测工程实践者&#xff0c;提供一套细分类型飞机、鸟类与无人机的YOLOv5检测训练方案&#xff0c;重点解决细粒度识别中机型区分难、样本组织繁琐的问题&#xff0c;适合具备一定深度学习基础、希望快速复现实验或搭建演示系…

作者头像 李华
网站建设 2026/10/11 1:13:04

钢铁产销一体化:用三张表+消息队列打通ERP/MES/LIMS断点

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

作者头像 李华
网站建设 2026/10/11 1:13:01

PJ85718DM+STM32F101ZG工业温控方案设计与实战

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

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

PJ85718DM+STM32F215ZG工业温度监测系统设计

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

作者头像 李华
网站建设 2026/10/11 1:11:49

9轴IMU卡尔曼滤波姿态解算:从原理到Matlab仿真与硬件部署

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

作者头像 李华