资讯详情

资讯详情

嵌入式看门狗故障排查指南:从复位原因到实战避坑

简介面向嵌入式开发者这是一份国民技术N32G45X系列微控制器ADC与DMA结合应用的完整例程包重点演示ADC1多路采集配合DMA直接存储器访问实现无中断连续数据传输适合需要掌握高性能数据采集与低CPU占用传输方案的工程师参考学习。压缩包共97个文件以52个h头文件和37个c源文件为主辅以工程配置文件、hex烧录文件以及bin、lib等文件整体仅566KB目录按HARDWARE、CMSIS、USER等模块划分清晰。已有864人学习下载。例程完整呈现ADC通道选择、采样时间设置以及DMA通道配置、源地址与目标地址规划等关键代码并说明环境监测、传感器数据采集等应用场景可直接移植到实际项目中帮助开发者快速搭建N32G45X高效数据采集系统。1. 看门狗常见问题排查这就是那个让亚洲第一中锋头疼的“倒计时陷阱”围绕“看门狗常见问题排查”这个主题核心是理清一个矛盾看门狗WDT本应是嵌入式系统的最后防线但在实际项目中它却常常成为“误复位”和“漏复位”的根源。很多时候程序跑飞了它没动作程序正常它反而把系统重启了。这篇文章要解决的就是这类问题——为什么看门狗会在关键时刻掉链子以及当它“乱咬人”时你该怎么按图索骥找到病因。看门狗的常见问题主要集中在几个层面配置不当、喂狗逻辑缺陷、中断与低功耗模式的干扰以及芯片本身的特殊行为。本文会从这些实际案例出发先讲清楚看门狗的内部工作机制再拆解几种典型的故障现场最后给出我可以直接抄用的隐患排除步骤和参数调整建议。这篇笔记适合正在被复位问题折磨的嵌入式工程师也适合准备在新项目里使用看门狗但还没想清楚“怎么喂才安全”的开发者。2. 看门狗与系统复位的关系先搞懂“咬人”的物理过程2.1 独立看门狗与窗口看门狗的区别与选型要排查问题先得知道你用的是哪种“狗”。独立看门狗IWDG和窗口看门狗WWDG虽然都叫看门狗但工作方式和失败模式完全不同。独立看门狗是一个自由运行的递减计数器它只关心你“有没有喂”不关心你“什么时候喂”。只要你在它归零之前重载计数值它就认为系统活着。窗口看门狗则更苛刻它不仅有“最晚喂狗时间”还有一个“最早喂狗时间”。喂得太早也不行因为这说明程序执行顺序可能乱了要么是跳过了关键流程要么是中断把主线逻辑挤掉了。我一般会在项目里用独立看门狗做“粗粒度”的系统级保护专门对付程序跑飞和死循环用窗口看门狗做“细粒度”的任务执行顺序校验比如某段关键代码必须在规定时间窗口内完成并且完成喂狗。两种狗混用的时候最怕的就是喂狗位置重叠或冲突导致窗口看门狗因为独立看门狗的喂狗动作而误判。选择哪种狗取决于你的系统对“时序异常”的敏感度。2.2 复位信号的产生路径与标志位排查看门狗问题第一步不是改代码而是看复位标志。几乎所有的MCU在复位后都会在RCC或复位控制寄存器里留下“复位原因”。有一次我在现场帮某公司排查设备频繁重启的故障现象是设备运行十几分钟就重启一次看起来毫无规律。我远程指导对方读了复位状态寄存器发现是独立看门狗复位标志位置1这就直接锁定了问题方向——跟电源、跟时钟都没关系就是狗在咬人。复位标志位的读取要放在程序的最早期比如启动文件里或main函数最开始的地方。如果等系统初始化跑了一圈再读某些单片机的标志位可能被硬件自动清掉或者被你的初始化代码误清除。我习惯的做法是在上电第一时间保存标志位到一个全局变量然后该清除的清除该记录的记录最后通过串口或调试器把复位原因打印出来。没有这个习惯排查复位问题就像闭着眼找东西。2.3 独立看门狗的硬件行为与时钟来源独立看门狗一旦启动除了复位没有任何办法把它关掉。这是它最可靠也最“狠”的地方。它通常使用专用的低速内部时钟LSI这个时钟不依赖主时钟。所以即使主晶振停了只要芯片内部还在供电独立看门狗依然在走。这个特性在排查问题的时候要特别注意你可能把主时钟源查了个底朝天却没意识到看门狗的计时基准根本没受影响。在实际项目里LSI的精度并不高不同温度、不同芯片之间LSI的频率可能有百分之十几的偏差。这意味着你在数据手册上看到的“最长时间”只是理论值实际要短一些。配置看门狗超时时间的时候我一般会留出30%到50%的余量。比如我需要保证系统能在100毫秒内喂狗那超时时间至少设置到150毫秒甚至200毫秒否则LSI频率偏快的时候正常喂狗都可能来不及这就会造成“明明程序没跑飞却不断复位”的假象。3. 看门狗误复位的典型原因为什么好端端的程序被“误杀”3.1 中断里的喂狗操作与优先级反转新手最常见的错误就是把喂狗放在中断服务函数里然后以为万事大吉。这种方式在低中断频率下看起来没问题但一旦中断优先级配置不当或者中断本身被更高优先级的中断长时间阻塞喂狗就会被无限期推迟。更隐蔽的情况是你把喂狗放在了一个低优先级的中断里而系统里存在一个高优先级的中断频繁触发导致低优先级中断长时间得不到执行看门狗自然就饿了。正确的做法是把喂狗放在主循环的“主流程”中而不是放在中断里。如果项目必须要用中断喂狗那也要确保这个中断的优先级足够高并且中断服务函数执行时间极短。我见过有人在ADC中断里喂狗结果ADC触发的频率因为DMA配置问题突然降低系统十几毫秒没进中断狗就咬了。这类问题排查起来特别费劲因为代码看起来“逻辑正确”——确实在喂狗但喂得太晚了。3.2 低功耗模式下的看门狗行为与唤醒源冲突低功耗模式是看门狗误复位的重灾区。很多MCU在进入停机模式或待机模式后独立看门狗还在运行而你的代码可能没有在唤醒后第一时间恢复喂狗。更麻烦的是如果你的唤醒源是一个外部中断而外部中断的触发频率不稳定那么从“进入低功耗”到“唤醒并喂狗”之间的时间间隔就可能大于看门狗的超时时间。我接手过一个低功耗报警器的案例设备平时睡眠每五分钟醒来采一次数据。为了省电睡眠时主时钟关闭看门狗却还开着。结果设备经常在唤醒过程中复位。原因就是唤醒后的时钟启动需要时间而喂狗代码放在了时钟稳定之后这一来一回超过了看门狗极限时间。解决办法是把喂狗动作提前到“刚从睡眠中被唤醒但还没做任何初始化”的时候先把狗喂饱再慢慢做时钟切换和外设恢复这样可以保证无论如何唤醒都会先喂狗一次。3.3 调试器暂停导致的看门狗复位用仿真器在线调试的时候如果设置了断点程序会暂停但看门狗不会暂停。这是一条铁律也是很多工程师从一开始就被坑到怀疑人生的地方。明明跑着没问题一进调试模式停了十几秒去看变量然后继续运行程序立刻复位。这不是你的代码有毛病纯粹是调试行为触发了看门狗。应对办法有两个。第一调试期间在初始化代码里临时屏蔽看门狗启动等调试完再打开但这个办法容易忘记恢复所以我会在代码里做一个宏开关控制。第二利用调试器自带的“调试时暂停看门狗”功能但不是所有MCU都支持这个功能而且要确认你的调试器驱动版本支持。还有一点有些MCU的独立看门狗即使在调试模式下也无法冻结这种情况下就只能用宏控制。这种问题不算代码逻辑错误但却是很多人排查很久后发现“啥都没改自己好了”的原因。4. 看门狗漏复位的场景程序死了它却没动作4.1 喂狗位置放在主循环末尾的缺陷误解之一只要在主循环里喂狗程序跑飞就一定能被复位。现实是很多跑飞是“局部跑飞”比如某个函数内部陷入死循环但中断还在正常工作主循环可能永远不会回到喂狗那一行。这种死循环如果在某个被中断打断的状态机里那看门狗完全不起作用因为喂狗代码可能刚好在死循环的后面而死循环发生在前面。更常见的漏复位场景是程序在一个“逻辑错误的分支”里自我循环。比如你写了一个while等待某个标志位这个标志位因为别的原因永远等不到那程序就卡死在这一行如果喂狗在while之后那就永远喂不了。解决办法是把喂狗做成一个独立的“任务”比如使用一个定时器中断每次中断里将喂狗标志位置1主循环只需要检测标志位标志位没置位就说明主循环被卡住了。我习惯叫这个“两级看门狗方案”——硬件看门狗负责最终兜底软件看门狗负责检查任务级的健康状况。4.2 独立看门狗无法检测的任务级故障硬件看门狗本质上只能检测“喂狗代码是否被执行”它无法区分“程序正常跑在非喂狗分支上”和“程序卡死在某个任务里”。一个常见的漏复位场景是一个后台任务在等待一个永远不会到来的消息队列。因为此时主循环里的喂狗代码仍然在正常执行硬件看门狗认为系统是健康的但实际系统的核心功能已经瘫痪。这时候独立看门狗形同虚设。这种情况下需要引入“任务级看门狗”也就是软件看门狗。做法是为每一个关键任务设置一个独立的计数器主循环定期检查这些计数器的数值一旦发现某个任务长时间没有更新计数主循环就主动触发系统复位。注意触发复位的方式建议使用NVIC的系统复位请求而不是直接调用某种“软复位”函数这能保证所有外设都经历完整的复位流程。这套机制能很好地弥补硬件看门狗“只管喂没喂”的盲区。4.3 时钟异常与看门狗计时的安全隐患还有一种漏复位现象比较隐蔽看门狗的时钟源没问题但系统主时钟出了问题导致整个程序的执行速度变慢。程序本身的逻辑还在正常跑喂狗也在正常喂但某个需要精确时序的外设比如PWM输出或通信波特率已经因为时钟异常而变得完全不可用。如果只看门狗没有复位系统就会带着一个“半残”的身体继续运行看起来好像没什么问题实际功能早已崩溃。这种情况要配合时钟安全机制一起使用。很多MCU内置时钟安全系统当外部晶振失效时可以自动切换到内部高速时钟同时产生一个中断。在中断里记录故障并做对应的降级处理必要时主动复位。我一般在处理这种系统时会把“时钟故障中断优先级”设置为最高同时在看门狗喂狗代码里增加一个对系统时钟状态的检查一旦发现时钟切换事件发生过就主动触发一次复位。这算是比“纯看门狗”更高一层但对实际产品稳定性的提升非常明显。5. 看门狗排查的实操步骤从无头绪到定位问题的清单5.1 第一步检查复位标志位来判断复位来源拿到一个频繁复位的设备不要急着看代码。先确认复位原因。以下是以ARM Cortex-M内核为例的检查方法其他内核思路一样只是寄存器名不同。/* 复位原因判断代码 - 适用Cortex-M0/M3/M4 */ uint32_t reset_cause 0; void check_reset_cause(void) { /* RCC时钟控制寄存器里的复位标志位 */ if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) ! RESET) { /* 独立看门狗复位 */ reset_cause | 0x01; RCC_ClearFlag(); /* 清除标志位 */ } if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) ! RESET) { /* 窗口看门狗复位 */ reset_cause | 0x02; RCC_ClearFlag(); } if (RCC_GetFlagStatus(RCC_FLAG_PORRST) ! RESET) { /* 上电复位 */ reset_cause | 0x04; RCC_ClearFlag(); } if (RCC_GetFlagStatus(RCC_FLAG_PINRST) ! RESET) { /* 外部引脚复位 */ reset_cause | 0x08; RCC_ClearFlag(); } /* 根据reset_cause的值打印或记录不同的复位原因 */ }这段代码的关键在于reset_cause这个变量能永久保留复位的来源哪怕后面系统初始化把寄存器的标志位清了这个变量的值还在。我在项目里会把这个变量通过串口发送到上位机或者存进一片专门的Flash区域方便后续回溯。注意读取标志位要趁早因为有些库函数在SystemInit阶段就把标志位清了你再去读就什么都读不到了。5.2 第二步用IO翻转法测量喂狗的时间间隔不给看门狗“定罪”也不急着“翻案”。先将喂狗代码临时屏蔽掉然后在喂狗的位置翻转一个GPIO用示波器或逻辑分析仪测量这个GPIO的脉冲间隔。这个间隔就是当前代码的“实际喂狗周期”。拿到这个周期之后你才能科学地设置看门狗超时时间。/* 用GPIO测量喂狗周期 - 临时调试用 */ void feed_dog_debug(void) { /* PB1用于示波器观察 */ GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_SET); /* 拉高 */ /* 正式的喂狗操作屏蔽IWDG */ /* IWDG_ReloadCounter(); */ GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_RESET); /* 拉低 */ }跑一段时间后观察PB1的波形正常情况下应该是间距基本一致的脉冲串。如果发现某些脉冲之间的间隔突然变大说明那段代码的执行时间出现了异常波动这就是看门狗容易“误咬”的时间点。这个方法的优势在于不改变程序的执行行为只是增加了一个IO翻转动作适合在线上定位。注意GPIO的翻转本身会带来微秒级的延迟对毫秒级的喂狗周期影响可以忽略不计。5.3 第三步测量从复位到第一次喂狗的时间复位后到第一次喂狗之间的时间窗口是另一个关键隐患点。如果这个时间窗口超过了看门狗超时时间系统就会在启动过程中不断复位表现为“反复重启永远进不了主循环”。这种情况的上电波形特征是电源正常复位引脚上有周期性脉冲。排查方法是先在main函数最开始的地方喂一次狗确保启动过程中就能满足看门狗的要求。如果连这一点都做不到说明启动代码太长需要精简初始化流程或者把看门狗启动时间往后推但这样会带来一段无保护的空窗期很不安全。我一般会确保复位后系统在1毫秒内完成第一次喂狗然后再做其他初始化。特别是那些需要等待外部晶振稳定的系统等待期间如果不喂狗狗咬人的概率极高。6. 看门狗配置参数与代码实现把超时时间算到“刚刚好”6.1 独立看门狗超时时间计算公式与配置独立看门狗的超时时间由两个参数决定预分频器和重装载值。公式很简单超时时间 (预分频系数 × 重装载值) / LSI频率。这里的LSI频率在不同芯片上不一样常见的是32kHz到40kHz之间要查对应的数据手册确认。很多工程师看手册不看LSI的精度范围只用典型值计算结果做出来的产品批量生产后总有那么几台会异常复位。/* 独立看门狗初始化 - 目标超时时间约1秒 */ void IWDG_Config(void) { /* 使能写访问到IWDG寄存器 */ IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); /* 设置预分频器为64分频 */ IWDG_SetPrescaler(IWDG_Prescaler_64); /* 设置重装载值为625单位是LSI时钟周期 */ /* 实际超时时间 (64 * 625) / 40000 1秒 */ /* 如果LSI实际为36kHz则实际超时时间为1.11秒 */ IWDG_SetReload(625); /* 重装载计数值 */ IWDG_ReloadCounter(); /* 启动独立看门狗 */ IWDG_Enable(); }这里的坑在于“625”这个数字不是随便定的它是根据LSI典型值40kHz反推出来的。如果LSI实际频率偏低实际超时时间会变长看门狗的“灵敏度”就会下降反之则变短。我经过几次翻车之后学乖了把超时时间设定为“期望值除以0.7”意思是就算LSI偏快30%也不会在正常喂狗周期内误触发。再配合实际测量喂狗周期余量就能控制得比较舒服。6.2 窗口看门狗的上窗口与下窗口配置窗口看门狗比独立看门狗多了一个“上窗口”的概念。窗口看门狗的计数器从0x7F往下递减你必须在计数器递减到窗口值之后、递减到0x3F之前完成喂狗。喂早了算违规喂晚了也算违规。这个窗口值决定了“最早能喂狗的时间点”一旦你的主循环执行速度变化较大这个窗口就要放宽。/* 窗口看门狗初始化 - 窗口值0x50超时时间约几毫秒量级 */ void WWDG_Config(void) { /* 使能窗口看门狗时钟 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); /* 设置窗口值为0x50计数器起始值0x7F */ WWDG_SetWindowValue(0x50); /* 使能窗口看门狗中断 */ WWDG_EnableIT(); /* 配置NVIC注意中断优先级要合理 */ NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel WWDG_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority 0; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure); /* 启动窗口看门狗重装载值为0x7F分频为8 */ WWDG_Enable(0x7F); /* 这个调用同时启动和重装载 */ }窗口值0x50意味着喂狗最早不能早于计数器从0x7F递减到0x50的时刻。如果系统启动后第一次喂狗发生在窗口值之前必然触发复位。这种问题在带RTOS的系统里特别容易出因为任务调度的不确定性导致喂狗时间抖动。如果遇到“跑一段时间后稳定复位”的情况优先怀疑窗口太窄想办法把窗口值调大而不是去缩小喂狗抖动。6.3 喂狗函数的最佳放置位置与策略最后说说喂狗代码本身怎么放。一句话总结喂狗位置要保证“所有正常执行路径都能经过它”同时“异常执行路径不能经过它”。这听起来简单做起来非常难。我一般会分三层处理。第一层是在主循环的固定位置无条件喂狗保证正常运行时的基本需求。第二层是在关键任务完成后喂狗比如通信数据处理完、传感器采集完这相当于报告这些任务健康。第三层是软件看门狗机制用独立的软件计数器记录各任务状态主循环统一检查。喂狗函数本身要短最好只是一个寄存器写操作不要带任何函数调用、不要加延时否则喂狗动作本身就可能成为性能瓶颈。/* 喂狗函数 - 只做一件事 */ void feed_dog(void) { /* 重装载独立看门狗计数器 */ IWDG_ReloadCounter(); /* 如果启用了窗口看门狗也要一起重装载 */ /* WWDG_Enable(WWDG_CFR_REG 0x7F); */ }注意这段代码里的窗口看门狗重装载我是注释掉的因为窗口看门狗的重装载通常要配合窗口判断如果你没有十足的把握当前的计数器值在合法窗口内贸然重装载反而可能触发复位。实际项目中我更倾向于只使用独立看门狗窗口看门狗留到那种对任务执行时序有刚性要求的场合再用。单独用独立看门狗时这个函数就是唯一与硬件交互的接口排查问题的时候只需要监视这个函数被调用的频率和时机信息量非常集中。7. 看门狗排查的避坑指南与实践建议这些坑我都替你踩过7.1 避坑一初始化看门狗后立即喂狗却仍然复位现象看门狗配置完成后紧接着调用重装载函数但系统依然周期性复位。原因某些MCU的独立看门狗启动后需要等待内部LSI时钟稳定如果你在时钟还没稳定时就执行重装载硬件可能不识别这次操作。这个问题在冷启动时特别明显因为芯片刚上电LSI还没进入稳定状态。解决在看门狗初始化函数里启动LSI时钟后等待LSI的稳定标志位被置位然后再执行重装载和启动看门狗。或者先不启动看门狗把初始化提前到上电启动阶段等时钟稳定后再启动。我遇到过一次厂商的库函数里压根没做等待LSI稳定的处理后来自己在初始化函数前面加了一个短暂延时搞定。7.2 避坑二调试模式下设置断点导致“随机”复位现象程序全速跑一切正常一进仿真模式设置一个断点停了一会儿继续运行就复位。原因独立看门狗在调试模式下不会自动暂停。断点一停CPU停了喂狗停了但看门狗还在跑超时一到就复位。这不是你的逻辑有问题是调试方式触发了保护。解决在代码里加一个调试宏仿真调试时禁止启动看门狗程序发布时才打开。这个宏开关要放在显眼的位置防止调试完忘记打开。/* 调试模式下屏蔽看门狗 - 发布时务必打开 */ #define WDT_DEBUG_DISABLE 1 void wdt_init(void) { #if (WDT_DEBUG_DISABLE 0) /* 正式代码才启动看门狗 */ IWDG_Config(); #endif }7.3 避坑三低功耗唤醒后看门狗“立刻”复位现象设备从低功耗模式唤醒后运行不到几十毫秒就复位。原因进入低功耗模式前喂狗周期被拉长到了看门狗超时极限。唤醒过程本身消耗了不少时间加上唤醒后要重新初始化时钟和总线这一段时间内完全没有喂狗等到代码终于走到喂狗位置时看门狗已经饿了很久了。解决在唤醒中断服务函数里的第一行代码就重新装载看门狗不要等到整个唤醒流程走完再喂。如果是从停机模式唤醒有些MCU会先执行中断服务函数再返回主循环利用这个中断函数你可以确保每次唤醒后先喂狗再干别的。7.4 避坑四喂狗函数被编译器优化掉导致意外复位现象程序逻辑看起来完全正确喂狗也在执行但看门狗就是复位。原因巧了有些编译器优化级别较高时如果你的喂狗函数只是对一个寄存器执行写操作而且没有任何返回值被使用编译器可能会认为这个操作没有实际效果从而将其优化掉。这个不是MCU的错编译器觉得“做了等于没做”就给你省了。解决把喂狗函数声明为volatile或使用特定的编译器屏障。最省事的做法是喂狗函数的参数和返回值都定义成volatile类型这样编译器就不会随便优化。或者直接把寄存器操作写成内联汇编一了百了。这里也是我个人的血泪经验那次排查了一个通宵最后反汇编看了一眼才发现编译器根本没生成写寄存器的指令。7.5 避坑五复位标志位在库函数初始化阶段被清除现象用调试器查看复位标志位的时候发现所有标志都是“无复位”但产品明明复位了。原因很多芯片的启动文件里会调用SystemInit函数这个函数会执行RCC寄存器初始化其中就包括清除复位标志位。你进main的时候已经晚了复位来源被洗掉了。解决如果你想保留复位原因不能依赖C库的启动流程。要把复位标志读取代码放到启动文件里直接在晶振初始化之前读取并保存到一个固定的全局变量。或者查看芯片的参考手册确认复位标志清除的具体时机调整自己的读取位置。8. 最后一步如何验证看门狗配置正确且长久可靠8.1 用钳形表或电流波形确认复位时的系统行为验证看门狗是否正常工作比看代码更重要的是看现象。我常用的手段是故意制造一个死循环把程序卡在一个while(1)里然后观察系统复位是否如期发生。如果复位了说明看门狗基本功能正常如果没复位那就需要回头检查配置。制造死循环的办法可以用一个调试开关控制正常产品代码里不要留这种后门。验证时给系统通电用示波器观察电源电流波形复位时电流会有明显的跌落过程。如果能稳定看到这个波形周期性出现说明看门狗确实在复位系统而且超时周期与你预期一致。8.2 长稳测试中的看门狗监控机制时间长的稳定性测试同样重要。我给设备做老化测试时会加一个外部监控脚本记录设备每次复位的时刻和运行时长。如果老化过程中出现了“非看门狗复位”比如上电复位或外部引脚复位那视野就要转移到供电和硬件设计上。看门狗能验证的不只是自己整个系统的健康状况都能从复位记录里看到端倪。养成一个好习惯每次做看门狗配置调整后都要重新跑一遍复位验证和长稳测试。千万不要只改一个延时参数就草率发布看门狗这个东西配置错了往往是批量性的问题。8.3 关于看门狗测试的一些个人习惯说一个我自己的习惯在新项目里我第一个写的模块就是看门狗然后才是时钟和外设。因为从项目一开始就有看门狗在盯着后续的开发过程中如果有谁也说不清原因的复位第一时间就能暴露出来。等代码框架逐渐完善再回头调整看门狗的超时窗口和喂狗策略。这样做前期会频繁被打断但长远来看能省掉不少后期集体排查的麻烦。另外要养成写测试用例的习惯。看门狗相关的测试不用很复杂几条就够正常运行时不复位、主循环卡死时复位、喂狗间隔超过极限时复位、低功耗唤醒后不复位。把这些测试固化下来每一次修改代码后都跑一遍。我见过太多项目因为改了一个优先级配置导致看门狗在特定场景下暴走有了这套回归测试这类问题基本能提前截住。这些是我调试看门狗问题时积累下来的实战经验有些坑是在项目交付前最后一刻才爬出来的代价不小。如果你也在被看门狗问题纠缠希望这篇文章里的排查思路和避坑清单能帮你省下几个加班的夜晚。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →