简介这份资源面向电子信息、嵌入式与物联网方向的毕业设计学生及DIY爱好者提供一套可基本实现功能的语音控制智能家居完整工程解决从语音识别、蓝牙通信到设备控制的软硬件联调问题。压缩包共2358个文件、约33.89MB涵盖Android上位机源码java、class、dex、apk、gradle等、32位单片机与51语音模块工程c、h、s、hex、uvproj、uvprojx等、语音识别模型文件crf、bin、lst以及json、xml配置与说明文档构成从移动端到嵌入式端的完整链路。已有1806人学习下载具备一定参考基础。读者可据此获得Android应用与单片机通过蓝牙低功耗通信的控制框架、语音指令解析与GPIO驱动外设的实现思路以及MVC/MVVM分层与中断处理的代码组织方式适合作为毕设原型参考与二次开发起点。1. 语音控制智能家居从一句口令到一盏灯亮起的完整链路很多同学做语音控制智能家居第一反应是直接上云端语音助手结果答辩现场网络一抖灯没亮、风扇没转场面相当尴尬。这套方案走的是另一条路本地语音识别加蓝牙控制把「说一句话—识别指令—下发控制」这条链路压在一个离线可跑的系统里不依赖外网成本压到一块主控板加一个蓝牙模块的量级。它适合正在做毕设或课程设计、需要一套能演示、能讲清原理、还能现场复现的同学也适合想快速搭一个智能家居原型的从业者。整套方案的核心不是堆功能而是把语音采集、指令识别、蓝牙通信、设备执行四个环节串成一条稳定可控的闭环下面按需求、设计、实现、避坑、验收的顺序拆开讲。2. 需求与选型为什么是本地语音加蓝牙而不是云端方案2.1 功能需求拆解三类指令与四个受控设备先把需求钉死不然后面选型全是拍脑袋。这套方案面向的是单房间或小范围场景受控设备控制在四类照明灯、温控风扇或小功率加热、遮阳窗帘或舵机模拟、电源插座通断。指令分三类单设备开关类「开灯」「关风扇」、状态调节类「灯亮一点」「风扇调大一档」、场景组合类「我要睡觉了」触发关灯加关窗帘。三类指令对应三种识别难度开关类是关键词匹配调节类要带参数解析场景类是意图映射这个分层直接决定了后面识别模块怎么写。需求里还有两条隐性约束必须提前写进设计文档一是响应时间从说完口令到设备动作通常要求控制在两秒以内否则演示时会有明显迟滞感二是离线可用答辩教室、实验室往往没有稳定网络云端方案一旦断网就是黑匣子排查都无从下手。这两条约束一立技术选型的空间就窄了很多。2.2 技术选型对比三条路线的取舍语音识别这块有三条常见路线我一般会拿一张表把取舍摆清楚再定。路线识别方式依赖成本适合场景云端语音助手上传音频到云平台识别稳定外网低按调用计费功能多、网络可靠本地关键词识别芯片板载固件做关键词唤醒与匹配无中固定口令、低功耗本地语音识别模块模块内跑声学模型串口输出文本无中低需要一定自由度的口令这套方案选第三条本地语音识别模块负责把音频转成文本主控拿到文本后自己做指令解析。原因是关键词芯片口令固定、扩展性差答辩时老师随口改一句口令就翻车云端方案又踩了离线约束。本地模块加主控解析的组合既保证离线又把「识别」和「理解」解耦识别模块换型号不影响上层逻辑这是血泪经验换来的结构。通信层选蓝牙而不是 Wi-Fi理由很实在蓝牙模块便宜、配对简单、不需要路由器演示时手机或主控直连受控端即可。代价是传输距离短、带宽低但智能家居的指令本身就是几十字节的短报文蓝牙完全够用。这里要注意蓝牙分经典蓝牙和低功耗蓝牙BLE如果受控端是电池供电的小节点优先 BLE如果是有线供电、只做透传经典蓝牙的串口透传模式开发最快。2.3 硬件清单与角色划分硬件按「主控 语音 通信 执行」四块配。主控选一块带多个串口的开发板语音模块占一个串口蓝牙模块占一个串口剩下的引脚驱动继电器和舵机。执行端用继电器模块控制灯的通断用舵机模拟窗帘开合风扇可以用继电器加调速模块插座用继电器即可。整套清单里最容易被忽略的是电源语音模块和蓝牙模块同时工作时电流有波动主控如果和它们共用一个不稳的电源会出现识别偶发失败这个坑后面避坑章节还会展开。角色划分上主控是大脑负责收语音文本、解析指令、组蓝牙报文语音模块是耳朵只负责输出文本蓝牙模块是嘴巴把指令发给受控节点受控节点是手脚收到报文后驱动继电器或舵机。这个划分的好处是每个模块职责单一出问题时能快速定位是哪一环掉了链子。3. 总体架构设计四层结构与指令流转路径3.1 分层架构采集层、识别层、决策层、执行层整套系统按四层切采集层负责麦克风拾音和音频预处理识别层把音频转成文本决策层做指令解析和场景映射执行层驱动具体设备。层与层之间用明确定义的接口通信采集层到识别层是音频流识别层到决策层是文本字符串决策层到执行层是结构化的控制报文。这样切的好处是每层可以单独测试识别层不准就换模块决策层逻辑错就改解析规则互不牵连。指令流转路径要画清楚用户说「开灯」→ 麦克风采集音频 → 识别模块输出文本「开灯」→ 主控收到文本 → 解析出设备「灯」和动作「开」→ 组装蓝牙报文 → 蓝牙发送 → 受控节点收到报文 → 驱动继电器闭合 → 灯亮。这条链路上任何一环延迟都会累积到响应时间里所以每一环都要做超时保护识别模块超过一定时间没输出就丢弃本次音频避免卡死。3.2 指令协议设计报文格式与设备寻址蓝牙传输的是字节流必须自己定一套简单协议否则受控端不知道收到的字节是什么意思。我一般用「帧头 设备地址 动作码 参数 校验」的定长帧结构帧头固定两个字节用于同步设备地址一字节区分四个受控设备动作码一字节区分开、关、调节参数一字节承载档位或亮度最后一字节做异或校验。定长帧的好处是接收端解析简单不用处理变长边界问题。// 蓝牙控制帧结构定义定长6字节 typedef struct { uint8_t head1; // 帧头1固定 0xAA uint8_t head2; // 帧头2固定 0x55 uint8_t dev_addr; // 设备地址0x01灯 0x02风扇 0x03窗帘 0x04插座 uint8_t action; // 动作码0x01开 0x02关 0x03调节 uint8_t param; // 参数调节档位或亮度开关类填0 uint8_t checksum; // 前5字节异或校验 } CtrlFrame; // 组帧函数调用前先填好 dev_addr/action/param void build_frame(CtrlFrame *f, uint8_t dev, uint8_t act, uint8_t param) { f-head1 0xAA; f-head2 0x55; f-dev_addr dev; f-action act; f-param param; f-checksum f-head1 ^ f-head2 ^ f-dev_addr ^ f-action ^ f-param; }这段代码的关键点在两个地方。一是帧头用两个字节而不是一个单字节帧头在字节流里太容易误同步双字节能把误判概率压下去二是校验用异或而不是求和异或实现简单、对单比特翻转敏感短报文场景够用。参数param在开关类指令里填 0接收端解析时按动作码决定是否读取它这样一套帧结构同时覆盖开关和调节两类指令不用为调节类单独设计协议。3.3 状态管理设备状态表与指令幂等受控端要维护一张设备状态表记录每个设备当前是开还是关、亮度或档位是多少。这张表的作用有两个一是让「开灯」这种指令具备幂等性灯已经开着再收到开灯指令不重复动作避免继电器频繁吸合二是支持状态查询用户问「灯开着吗」时能直接回答。状态表用一维数组按设备地址索引即可每个元素存动作码和参数两个字段。// 设备状态表下标即设备地址0号位不用 typedef struct { uint8_t power; // 0关 1开 uint8_t level; // 档位或亮度 0-100 } DevState; DevState dev_table[5]; // 支持4个设备下标1-4 // 执行前先比对状态相同则跳过保证幂等 uint8_t apply_cmd(uint8_t dev, uint8_t act, uint8_t param) { if (dev 1 || dev 4) return 0; // 地址越界保护 if (act 0x01 dev_table[dev].power 1) return 1; // 已开跳过 if (act 0x02 dev_table[dev].power 0) return 1; // 已关跳过 // 真正驱动硬件并更新状态表 drive_hardware(dev, act, param); dev_table[dev].power (act 0x01) ? 1 : (act 0x02) ? 0 : dev_table[dev].power; if (act 0x03) dev_table[dev].level param; return 1; }幂等处理看着不起眼但演示时连续说两遍「开灯」的情况太常见了没有这层保护继电器会咔咔响两下观感很差。地址越界保护也是必须的蓝牙报文在干扰下可能收到脏数据校验过了但地址字段是乱值不拦一下就可能驱动到不存在的引脚。4. 核心模块实现语音识别、指令解析与蓝牙下发4.1 语音识别模块接入串口配置与文本输出语音识别模块一般通过串口输出识别结果接入的第一步是把串口参数配对。常见配置是波特率 9600 或 115200、8 位数据位、1 位停止位、无校验具体以模块手册为准配错波特率的表现是收到一堆乱码这是排查时第一个要看的点。主控这边开一个串口接收中断把收到的字节攒进缓冲区识别到结束符后把整条文本交给解析函数。// 语音模块串口接收中断里攒字节主循环里解析 #define VOICE_BUF_SIZE 64 char voice_buf[VOICE_BUF_SIZE]; volatile uint8_t voice_len 0; volatile uint8_t voice_ready 0; void on_voice_uart_rx(uint8_t byte) { if (byte \n || voice_len VOICE_BUF_SIZE - 1) { voice_buf[voice_len] \0; // 补字符串结束符 voice_ready 1; // 标记一条完整指令到达 voice_len 0; } else { voice_buf[voice_len] (char)byte; } } // 主循环里轮询避免在中断里做耗时解析 void voice_task(void) { if (!voice_ready) return; voice_ready 0; parse_command(voice_buf); // 交给解析层 }这里的设计考虑是中断只做搬运、不做解析。解析函数里可能有字符串比较和查表放在中断里会拉长中断响应时间影响其他串口收数。用voice_ready标志位把解析挪到主循环是嵌入式里很常规的做法。缓冲区大小按最长口令估一般 64 字节足够超长直接截断防止缓冲区溢出。4.2 指令解析关键词匹配与参数提取解析层要做两件事从文本里认出设备名和动作词再从文本里抠出参数。设备名和动作词用关键词表匹配参数用简单的数字提取。匹配顺序有讲究先匹配场景词「睡觉」「回家」再匹配调节词「亮一点」「大一档」最后匹配开关词因为场景词优先级最高一句话里同时出现「睡觉」和「灯」时应该走场景逻辑而不是单设备逻辑。// 关键词表文本片段 - 设备地址 动作码 typedef struct { const char *word; uint8_t dev; uint8_t act; } Keyword; Keyword keywords[] { {开灯, 0x01, 0x01}, {关灯, 0x01, 0x02}, {开风扇, 0x02, 0x01}, {关风扇, 0x02, 0x02}, {开窗帘, 0x03, 0x01}, {关窗帘, 0x03, 0x02}, {开插座, 0x04, 0x01}, {关插座, 0x04, 0x02}, }; // 返回1表示命中结果写入 dev/act/param uint8_t match_keyword(const char *text, uint8_t *dev, uint8_t *act, uint8_t *param) { // 先处理场景指令 if (strstr(text, 睡觉)) { *dev 0xFF; *act 0x10; *param 0; return 1; } if (strstr(text, 回家)) { *dev 0xFF; *act 0x11; *param 0; return 1; } // 再匹配单设备关键词 for (int i 0; i sizeof(keywords)/sizeof(Keyword); i) { if (strstr(text, keywords[i].word)) { *dev keywords[i].dev; *act keywords[i].act; *param 0; return 1; } } return 0; // 未命中交给兜底逻辑 }场景指令用dev 0xFF这个特殊地址标记执行层看到这个地址就知道要展开成一组设备动作而不是驱动单个设备。这种「特殊地址 动作码」的写法比在解析层直接展开场景更灵活场景内容改了只动执行层的映射表解析层不用动。参数提取这块调节类指令可以在关键词命中后再扫一遍文本里的数字或者用「一档」「二档」这类词表映射具体看识别模块输出的文本格式有的模块会把数字转成汉字有的保留阿拉伯数字接入时先抓几条真实输出看看再定规则。4.3 蓝牙下发与受控端执行连接管理与重发机制蓝牙下发这块主控作为发起端受控节点作为接收端。经典蓝牙串口透传模式下主控和节点先配对配对成功后主控往串口写字节节点从串口读字节链路层的事模块自己处理。要注意的是配对状态可能掉尤其是演示前反复上电的情况所以主控发指令前要检查连接状态没连上先发起连接连接失败重试两次再报错。// 蓝牙下发带连接检查和一次重发 uint8_t send_ctrl(uint8_t dev, uint8_t act, uint8_t param) { CtrlFrame f; build_frame(f, dev, act, param); for (int retry 0; retry 2; retry) { if (!bt_is_connected()) { bt_connect(); // 尝试重连 delay_ms(200); // 给模块一点时间 continue; } if (bt_write((uint8_t *)f, sizeof(f)) sizeof(f)) { return 1; // 写成功 } } return 0; // 两次都失败上报错误 }重发机制只做一次不做无限重试因为智能家居指令有时效性重发太多次用户已经走开了灯才亮反而奇怪。写失败时上层要能感知可以在主控上加一个状态指示灯发送失败闪红灯演示时一眼能看出是通信问题还是识别问题。受控端收到帧后先校验帧头和校验和校验不过直接丢弃校验过了再查状态表做幂等判断最后驱动硬件。受控端的解析代码和主控组帧是对称的这里不重复贴关键是校验和计算要用同一套异或逻辑两边对不上就会全部丢帧。5. 避坑与排查五条最容易翻车的点5.1 识别偶发失败电源波动与地线干扰现象是同一句口令有时识别成功有时没反应换个人说成功率又不一样。原因多半不在识别算法而在电源。语音模块和蓝牙模块同时工作时瞬态电流能到几百毫安如果主控和模块共用一路不稳的电源电压跌落会让模块复位或采样失真。解决方法是给语音模块单独加一颗稳压芯片和足够的滤波电容地线走星型拓扑模块地线单独回电源地不要和继电器这种大电流负载串在一起。改完电源后如果还有偶发失败再去看麦克风增益增益太低远场拾音差太高又容易削波。5.2 蓝牙连不上或频繁掉线配对信息与波特率现象是主控发指令没反应查连接状态显示未连接或者连上几秒就断。原因常见两个一是配对信息残留模块里存了旧的配对记录新连接被拒二是串口波特率和模块透传波特率不一致数据发出去模块没认。解决方法是先清配对信息重新配对再核对两边波特率用串口助手抓一下模块上电时打印的配置信息最直接。如果掉线频繁检查供电和天线周围有没有金属遮挡蓝牙天线贴在大块金属旁边信号会明显变差。5.3 指令误触发关键词太短与场景词冲突现象是没说话设备自己动了或者说「关灯」结果窗帘动了。原因是关键词太短识别模块把环境音里的相似音节也输出了或者关键词表里有包含关系「开灯」和「开窗帘」都含「开」匹配顺序不对就串了。解决方法一是关键词尽量用两字以上组合二是匹配时按词长从长到短排先匹配「开窗帘」再匹配「开灯」三是加一个置信度门槛识别模块输出置信度低的直接丢弃。场景词和单设备词冲突时按前面说的场景优先原则处理。5.4 继电器误动作与粘连驱动能力与续流现象是设备偶尔自己开关或者关了之后又弹开。原因是主控引脚直接驱动继电器线圈电流不够导致吸合不稳或者线圈断电时的反向电动势打坏了驱动管。解决方法是用三极管或专用驱动芯片做隔离驱动线圈两端并续流二极管继电器触点和线圈之间光电隔离更稳。如果驱动的是交流负载强电部分一定要和弱电部分物理隔开走线不要平行这是安全底线不是可选项。5.5 演示现场翻车环境噪声与口令习惯现象是实验室好好的到答辩教室识别率骤降。原因是教室混响大、背景人声多识别模块的远场拾音扛不住。解决方法是演示前到现场做一次校准把麦克风朝向说话人、离嘴 30 到 50 厘米口令用短句、语速放慢提前把常用指令练几遍形成肌肉记忆。另外准备一套手动按键兜底语音万一连续失败可以切手动演示别让整场答辩卡在一个口令上。6. 验收与答辩怎么证明这套系统真的能用验收这块我一般按「功能覆盖、响应时间、稳定性、可解释性」四个维度准备材料每个维度都有可量化的指标答辩时拿数据说话比口头描述有说服力。验收维度验收方法合格标准功能覆盖逐条执行三类指令清单开关类全通过调节类参数正确场景类动作完整响应时间从说完口令到设备动作计时平均不超过 2 秒最长不超过 3 秒稳定性连续执行 50 次指令成功率不低于 90%无死机无掉线可解释性现场讲解指令流转链路能说清每一环的输入输出和失败处理功能覆盖的测试清单要提前写好三类指令各列若干条逐条打勾答辩时把这张表展示出来老师一看就知道你测过。响应时间用手机秒表或者串口打时间戳都行关键是测多次取平均别只测一次。稳定性测试最容易忽略连续跑 50 次能暴露电源和内存问题跑的过程中观察有没有重启、有没有指令丢失。可解释性这块答辩时被问得最多的就是「识别错了怎么办」「蓝牙断了怎么办」提前把兜底逻辑和错误处理讲清楚比堆功能更能体现工程思维。答辩演示有个技巧把演示流程按「正常场景 → 边界场景 → 故障恢复」三段设计。正常场景走一遍开灯、调风扇、睡觉模式边界场景演示说错口令时的兜底、连续说两遍的幂等故障恢复演示拔掉蓝牙再插上、断网情况下依然能本地控制。三段走完系统的完整性和鲁棒性都体现出来了。演示前一定按顺序彩排两遍把每个动作的间隔留够别让老师等。从那以后我每次带这类项目都会在答辩前一天到现场把整套流程完整走三遍电源、配对、口令、兜底一个不落因为翻车往往不是技术不行而是没在真实环境里跑过。希望这套结构能帮到你照着搭一遍再按验收表测一轮交上去的东西自己心里就有底了。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
Linux硬链接与符号链接:inode原理、ln实操与断链排查 前两天团队里一位开发者发来消息,说发布目录里的静态资源整站 404,重启服务也没用。我上去看了一眼,ls -l里那个current后面挂着一行红色的-> /srv/app/releases/v1.2.3,而releases下面这个目录早就被清理脚本删掉了。问题不是… · 2026/11/14 15:31:56
TypeScript插件系统实战:plugin.json、SDK与CLI加载失败排查 1. 从"plugins"这个标题说起:插件系统到底在解决什么问题"plugins"这个词单独拎出来,信息量其实非常少。但结合热搜词里反复出现的cursor、plugin.json、TypeScript SDK、CLI、harness failed to load plugins这些关键词,… · 2026/11/13 23:52:48
CMake依赖管理:原理、技巧与最佳实践 1. CMake依赖管理的核心挑战在构建C/C项目时,依赖管理是最令人头疼的问题之一。我经历过无数次因为链接顺序错误导致的undefined reference问题,也遇到过因为循环依赖导致的构建失败。CMake作为现代构建系统的标准,提供了多种机制来处理这些依… · 2026/11/11 18:15:55
电工证入伍加分吗多少钱才合适?实操考试心里没底怕挂科 电工证入伍加分吗多少钱才合适?实操考试心里没底怕挂科 实操考试心里没底怕挂科,报名前最担心的就是“电工证入伍加分吗”,还纠结“多少钱”才能考下来,这种焦虑我懂。特别是像洛阳这样的三四线城市,刚毕业或者准备转行的年轻人,对特种作业证的含金量、… · 2026/11/15 1:03:33
嘉善电工证报考流程在哪考?实操考试心里没底怕挂科?别慌,这招帮你稳过 嘉善电工证报考流程在哪考?实操考试心里没底怕挂科?别慌,这招帮你稳过 实操考试心里没底怕挂科?这是很多准备报考嘉善电工证的学员最真实的担忧。尤其是像鹤壁的在职建筑工人,平时工作忙、时间紧,一听说要上手操作,紧张感直接拉满。别急,这篇文章就是… · 2026/11/15 1:03:33
台湾电工证报考条件值不值得考 这些细节不看真亏了 台湾电工证报考条件值不值得考 这些细节不看真亏了 怕考不过白交培训费?台湾电工证报考条件和考试难度,很多人都没搞清楚。尤其对于河南许昌劳务班组负责人来说,电工证不只是个资格证明,更是进工地、拿项目、谈合作的关键筹码。但现实中,不少学员因为信… · 2026/11/15 1:03:33
驾驶员电工证哪家好通过率揭秘:怕考不过白交培训费?这几点必须知道 驾驶员电工证哪家好通过率揭秘:怕考不过白交培训费?这几点必须知道 怕考不过白交培训费?现在报名考【驾驶员电工证】的小伙伴越来越多,但真正了解考试难度、通过率和培训质量的人却不多。今天咱们就从濮阳一位转岗从业者的真实经历出发,揭秘【驾驶员电工… · 2026/11/15 1:03:33
苏州考取电工证多少钱 2026河南最新政策怎么考最省事 苏州考取电工证多少钱 2026河南最新政策怎么考最省事 你缺的是电工证,不是机会。眼下找工作处处碰壁,特种作业证成了门槛,尤其是电工证,几乎是不少电工、安装、维修类岗位的硬性要求。2026年河南最新政策已经落地, 苏州考取电工证多少钱… · 2026/11/15 1:03:33
拿到假电工证求职全流程避坑指南:多久拿证才能顺利上岗 拿到假电工证求职全流程避坑指南:多久拿证才能顺利上岗 你是不是正盯着招聘网站上那句“持证上岗,优先录用”发愁?手里没有电工证,却急着找工作,连面试资格都拿不到,这种焦灼谁懂?尤其是在周口这样的中小型施工企业,电工证几乎是基础门槛,… · 2026/11/15 1:02:33
长春初级电工证怎么考?通过率揭秘全在这里 长春初级电工证怎么考?通过率揭秘全在这里 之前考的证在外省能不能转过来?这几乎是每个想从事电工工作的人都会问的问题。特别是那些在外地打拼多年、手里握着一张“外地电工证”的人,到了长春想继续干这一行,第一反应就是“我的证能用吗?”。今天我们就… · 2026/11/15 0:00:50
国内电工证报考条件与考试时间 低压电工证怎么考?学历不高也能报名,官方报名入口全在这 你是不是经常听说“电工证是入行门槛”,但又担心自己学历不够、经验不足,根本报不了名?别急,今天就带你从零了解【国内电工证】的报考流程、考试内容,还有怎么在 官方报名入口… · 2026/11/15 0:00:50
电工作业时如何断电?电子证书到底能不能全国通用? 电工作业时如何断电?电子证书到底能不能全国通用? 实操考试心里没底怕挂科,特别是电工作业时如何断电这一操作,不仅关系到你能不能拿到证书,更关系到以后能不能顺利上岗。很多人觉得这不过就是“断个电”,但其实这里面的门道可不少,稍有不慎就可能出错… · 2026/11/15 0:00:50
长春初级电工证怎么考?通过率揭秘全在这里 长春初级电工证怎么考?通过率揭秘全在这里 之前考的证在外省能不能转过来?这几乎是每个想从事电工工作的人都会问的问题。特别是那些在外地打拼多年、手里握着一张“外地电工证”的人,到了长春想继续干这一行,第一反应就是“我的证能用吗?”。今天我们就… · 2026/11/15 0:00:50
国内电工证报考条件与考试时间 低压电工证怎么考?学历不高也能报名,官方报名入口全在这 你是不是经常听说“电工证是入行门槛”,但又担心自己学历不够、经验不足,根本报不了名?别急,今天就带你从零了解【国内电工证】的报考流程、考试内容,还有怎么在 官方报名入口… · 2026/11/15 0:00:50
电工作业时如何断电?电子证书到底能不能全国通用? 电工作业时如何断电?电子证书到底能不能全国通用? 实操考试心里没底怕挂科,特别是电工作业时如何断电这一操作,不仅关系到你能不能拿到证书,更关系到以后能不能顺利上岗。很多人觉得这不过就是“断个电”,但其实这里面的门道可不少,稍有不慎就可能出错… · 2026/11/15 0:00:50
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/13 6:12:21
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/13 6:11:51
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/13 22:31:30