尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

调试实战指南:从软件到硬件的全方位排错技巧

调试实战指南:从软件到硬件的全方位排错技巧 不知道你有没有过这种经历一个bug在测试那边稳定复现你一到工位它就装死或者代码翻来覆去看了三遍逻辑上完全没问题可程序就是跑不出预期结果。这种时候大部分人第一反应是怀疑编译器、怀疑库、怀疑操作系统最后实在没辙了怀疑是不是硬件坏了。我在嵌入式、后端、上位机开发几个方向都摸爬滚打过今天这篇调试实战指南就是把我这些年跟bug搏斗的招数、踩过的坑、用过的好用工具一次性整理出来。不搞虚的全部是能直接用在你项目里的实战经验。这篇东西适合谁如果你是刚入行、每次遇到bug都手忙脚乱的初级开发它可以帮你建立一套自己的排错思路如果你是写了不少代码但总觉得调试靠运气的同学它能让你把调试变成一件有条理、可重复、可交付的工程化工作。无论你手里是STM32这类单片机还是跑着Linux的高性能板子或者干脆是纯软件的Web服务这套方法论都能套得上。1. 调试思维先定位再修复很多新手拿到bug第一件事就是改代码这是最大的误区。调试的本质不是让代码立刻变对而是搞明白“为什么不对”定位到根因之后再动手。我在带新人的时候反复强调一句话动手改之前先把你对问题的理解写下来。写不出来说明你还没定位到根因。1.1 复现问题是调试的第一步复现不了的问题就不能叫问题只能叫“灵异现象”。所以接到任何一个bug我做的第一件事永远是完整记录复现路径操作了什么、输入了什么数据、当时的环境参数是什么、页面上显示什么、日志里报什么。这里有个关键点——复现路径一定要精简到最小集合。举个例子我之前调一块板子上的UDP通信现象是收发数据偶尔乱码。一开始复现路径特别复杂要开三个线程、定时发数据、再叠加温度变化才能触发。后来我花了两天把场景一步步简化最后发现只要在一个循环里连续发送100包特定长度的数据每发一包sleep 1毫秒就必现乱码。最小复现路径一旦确定根因就很快浮出水面——是接收端的缓冲区处理逻辑对半包和粘包处理不严谨而不是最开始怀疑的网络芯片驱动问题。如果我一直抱着原始复杂场景去查可能在错误方向上不知道要转多久。还有一点复现次数很重要。我一般的标准是至少稳定复现三次以上才认为找到了触发条件。如果概率很低比如一百次出现一次那就要考虑是不是时序竞争、内存泄漏或者外部干扰导致的问题这类问题后面会专门讲。1.2 二分法缩小问题范围的核心手段调试界有一句名言计算机科学有两个难题一个是缓存失效另一个是命名。我觉得还应该加上一个——不知道bug在哪一段。面对一个大系统如果毫无头绪地从头翻代码效率极低。我用的最频繁的定位方法就是二分法。具体操作思路是这样的问题现象发生在功能链路的末端那么我就在链路的中间位置打一个检查点或者加一条日志看这个中间点的数据是否正常。如果正常说明问题在后半段如果不正常说明问题在前半段。然后继续在前半段或后半段再取中点重复下去。这个方法在排查一个几千行的模块时尤其高效理论上你只需要十几次检查就能把问题缩小到一个函数甚至一行代码的范围内。比如之前调试ifup-eth脚本的一个bug现象是某些机器上重启网络后路由表异常。我当时没有盲跳脚本而是在脚本里用二分法加echo打点分别打印文件解析结果、路由添加命令执行前后状态很快就定位到是配置文件中网卡名长度超过了一个隐藏的缓冲区上限导致后续命令拼接出错。这种问题靠肉眼读脚本几乎不可能发现。1.3 日志是调试的“记忆”调试器能让你看当前的现场但很多问题只有运行过程积累的信息才能暴露出来。我现在做任何项目第一步就是把日志系统搭好这不是多余的工程洁癖而是给未来省时间。日志的关键不是“有”而是“有用”。我常年遵守几条约定日志必须带时间戳精确到毫秒否则遇到时序问题你根本没法比对。日志中必须打印关键变量名和值而不是笼统地打一句“处理失败”。区分日志级别DEBUG用于开发期详细输出INFO记录关键步骤ERROR记录异常状态生产环境默认关闭DEBUG级别免得日志量爆炸。重要的用户操作和网络请求必须有唯一标识串联起来。举个例子调试两个设备之间的通信问题如果双方日志都带毫秒时间戳你把两份日志按时间轴对齐马上就能看出是谁的消息晚到了、谁的消息根本没发出去。而如果日志都是裸文本那基本只能靠猜。后面我会专门讲怎么让VS这类工具把调试信息同时输出到日志文档和窗口显示。2. 软件调试从IDE到命令行的实用套路软件调试场景最丰富从简单的print大法到断点单步再到远程调试和性能剖析不同场景用不同工具。这一小节我按工具讲都是我自己用顺手的方案。2.1 IDE断点调试把断点当成“探针”用大多数时候我们面对的是桌面端或后端代码IDE调试是最直观的手段。无论你用VS、CLion还是Dev-C核心思路都是那几件事设断点、看调用栈、看变量值、单步跟踪。这里我想强调一个很多教程不会细讲的点断点类型。普通断点只是暂停在那一行但条件断点、日志断点才是真正节省生命力的东西。比如你在一个循环里想捕获某个变量等于特定值时的状态如果手动按F5让它跑几千次循环效率太低。直接在断点条件里写上value 0x3F调试器会在满足条件时才停下来一击即中。日志断点则是断点不暂停只是往输出窗口打一条信息这个在不想打断高频循环、又想观察趋势的时候特别有用。用Dev-C调试还有个小坑很多人装了之后发现断点无效其实是因为编译时没有开启调试信息。Dev-C需要在“工具-编译器选项”里加上-g参数并且在编译时选择Debug模式否则断点根本命中不了。当年我实习时第一次用Dev-C查一个链表问题时断点怎么都进不去后来才发现是默认的Release模式浪费了半个下午。调试时最容易忽略的窗口是调用堆栈。当程序突然跑到一个不该去的地方或者崩溃时调用堆栈直接告诉你“我是被谁调进来的”。有一条非常实用的经验不要往下看先看栈顶。崩溃现场栈顶的两个函数基本上就是凶手。2.2 GDB命令行调试服务器上的救命稻草很多时候我们要调试的程序跑在Linux服务器上没有图形界面这时候gdb就是唯一靠谱的伙伴。很多人在服务器上只能靠加日志来排查问题其实学会了GDB很多场景根本不用加日志。我整理的GDB最常用命令大概就这十几个命令作用使用频率break/break 函数名/break 文件:行号设置断点极高info breakpoints查看断点列表高run启动程序运行到断点极高next单步执行遇到函数不进入极高step单步执行遇到函数进入高finish运行到当前函数返回高print 变量名打印变量值极高display 变量每次停下都自动显示变量高backtrace / bt查看调用栈极高info locals查看当前函数局部变量高watch 变量监视变量值改变时暂停中continue继续运行到下一个断点高thread apply all bt查看所有线程调用栈极高这里我想重点说两个使用场景。第一个是段错误Segmentation fault。遇到这种崩溃直接gdb ./程序然后run程序崩溃后输入bt栈顶就是导致崩溃的函数。大多数情况下从这里你立刻能定位到是空指针解引用还是数组越界。第二个是多线程调试gdb默认只停在当前线程输入info threads可以查看所有线程thread 编号切换到指定线程thread apply all bt一次性查看全部线程的调用栈。多线程死锁排查靠这个命令能省大量时间。还有一个小技巧给GDB装上peda或者pwndbg插件调试体验会好很多它会自动高亮寄存器、栈内容显示反汇编信息。虽然不是每个环境都允许装额外插件但能用的时候体验差距真的很大。2.3 远程调试和无线调试摆脱数据线的束缚嵌入式或Android开发中调试器没法直接跑在目标设备上所以远程调试是刚需。以Android为例adb是核心工具但很多新人不知道Android Studio是可以无线连接调试的。我常用的Android无线调试步骤是这样的先用USB连接手机和电脑确保adb devices能识别到设备。然后执行adb tcpip 5555让设备在5555端口开启无线调试再查看手机的IP地址执行adb connect 手机IP:5555最后断开USB线就能继续调试了。这里有个坑手机IP地址必须在同一局域网内而且如果手机系统是Android 11以上还需要在开发者选项中单独开启“无线调试”并配对。另外无线调试的端口默认是5555有些同事问我怎么固定端口其实adb tcpip命令后面跟的参数就是端口你指定成固定的就行比如adb tcpip 6666。只是注意每次手机重启后需要重新设置一次。再说CLion调试同一项目多个目标程序这个我也经常用。CLion的调试配置里选择“Edit Configurations”可以创建多个运行目标每个目标指定不同的可执行文件和参数调试时下拉切换目标即可。这样做的好处是比如同一套代码编译出客户端和服务端两个程序你可以在CLion里同时启动两个调试会话左边断点停在服务端接收函数右边断点停在客户端发送函数两端同时看问题一目了然。2.4 让调试信息既上屏幕又落日志有时候我们需要把调试信息同时输出到实时窗口和持久化日志文件。VS里有个很实用的做法使用OutputDebugString输出调试信息再用DebugView工具实时捕获同时用Trace监听器把信息写入文件。在代码里加入这样一段配置在程序启动时初始化Trace.Listeners.Clear(); Trace.Listeners.Add(new TextWriterTraceListener(debug.log)); Trace.Listeners.Add(new DefaultTraceListener()); Trace.AutoFlush true;这样Trace.WriteLine和Debug.WriteLine的信息会同时进入VS输出窗口和debug.log文件。我排查线上偶发问题时常用这一招——让现场同事把日志文件发过来不用我盯着屏幕照样能拿到完整现场。原则就一个调试信息不怕多就怕丢了上下文。再说一个npm生态里很常见的问题。很多前端同学在安装依赖时遇到过error: cannot find native binding. npm has a bug related to optional dependencies这样的报错。这个问题主要是因为npm在安装原生模块时对可选依赖的处理存在缺陷。我的经验是先执行npm cache clean --force清理缓存删除node_modules和package-lock.json然后重新安装。如果还不行就把package.json里不需要的可选依赖移除或者改用npm install --no-optional跳过可选依赖的安装。我用npm已有六七年这个报错在旧版本npm上触发的频率明显更高升级npm的LTS版本也是一个有效的规避手段。3. 硬件与嵌入式调试串口、调试器与现场实践软件调试再难好歹你能看到代码、设断点。硬件调试难度直接上一个台阶因为你看不到内部执行过程只能通过外部引脚、通信接口和指示灯去推断内部状态。我刚开始做嵌入式时最崩溃的就是程序“莫名其妙”不工作后来发现大部分时候不是芯片在捣乱而是调试手段没用对。3.1 串口调试助手嵌入式调试的一等公民串口是嵌入式系统调试最基础的通道而SSCOM、Commix这两款串口调试助手几乎是圈内默认的工具。用法不难——选择正确的串口号、设置波特率、打开串口然后就能收发数据了。但实际使用中有几个细节是新手容易忽略的第一波特率必须与目标设备一致。这个看起来是废话但我见过太多人拿着9600的助手去读115200设备发来的数据满屏乱码还以为是硬件坏了。第二注意HEX显示和字符显示的切换。如果双方是以原始字节通信的建议用HEX显示模式否则遇到不可见字符显示会花掉。第三很多串口调试助手支持定时发送和文件发送调试上下位机协议时用定时发送模拟周期上报配合时间戳功能能很直观地看到响应延迟。我常用Commix的一个原因是它的“显示发送”功能可以同时显示发送出去的原始字节和接收到的数据在做协议调试时极其重要。有一次我调一块STM32的模组上位机发数据后设备一直不回包折腾了一上午。后来开着Commix的HEX发送模式和显示发送才发现我的发送数据里带了一个前面加进去的换行符0x0A设备端协议解析严格多一个字节都不认。用串口助手能看到完整的字节流这种小到肉眼难查的问题一下就暴露了。如果你在调PID这类控制算法我强烈推荐VOFA这个上位机工具。它支持协议解析和波形显示你用串口按固定格式把目标值、当前值、输出值发上来它直接画出曲线。调PID时曲线比任何文字日志都直观——你可以看着超调量、稳定时间去拧Kp、Ki、Kd参数而不是一遍遍打印数据然后自己在脑子里画折线图。3.2 STM32调试从硬件坑到软件坑STM32系列是嵌入式开发绕不开的芯片围绕它的调试经验和坑也特别多。先说硬件层面的经典问题STM32F103的PA11引脚。这个引脚默认复用功能是USB D-很多人把它当普通GPIO用结果发现怎么配置都不对。排查思路要清晰——先去参考手册看这个引脚是否有默认复用功能或JTAG占用。实际上不止PA11PA13、PA14、PA15和PB3、PB4这几个引脚默认被JTAG调试接口占用如果复用为GPIO必须先把对应调试端口关闭。比如GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE)就是关闭JTAG只保留SWD的经典操作。另一个常见坑是调试器和目标板连接不稳定。很多人用J-Link或ST-Link给STM32下载程序时偶尔出现连接不上。这个问题八成是复位引脚被外部电路拉低或者调试线太长导致信号质量差。我的习惯是把SWDIO和SWCLK两根线尽量控制在10厘米以内并接上地的杜邦线这样基本不会再出现“擦除失败”的情况。软件层面Keil调试时最让我受益的功能就是“逻辑分析仪”。在Keil中调试模式下通过View-Analysis Windows-Logic Analyzer可以打开它添加变量之后就能看变量波形变化。我调过一次I2C通信的时序问题通过逻辑分析仪窗口同时观察SCL和SDA的电平变化曲线立刻发现SDA在某个字节的第九个时钟沿数据保持时间不够于是把代码里的I2C延时微调了一下就解决了。如果不借助这个工具我大概只能拿示波器慢慢戳引脚。还有一个STM32环境下的PA11问题如果芯片已经锁死或引脚冲突你可以用ST-Link Utility把Flash整体擦除后再重新烧写。注意做这一步之前要确认有备份否则原来固件里如果有校准数据或生产信息擦了就找不回来了。3.3 变频器与专用控制器调试参数化调优的系统方法除了单片机和PC工业现场的设备调试也有自己的套路。比如120系列变频器的调试本质上是一套参数化配置的过程。我第一次调变频器时面对几十个参数一脸懵后来摸清了逻辑变频器调试的核心是按“电机参数→运行参数→控制方式→保护参数”的顺序配置。首先要做电机自学习也叫参数辨识这时候要把电机额定电压、额定电流、额定频率、额定转速这几个参数填准然后让变频器自动测出定子电阻、转子电阻这些内部参数这是后续矢量控制性能的基础。接着设置运行参数包括加速时间、减速时间、运行频率上下限。加速时间设太短电机会过流报警设太长设备启停效率低。一般先用默认值跑起来再根据现场负载惯量微调。具体到120变频器有几个参数我特别提醒一下上限频率和下限频率务必根据实际机械结构设置防止设备超速启动频率建议设定在0.5Hz到1Hz之间太低启动无力太高启动冲击大转矩提升参数在低速重载场合要谨慎调高太高会让电机过热。蓝德控制器这类专用设备的调试思路也类似。以电动车辆控制器为例它的参数包括电流环比例、速度环比例、限流值、刹车回馈强度等。这里的经验是每次只改一个参数改完记录初始值再做一次完整的运行测试。因为多个参数之间是耦合的同时改两个出现问题后你根本不知道是谁导致的。3.4 高性能嵌入式平台的调试场景现在不少项目开始用性能更强的处理器跑Linux系统比如RK3568调试摄像头、复旦微Z7系列FPGAARM平台、甚至自己编译和调试主线内核。这类平台的调试传统串口和调试器依然重要但思维要切换到系统层。以RK3568调试OV5695这颗摄像头传感器为例常见问题是I2C访问不到设备。排查步骤通常是这样的先确认I2C总线上拉电阻是否有焊接问题再用i2cdetect命令扫描设备地址看能不能探测到OV5695的I2C地址。能探测到但初始化失败就抓取内核日志看寄存器配置是否正确连地址都探测不到那大概率是硬件连接或供电问题先拿万用表量电压和时钟线不要急着改驱动代码。调试内核或底层驱动出问题时我习惯printk配合GPIO引脚模拟逻辑分析仪来定位时序问题。这个方法听着土但确实管用——在一次调试某平台MIPI信号时我在驱动各个关键节点翻转一个空闲GPIO然后示波器观察很快确认了信号在哪一步断了比反复猜驱动配置快得多。另外提一句如果自己编译主线内核磁盘空间不够是常见问题。一个带调试信息的内核加上模块和构建中间文件二三十G都是常事。解决方案是构建时在/build目录或者专门挂一块大分区并且注意make clean和make mrproper的区别——前者清除编译产物后者连配置文件一起清掉别在根分区上堆太多旧内核源码。4. 网络调试两台电脑通信问题定位方法网络调试在项目联调阶段占比巨大。我现在做一个新的网络应用第一步永远是先拿网络调试助手验证协议再启动自己的代码。这样能先确认链路是通的、协议是对的然后才轮到代码背锅。4.1 网络调试助手实战流程拿最经典的两台电脑UDP通信场景举例。同事A的电脑作为服务端监听某个端口同事B的电脑作为客户端往A的IP端口发数据用网络调试助手就能测通。但也会出现“连不上”的问题这时候我通常按以下顺序排查先检查两台电脑是否在同一个网段。ipconfigWindows或ifconfigLinux看一下IP地址如果不在同一网段先改IP或者网关。用ping命令测试基本连通性。能ping通说明二层三层链路是通的问题在协议层或端口ping不通就回到物理层和IP配置排查。查防火墙。Windows的防火墙经常拦截UDP数据包尤其是非系统常用端口。排查时可以临时关闭防火墙测试确认是防火墙问题后再添加入站规则放行。确认服务端的绑定地址。非常多人在这里掉坑——服务端只绑定了127.0.0.1外部IP来的包根本进不来。要绑0.0.0.0才能接受所有网卡的数据。有一次我帮同事排查一个UDP收不到数据的问题上面四步都查过没问题最后发现是公司无线网络的“AP隔离”功能把客户端之间的二层通信隔离开了。两台电脑虽然连在同一个Wi-Fi下但互相ping不通。解决办法是改成有线连接或换一个支持关闭AP隔离的网络环境。接下来说TCP通信和UDP的一个本质区别TCP是有连接的你有一个握手过程任何一步失败都能明确看到。UDP则不同发出去的数据如石沉大海你根本不知道对方收没收到。所以在调UDP协议时建议协议的响应机制要设计好接收方收到数据后必须回一个ACK包发送方一定时间收不到ACK就判定丢包。这不仅是产品逻辑问题也是调试时能确认链路是否正常的关键设计。4.2 固定无线调试端口前面提到了Android无线调试其实通用Wi-Fi调试还会遇到一个问题设备IP地址是DHCP动态分配的重启后可能变化。固定调试端口的方法本质上是让设备开启一个固定的监听端口然后通过路由器做IP和MAC绑定来固定局域网IP。针对Android开发的话可以给adb tcpip 5555端口设置端口重定向——如果你的设备连接的是电脑共享的网络可以直接在电脑上用adb forward tcp:5555 tcp:5555把设备5555端口映射到本地这样即使设备IP变了本地调试端口也能保持稳定。对嵌入式Linux设备固定调试端口我一般写一个开机自启脚本里面执行nc -lk 端口或者启动一个sshd服务再把设备MAC地址在路由器里做IP绑定。这样只要你拿着那台路由器设备每次开机IP都是固定的网络调试起来省心很多。4.3 从硬件接网线到SPI/I2C总线的调试再说一个很多人忽略的调试思路——用接网线的方式来调试高性能板卡。有很多FPGA开发板和ARM核心板调试口例如UART、JTAG、Ethernet就在板载网口旁边用一条网线就能把调试信息接到宿主机上。如果通过串口服务器或者调试板卡还能实现远程串口调试不用每次蹲在机柜旁边拿笔记本捅串口线。I2C和SPI这类板内总线的调试除了用逻辑分析仪还有一个低成本方案用一个便宜的单片机或树莓派写脚本模拟对端设备。比如你在调一个传感器的I2C驱动手头没有传感器硬件时可以先用一个跑着I2C从机模拟程序的Arduino板子来充当传感器把设备地址和关键寄存器响应都模拟出来。这样主控的驱动开发就不用等硬件到位而且还能随心所欲地制造异常场景比如故意不ACK、故意延迟响应来测试主控驱动的健壮性。这个技巧在项目前期联调中帮了我很多次。5. 借助AI和自动化工具让调试效率再翻一倍这几年我明显感觉调试工作方式在发生改变尤其是AI辅助编程工具成熟以后很多以前靠人肉翻代码才能找到的问题现在可以先让AI帮你扫一遍。5.1 用AI扫描代码中的潜在bug和设计缺陷很多同学觉得AI只能写代码其实让AI做代码审查能力也很惊艳。我现在的常用操作是把一个模块的关键代码完整复制给AI然后明确告诉它“帮我找这个模块中可能存在的空指针、数组越界、资源泄漏、并发竞争问题并分析设计是否合理”。这里有个使用技巧——不要只给代码片段要把数据结构定义、关键函数的输入输出约定、以及上下文环境话说清楚。比如你给一段多线程代码就要说明哪些变量是共享的、锁的保护范围是什么这样AI才能给出有价值的分析而不是泛泛而谈。我曾在一次AI审查中它指出我的代码里有个检查数组下标上限的分支逻辑顺序错误会导致在某些边界情况下访问越界。这个bug当时测试没跑出来但代码逻辑上确实存在隐患修复后程序健壮性明显提升。需要说明的是AI审查不能替代人工审查更不能不经过验证就把它的结论当作真理。AI给出的结论最终都要回到代码和实际运行中确认。用一句话总结我的体会就是AI是帮我们发现疑点的助手而不是最终裁判。5.2 用自动化补上调试的最后一块短板人最大的不可靠因素就是会忘记和会忽略。所以我这些年调试的经验之一是把验证工作尽量自动化。比如每次修复完一个bug除了确认现象消失我会立刻补一条对应的自动化测试用例防止回归。这不只是写单元测试通信协议的可以用脚本发一组典型包然后比对接收数据嵌入式驱动的可以写一个开机自检的测试固件把关键外设初始化后自动跑一遍读写和校验。我在做STM32相关项目时会维护一个专门用于产线测试的固件它上电后自动扫描各个外设把结果通过串口打印出来。这样每次拿到新板子或者怀疑硬件异常时只要烧上这个测试固件就能快速判断问题在硬件还是软件。这个习惯帮我省去了大量手工测量和猜测的时间。5.3 硬件调试中的“武器库”推荐既然这篇是实战指南最后把工具盘点一下都是我自己用着顺手的工具/软件适用场景我的使用建议SSCOM / Commix串口通信调试必装打开即用注意HEX/字符显示切换VOFAPID调参、曲线可视化串口数据直接出波形调PID神器网络调试助手UDP/TCP联调先于业务代码验证协议J-Link / ST-LinkSTM32等嵌入式MCU调试配合Keil、STM32CubeIDE使用注意线长GDBLinux服务端/嵌入式Linux调试学好bt、print、watch服务器上格外好用逻辑分析仪I2C/SPI/UART时序分析百元级的就能满足多数调试场景比示波器便宜、好用AI编程助手代码审查、找bug疑点给全上下文结论必须人工复核6. 常见问题排查技巧实录调试做了这么多年有些问题反复在团队里出现。我把高频问题整理成了一份速查表遇到类似现象直接照着查能少走很多弯路。现象可能原因排查方向串口收到乱码波特率不匹配、地线没接好、发送端携带多余字节核对波特率检查HEX显示用示波器看UART波形单片机连不上调试器复位引脚被拉低、SWD线太长、芯片被锁检查复位电路缩短线长用烧录器执行全片擦除UDP能发出但收不到防火墙拦截、绑定地址错误、AP隔离、端口未监听按ping→防火墙→绑定地址→网络隔离顺序排查程序间歇性崩溃内存越界、栈溢出、多线程竞争用GDB配合bt看崩溃点用watch盯关键变量开启AddressSanitizer重编译设备I2C扫描不到地址上拉电阻缺失、供电异常、地址错误、总线挂死万用表量供电和电平i2cdetect扫描必要时复位从设备npm安装原生模块报native binding错误npm optional dependencies缺陷、缓存损坏清理缓存删node_modules重装或用--no-optional跳过Android无线调试连不上未开启无线调试、IP变化、USB端口没设置确认开发者选项重新adb tcpip确认同一局域网变频器过流报警加减速时间过短、负载惯量大、电机参数未辨识增大加减速时间先做电机自学习再微调转矩提升板卡跑Linux启动卡死内核崩溃、设备树错误、rootfs损坏用串口console看内核日志检查设备树dmesg报错再分享一个我吃了亏才总结出来的习惯做任何底层硬件或驱动调试时每一次启动测试前都要记录当前硬件状态和改动点。我用一个简单的文本文件记录内容包括修改了哪个文件、改了什么参数、测试结果是什么。很多时候你排查到半夜突然发现下午改的那个延时导致了新问题如果没有记录你可能要重新试错一遍才能想起来。养成记录的习惯之后调试过程会变得高度可追溯效率提升不是一点半点。7. 写在最后的一点个人体会如果让我用一个词总结调试这件事我会选“耐心”。不是那种“慢慢来不着急”的耐心而是“反复验证、绝不猜”的耐心。我见过太多工程师调了好几天bug最后发现是自己一开始设想的方向就错了前功尽弃。所以每次开始调试前我会强迫自己回答三个问题这个bug第一次出现是什么时候我的改动和它有没有时间相关性有没有可能是我改坏了的这三个问题虽然简单却能在关键时候把我拉回正确轨道。另外一个小技巧始终受用当你实在找不到根因时试着向别人完整地描述这个问题。很多时候你描述到一半自己就发现了盲点。我们组里管这个叫“橡皮鸭调试法”意思是找一只橡皮鸭把问题从头到尾讲给它听讲着讲着你就有灵感了。这不是搞笑是真的有用因为人在复述过程中会把模糊的直觉变成明确的思路而bug往往就藏在那些被想当然忽略掉的细节里。调试能力不是天生就有的是靠着一次一次踩坑、一次一次复盘长出来的。希望这篇指南让你少踩一些我踩过的坑哪怕只是帮你省下半天查日志的时间那这篇文章就值了。
返回列表