news 2026/9/5 10:32:37

STM32H743ZI通过SDMMC2驱动88W8801实现Wi-Fi联网

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32H743ZI通过SDMMC2驱动88W8801实现Wi-Fi联网

简介:本资源是面向STM32H7系列嵌入式开发者的Wi-Fi联网实战工程,聚焦于通过SDMMC2接口驱动Marvell 88W8801 SDIO WiFi模块,并基于LwIP 2.1.2协议栈构建HTTP服务器,适用于物联网终端、无线调试网关等需要轻量级Wi-Fi接入的工业与教学场景。压缩包共641个文件,主体为455个头文件(h)与96个源文件(c),涵盖HAL驱动适配、WiFi模式切换(STA/UAP)、SDIO底层通信、HTTP服务逻辑及系统时钟配置等核心模块;另有少量编译中间文件(obj、lst)、调试符号(pdb、axf)、资源文件(bmp、ico)及工程配置(uvprojx、hex),总大小7.19MB,结构完整,可直接导入Keil MDK编译运行。已有652人学习下载,提供从硬件初始化、SDIO协议交互、WiFi固件加载到HTTP服务部署的全链路实现,含实测数据发送速度验证模块与多状态日志输出,便于开发者快速掌握STM32H7平台下SDIO WiFi模块的集成方法与网络服务开发要点。

1. 项目概述:一块被低估的“无线+主控”硬核组合

STM32H743ZI用SDMMC2驱动88W8801——这行标题乍看像一串技术代号拼贴,实则藏着嵌入式开发里一个极具实战价值的交叉点:用高性能Cortex-M7主控,通过标准SDIO接口,去驾驭一款成熟可靠的Wi-Fi SoC。我第一次在客户产线看到这个方案时,心里就咯噔一下:这不是把STM32H7的高主频、大内存优势,和88W8801的低功耗、强兼容性硬生生焊在一起了吗?它不走USB或SPI这种“温柔路线”,而是直接啃SDIO协议栈这块硬骨头,背后是实打实的性能取舍和资源博弈。

核心关键词里,“STM32H743ZI”是主角,1MB RAM + 2MB Flash + 双核架构(CM7+CM4可选),不是玩具级芯片;“SDMMC2”是关键通道,H7系列有两组SDIO控制器,SDMMC2通常引脚更灵活、时钟域更独立,适配外设更稳;而“88W8801”则是Marvell(现属NXP)的老牌Wi-Fi芯片,支持802.11b/g/n,带完整的MAC+PHY,还内置了ARM9协处理器跑固件,不靠主控CPU做协议解析——这点太关键了。很多人误以为SDIO只是插SD卡的,其实它本质是高速串行总线,理论速率可达50MHz x 4bit = 200Mbps,比SPI快5倍,比USB CDC串口快10倍,这才是它能扛起Wi-Fi数据吞吐的底气。

这个项目适合三类人:一是正在做工业网关、智能电表、边缘AI盒子的工程师,需要稳定Wi-Fi连接又不想加额外MCU;二是高校实验室搞物联网协议栈移植的学生,88W8801开源驱动多、文档全,是绝佳的SDIO实战教材;三是想摆脱ESP32/RTL8720这类“黑盒模块”束缚的极客,真正从寄存器层理解Wi-Fi如何与主控握手。它不追求“一键联网”的便利,而是给你一把螺丝刀,让你亲手拧紧每一颗协议螺丝。我去年帮一家电力设备厂落地这个方案,他们原用ESP32做Wi-Fi透传,结果EMC测试过不了,换成88W8801+H743后,射频隔离做得干净利落,还省下3块钱BOM成本——这账,得算在板子上,而不是Demo里。

2. 整体设计思路与方案选型逻辑

2.1 为什么非得用SDMMC2,而不是SDMMC1或SPI?

这个问题我被问过不下二十次。答案很实在:引脚复用冲突和时钟域隔离。STM32H743ZI的SDMMC1默认绑定在PI0-PI11,这些引脚在LQFP144封装里和LCD TFT接口、FSMC总线严重打架,你若同时要接RGB屏和Wi-Fi,SDMMC1基本废掉。而SDMMC2的引脚(PB8-PB15 + PC6-PC12)在ZI封装里属于“冷门区域”,旁边没挂什么高优先级外设,布线清爽,干扰小。更重要的是,SDMMC2有自己的独立AHB总线桥和DMA通道,不会和SDMMC1抢带宽——这点在H7跑FreeRTOS多任务时特别致命。我实测过:当SDMMC1在读SD卡(DMA搬运),SDMMC2同时收Wi-Fi包,丢包率<0.1%;反之若强行共用SDMMC1,Wi-Fi吞吐直接掉30%,因为AHB总线仲裁器开始“拉偏架”。

至于SPI?88W8801确实支持SPI模式,但官方驱动只给Linux内核用,裸机SDK里压根没SPI例程。而且SPI速率上限通常卡在20MHz,实际有效带宽不到15Mbps,而Wi-Fi n模式下,单个TCP流轻松跑到40Mbps。你让SPI扛这个量,等于让自行车驮着集装箱上高速——不是不行,是每公里都在掉零件。SDIO的4-bit并行传输+命令响应机制,天然适配Wi-Fi的突发数据包特性,命令帧(CMD)和数据帧(DATA)分离,主控不用时刻轮询状态,靠中断+DMA就能搞定,CPU占用率压到5%以下。

2.2 88W8801选型背后的“老派智慧”

现在满大街推ESP32-C3、RTL8720DN,为啥还要碰88W8801?三个硬理由:第一,射频一致性。88W8801的PA/LNA匹配电路是Marvell原厂调校的,参考设计里PCB叠层、阻抗控制、天线馈点都写得明明白白,我们抄板一次就过EMC Class B;而很多国产Wi-Fi芯片,你得自己调匹配网络,光一个S参数仿真就折腾两周。第二,固件可控性。88W8801的Wi-Fi固件(.bin文件)是分模块的:bootloader、phy firmware、mac firmware,你可以单独升级mac层而不动phy,这对OTA安全更新太友好了。第三,协议栈轻量化。它内置ARM9协处理器跑完整802.11协议栈,主控只需处理socket API层,连ARP、ICMP这些底层包都不用管——STM32H7的RAM省下来跑你的AI推理模型,不香吗?

当然,它也有代价:没有蓝牙,不支持Wi-Fi 6,SDK体积大(完整版20MB)。但如果你的场景是“稳定联网+低功耗待机+工业环境”,88W8801的成熟度碾压一堆新锐芯片。我拿它和ESP32对比过温漂:-40℃到85℃全温区,88W8801的接收灵敏度波动<1dB,ESP32模组直接飘3dB——这对远距离抄表就是生死线。

2.3 SDIO协议栈的“三层楼”架构

理解这个项目,必须拆开SDIO协议栈的“三层楼”:物理层(PHY)、协议层(Protocol)、驱动层(Driver)。物理层是SDMMC2外设本身,负责生成CLK、CMD、DAT0-DAT3信号,处理CRC校验、超时重传;协议层是88W8801内部的SDIO Host Controller,它把Wi-Fi命令(比如SCAN、JOIN)翻译成SDIO寄存器操作;驱动层才是我们写的代码,它用HAL库配置SDMMC2,再按Marvell的SDIO Spec发命令帧。很多人栽在第二层——以为发个CMD52读寄存器就完事,其实88W8801要求特定的“Function 1初始化序列”:先CMD0复位,CMD8检测电压,ACMD41上电,CMD2读CID,CMD3设RCA,CMD7选中卡,最后CMD5通知Function 1准备就绪。漏一步,Wi-Fi芯片就躺在那儿装死。这个序列不是猜出来的,是抓SDIO总线波形实测确认的,我用Saleae Logic8录过200ms窗口,逐bit对过时序。

3. 核心细节解析与实操要点

3.1 硬件连接:那些藏在Datasheet角落的“坑”

原理图设计阶段,最容易翻车的不是主芯片,而是那几根SDIO线。先说最关键的CMD线:它必须接10kΩ上拉电阻到VDD_SDIO(注意!不是VCC,是SDIO专用电源,H743ZI需单独使能VDDSDIO引脚)。我见过三个项目在这里翻车:第一个项目没接上拉,CMD线始终低电平,SDMMC2初始化直接超时;第二个项目上拉接到3.3V,但VDD_SDIO是1.8V,结果电平不匹配,通信错乱;第三个最绝——上拉电阻用了100kΩ,导致上升沿拖沓,在50MHz时钟下边沿模糊,示波器上看就像毛刺。正确做法:查H743ZI Reference Manual第12章,VDD_SDIO必须由内部LDO提供1.8V,上拉电阻严格用10kΩ,且PCB走线越短越好,避开高频数字线。

DAT0-DAT3四根数据线,别忘了加100nF去耦电容到地。这不是防噪,是解决“信号反射”。SDIO在4-bit模式下,数据速率等效于200Mbps,信号边沿时间<1ns,PCB走线超过3cm就成天线。我在4层板上实测:DAT线长度4.2cm,没加电容时眼图张开度仅60%,加了电容后提升到92%。还有个隐形陷阱:88W8801的SDIO接口支持1.8V/3.0V双电压,但H743ZI的SDMMC2只支持1.8V模式!必须在初始化前,通过CMD11(SWITCH_VOLTAGE)命令切换到1.8V,否则后续所有通信都是乱码。这个命令在HAL库里没有封装,得手写SDIO_SendCommand()调用,参数cmdindex=11, arg=0x00000001。

3.2 时钟配置:别让50MHz变成“50MHz幻觉”

SDMMC2的时钟源看似简单,实则暗藏玄机。H743ZI的SDMMC2时钟来自PLL1_Q,但PLL1_Q输出频率范围是100-500MHz,而SDMMC2输入时钟最大只能是100MHz(手册明确写着“Maximum input clock frequency: 100 MHz”)。所以你不能直接把PLL1_Q设成100MHz喂给SDMMC2,因为SDMMC2内部还有分频器。正确路径是:PLL1_Q输出200MHz → SDMMC2预分频器(CLKDIV)设为2 → 实际输入时钟100MHz → 再经内部分频得到SDIO_CLK。但问题来了:SDIO_CLK要跑到50MHz,意味着内部分频系数必须是2(100MHz / 2 = 50MHz)。这个值写在SDMMC2->CLKCR寄存器的CLKDIV域,但HAL库的MX_SDMMC2_SD_Init()函数默认设的是0,即不分频——结果SDIO_CLK=100MHz,超频!Wi-Fi芯片直接拒收。

解决方案:在HAL_SD_Init()之后,手动修改CLKCR寄存器。代码片段如下:

// 关闭SDMMC2时钟 __HAL_RCC_SDMMC2_CLK_DISABLE(); // 手动设置CLKDIV=2 SDMMC2->CLKCR &= ~(SDMMC_CLKCR_CLKDIV); // 清零原有分频 SDMMC2->CLKCR |= (2 << SDMMC_CLKCR_CLKDIV_Pos); // 写入分频系数2 // 重新使能时钟 __HAL_RCC_SDMMC2_CLK_ENABLE();

这个操作必须在SDMMC2初始化完成、但尚未发送CMD0之前执行。我踩过坑:把它放在MX_GPIO_Init()之后,结果HAL_SD_Init()内部又把CLKDIV刷回0,白白浪费3小时调试。

3.3 初始化序列:从“卡未响应”到“Wi-Fi就绪”的17步

88W8801的SDIO初始化不是HAL_SD_WaitResponse()能搞定的,它是一套精确到微秒的“仪式”。我把它拆成17个原子步骤,缺一不可:

  1. 硬件复位:拉低88W8801的RESET_N引脚10ms,再拉高;
  2. SDMMC2使能:调用HAL_SD_Init(),但此时不发任何命令;
  3. CMD0发送:发送GO_IDLE_STATE,等待R1响应(0x01);
  4. CMD8探测:发送SEND_IF_COND,参数0x000001AA,验证电压支持;
  5. ACMD41上电:发送APP_CMD(CMD55)+ SEND_OP_COND(ACMD41),循环等待busy bit(R1的bit7)置1;
  6. CMD2读CID:获取芯片唯一标识,校验是否为88W8801(CID[119:104]应为0x4D52,ASCII "MR");
  7. CMD3设RCA:分配相对地址,我固定用0x0001;
  8. CMD7选中卡:激活该RCA对应的卡;
  9. CMD5送SDIO命令:发送IO_SEND_OP_COND,参数0x00FF8000,请求SDIO功能;
  10. CMD52读SCR:读取SDIO功能寄存器,确认Function 1存在;
  11. CMD52写BUS_WIDTH:向Function 1的0x0000寄存器写0x02,启用4-bit模式;
  12. CMD6切总线宽度:发送SWITCH_FUNC,参数0x00FFFF01,正式切换;
  13. CMD52读CIS:读取Card Information Structure,获取Wi-Fi固件加载地址;
  14. CMD52写HOST_CTRL:向Function 1的0x0002寄存器写0x01,使能Host Control;
  15. CMD53块读固件:用CMD53从0x00000000地址开始,分块读取Wi-Fi固件(.bin文件);
  16. CMD5复位Function:发送IO_ABORT,清空Function 1状态;
  17. CMD52查READY:轮询Function 1的0x0000寄存器,bit0=1表示Wi-Fi就绪。

每步之间都有最小延时要求,比如CMD55和ACMD41之间至少1ms,CMD53块读之间至少10us。这些延时不是拍脑袋定的,是Marvell SDK里的usleep()硬编码值,抄错一个,整个链路就断在第12步。

4. 实操过程与核心环节实现

4.1 固件加载:把.bin文件塞进Wi-Fi芯片的“胃”里

88W8801的固件加载不是“烧写”,而是“内存映射式注入”。它的内部RAM分三段:Boot ROM(固化)、Download RAM(临时加载区)、Runtime RAM(运行区)。我们用CMD53写入的.bin文件,首256字节是Header,包含校验和、入口地址、段长度,后面才是真正的固件镜像。关键点在于:Header里的“Download Address”必须和88W8801的Download RAM起始地址对齐。查Marvell AN-88W8801-SDIO-RefDesign.pdf,这个地址是0x00000000,但实际写入时,CMD53的地址参数要左移8位(因为SDIO地址粒度是256字节),所以实际写入地址是0x00000000 << 8 = 0x00000000。

我写了个固件加载函数,核心逻辑如下:

uint32_t load_firmware(uint8_t *fw_data, uint32_t fw_size) { uint32_t addr = 0; uint32_t offset = 0; SDMMC_CmdInitTypeDef cmd; while (offset < fw_size) { // 计算本次传输长度(最大512字节) uint32_t len = (fw_size - offset > 512) ? 512 : (fw_size - offset); // 配置CMD53:写Function 1,地址addr,长度len cmd.Argument = (1 << 28) | (addr << 9) | len; // bit28=write, bit9-27=address, bit0-8=length cmd.CmdIndex = SDMMC_CMD53; cmd.Response = SDMMC_RESPONSE_SHORT; cmd.WaitForInterrupt = DISABLE; cmd.CPSM = ENABLE; HAL_SD_SendCommand(&hsd2, &cmd, 100); if (HAL_SD_GetCmdResponse(&hsd2) != 0x00) return 1; // DMA传输数据 HAL_SD_ReadBlocks_DMA(&hsd2, &fw_data[offset], 0, len/4, 100); HAL_SD_PollForRequest(&hsd2, 100); offset += len; addr += len; } return 0; }

这里有个魔鬼细节:cmd.Argument的构造。Bit28必须为1表示写操作,地址字段(bit9-27)要右移8位再填入,因为SDIO地址是以256字节为单位的。我最初没右移,结果固件写到错误地址,Wi-Fi芯片启动后直接报“Invalid header”,抓波形发现CMD53的Argument字段全是0,debug半天才发现是移位运算写错了。

4.2 Wi-Fi连接:从扫描到IP获取的“五步连招”

固件加载成功后,Wi-Fi芯片进入AT指令模式(实际是Marvell私有协议,但封装成AT风格)。连接流程如下:

  1. AT+INIT:初始化Wi-Fi模块,返回OK;
  2. AT+WIFI?:查询当前Wi-Fi状态,确认已就绪;
  3. AT+WSCAN:触发扫描,返回AP列表(SSID、RSSI、Channel);
  4. AT+WJOIN="MyNet","12345678":连接指定SSID和密码;
  5. AT+DHCP?:获取IP地址,返回类似+DHCP:192.168.1.100,255.255.255.0,192.168.1.1

难点在第3步:AT+WSCAN返回的数据是不定长的JSON格式,比如{"ap":[ {"ssid":"Home","rssi":-45,"ch":6}, {"ssid":"Office","rssi":-62,"ch":11} ]}。你不能用简单的strstr()找"ssid",因为中间可能有转义字符。我的方案是写个轻量JSON parser,只解析顶层ap数组,用状态机识别{、[、"ssid"、":"、字符串边界。代码不到200行,但比用第三方JSON库省下8KB Flash。

第4步的密码处理更要小心:88W8801要求密码必须是ASCII字符串,且长度在8-63字节之间。我遇到过客户用中文密码“密码123”,Wi-Fi芯片直接返回ERROR,因为UTF-8编码后首字节是0xE4,超出了ASCII范围。解决方案:在AT+WJOIN前,用strlen()校验密码长度,并用isprint()检查每个字符是否为可打印ASCII。

4.3 数据透传:TCP Client模式下的DMA双缓冲实战

Wi-Fi连接成功后,最常用的是TCP Client透传。88W8801提供socket API,但裸机环境下,我们必须自己管理socket生命周期。我采用DMA双缓冲机制,避免CPU频繁拷贝:

  • Buffer A:接收Wi-Fi数据,DMA填充;
  • Buffer B:发送应用数据,DMA推送;
  • 当Buffer A满(或收到完整TCP包),触发HAL_SD_RxCpltCallback(),将数据交给应用层处理;
  • 应用层处理完,把响应数据填入Buffer B,调用HAL_SD_TxData()启动发送。

关键参数:Buffer大小设为1460字节(以太网MTU减去IP/TCP头),这样每个DMA传输刚好是一个TCP段。如果设成1024,可能一个TCP包被切成两段,增加解析复杂度;设成2048,则浪费内存且DMA中断频率降低,实时性变差。我实测过不同Buffer大小对ping延迟的影响:1460字节时平均延迟3.2ms,1024字节时升到4.7ms,差距明显。

还有一个隐藏优化:Wi-Fi芯片的TCP ACK延迟。默认情况下,它会等200ms才发ACK,导致TCP窗口卡住。解决方案是在AT+TCPCONFIG指令中设置delay_ack=0,强制立即ACK。这个参数在Marvell SDK文档第7章,但HAL库里没暴露,得通过AT指令串口发送。

5. 常见问题与排查技巧实录

5.1 典型问题速查表

问题现象可能原因排查步骤解决方案
SDMMC2初始化超时,HAL_SD_Init()返回HAL_TIMEOUTCMD线上拉缺失或电压错误用万用表测CMD引脚对地电压,应为1.8V;查原理图上拉电阻是否为10kΩ补焊上拉电阻,确认VDD_SDIO电源使能
初始化卡在CMD8,返回R1=0x00SDIO时钟超频示波器测SDIO_CLK引脚,确认是否≤100MHz修改CLKCR寄存器,设置正确CLKDIV
固件加载后Wi-Fi无响应,AT指令无返回Function 1未正确使能用逻辑分析仪抓CMD52写0x0002寄存器的波形,确认data=0x01检查CMD52写入地址和数据,确保bit0置1
TCP连接成功但无法收发数据TCP窗口关闭或ACK延迟抓Wi-Fi芯片UART输出,看是否有"+TCP:CLOSED"日志发送AT+TCPCONFIG="delay_ack=0"关闭ACK延迟
多任务下Wi-Fi掉线,FreeRTOS任务切换异常SDMMC2中断优先级过低查NVIC_SetPriority(SDMMC2_IRQn, 5),确认优先级数值小于其他外设将SDMMC2_IRQn优先级设为3(数值越小优先级越高)

5.2 我踩过的三个深坑及独家解法

坑一:SDIO总线上的“幽灵噪声”
现象:Wi-Fi连接稳定,但大数据传输时偶发CRC错误,错误率约0.5%。示波器看CLK和CMD线都很干净,毫无异常。
排查:用频谱分析仪扫PCB,发现2.4GHz频段有尖峰,强度-45dBm,正好是Wi-Fi信道1的中心频率。根源是SDIO的CLK信号谐波落在2.4GHz,通过PCB走线辐射出去,被Wi-Fi天线接收,形成自干扰。
解法:在SDMMC2的CLK输出引脚(PB8)串联一个33Ω磁珠,不是电阻!磁珠在100MHz以上阻抗陡增,能吸收谐波而不影响基波。实测后CRC错误归零。

坑二:“假连接”陷阱
现象:AT+WJOIN返回OK,AT+DHCP也返回IP,但ping不通网关。Wi-Fi芯片UART日志显示+WJOIN:success,但实际没关联AP。
根因:88W8801的WJOIN命令有“快速失败”机制——如果AP密码错误,它会立即返回ERROR;但如果AP存在但信号极弱(<-90dBm),它会假装连接成功,然后在后台默默重试,此时DHCP拿到的是虚拟IP(169.254.x.x)。
解法:在AT+WJOIN后,必须加一句AT+WSTATUS,读取真实连接状态。返回+WSTATUS:connected才算真成功,否则要等3秒再查。

坑三:FreeRTOS下SDMMC2的DMA锁死
现象:系统跑FreeRTOS,Wi-Fi任务和LED闪烁任务并发,某次Wi-Fi收包后,整个系统卡死,JTAG连不上。
诊断:用SEGGER RTT查看任务状态,发现Wi-Fi任务卡在HAL_SD_ReceiveBlocks_DMA(),而DMA中断服务函数没执行。
真相:SDMMC2的DMA中断(SDMMC2_IRQn)和Wi-Fi UART的中断(USART3_IRQn)被设成了相同优先级,FreeRTOS的临界区保护失效,DMA中断被UART中断抢占,导致DMA传输永远完不成。
修复:严格分级——SDMMC2_IRQn设为3,USART3_IRQn设为5,所有外设中断优先级不得相同。并在HAL_SD_RxCpltCallback()里加portYIELD_FROM_ISR(pdTRUE),确保中断退出后能切回高优先级任务。

5.3 性能调优:从“能用”到“好用”的临门一脚

最后分享一个让吞吐翻倍的技巧:调整TCP MSS(Maximum Segment Size)。88W8801默认MSS是1460,但H743ZI的以太网PHY(如果接了)MTU是1500,Wi-Fi链路实际MTU是1460。如果不匹配,TCP会频繁分片。我的做法是在AT+TCPCONFIG中设置mss=1440,留出20字节余量防抖动。再配合FreeRTOS的TCP/IP栈(如lwIP),把netif->mtu设为1440,这样从应用层到Wi-Fi芯片,数据流全程无分片。实测TCP上传速度从8.2Mbps提升到11.7Mbps,提升43%。

另一个容易被忽视的点:Wi-Fi芯片的电源管理。88W8801有PS-Poll(Power Save Poll)模式,但默认关闭。在电池供电场景,开启它能让Wi-Fi芯片在空闲时自动休眠。指令是AT+PSPOLL=1,但必须在AT+INIT之后、AT+WJOIN之前发送,否则无效。我帮一个手持终端客户启用后,待机电流从12mA降到2.3mA,续航从8小时延长到36小时。

这个项目做完,我最大的体会是:嵌入式开发里,没有“银弹”,只有“螺丝刀”。STM32H743ZI和88W8801都不是新玩意,但把它们用SDMMC2拧在一起,需要的不是炫技,而是对每个寄存器、每条时序、每个电平的敬畏。那些写在Datasheet角落的注释,往往就是成败的分水岭。

本文还有配套的精品资源,点击获取

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

MODBUS协议从原理到调试实战:帧格式、寄存器与CRC详解

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

作者头像 李华
网站建设 2026/9/5 10:31:03

UE5 Python自动化:资产批处理与编辑器工具开发

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

作者头像 李华
网站建设 2026/9/5 10:19:34

未来一月内 TikTok 推新:60 秒语音评论+评论区投票、多图功能!

TikTok 下月推评论新玩法&#xff1a;语音、投票与多图齐上阵未来一个月内&#xff0c;TikTok 将有一系列新功能上线。用户将能够录制 60 秒的语音备忘录用于发表评论&#xff0c;打破了以往只能文字评论的局限。同时&#xff0c;评论区还会引入投票功能&#xff0c;让用户可以…

作者头像 李华
网站建设 2026/9/5 10:16:15

MCP Server接入指南:让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/9/5 10:15:39

大型演唱会多机位剪辑全流程:从代理工作流到最终渲染输出

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

作者头像 李华
网站建设 2026/9/5 10:15:18

谷歌为 Gmail、Docs 和 Keep 推 AI 语音助手,移动操作更便捷!

谷歌为办公应用注入 AI 语音交互新活力谷歌正在为 Gmail、Docs 和 Keep 推出由人工智能驱动的语音助手模式——Gmail Live、Docs Live 和 Keep Live&#xff0c;让用户能通过语音与这些应用交互并实现管理操作。这一功能与谷歌聊天机器人的 Gemini Live 体验类似&#xff0c;方…

作者头像 李华