首页 / 资讯中心 / 文章详情

Keil软件仿真逻辑分析仪与串口调试实战指南

Keil软件仿真逻辑分析仪与串口调试实战指南 ★ FEATURED ARTICLE
做STM32开发手里没个逻辑分析仪有些问题真不好查。调PWM波形对不对、串口到底发了什么数据、延时时间准不准光靠万用表只能测个通断靠串口助手只能看到数据内容看不到时序细节。以前我也为这事儿头疼后来发现Keil软件仿真模式下就藏着一个逻辑分析仪不用接任何硬件直接在电脑上就能看到STM32管脚波形配合串口调试的虚拟串口窗口很多问题在没上板之前就能提前暴露。这篇内容适合几类人一是刚学STM32、手头连开发板都还没买但想先跑通代码逻辑的新手二是有开发板但缺示波器、逻辑分析仪这类硬件测试设备的同学三是想深入理解串口通信时序、顺便排掉调试路上各种坑的爱好者。我会把软件仿真模式下的逻辑分析仪从配置到实战完整过一遍最后再专门聊串口调试的避坑经验。1. 软件仿真是在干什么为什么值得先学会1.1 软件仿真和在线调试到底差在哪很多人一提到Keil调试第一反应就是接ST-Link下载器连上开发板在线调试。这个思路没错但前提是你手头得有板子、有下载器、有驱动。软件仿真则是另一条路它用PC的CPU去模拟ARM内核的指令执行芯片型号、内存映射、外设寄存器全都在电脑里模拟出来编译出来的hex或axf文件直接在这个虚拟的STM32里跑不需要任何真实硬件。在线调试是“真刀真枪”地控制芯片运行、读取变量、打断电软件仿真则相当于在PC上搭了一个虚拟机专门跑STM32的程序。两者都叫“调试”但侧重点完全不同。软件仿真的优势非常明显零硬件成本随时随地能跑可以反复复位、修改参数重来甚至能强制往寄存器里写值来模拟外设状态。这些在真实芯片上操作要谨慎得多但在仿真环境下可以随便折腾。它的局限也很好理解仿真器毕竟是模拟不是芯片本尊。外部中断信号、ADC真实采样电压、DAC模拟输出、下载器在线升级这些跟真实物理世界挂钩的东西仿真模拟不出来或者只能模拟个大概。所以我的建议是软件仿真适合验证逻辑和时序硬件调试负责验证电路和真实外设行为两者互补而不是互相替代。1.2 五分钟把Keil切到纯软件仿真模式把Keil从在线调试切换到软件仿真其实就几个步骤改完以后点一下调试按钮就能进去。打开你的Keil工程点击工具栏上的魔术棒图标也就是Options for Target。在弹出的窗口里切到Debug选项卡默认情况下Keil通常选的是右侧的UseULINK2/ME Cortex Debugger或者UseST-Link Debugger这个取决于你之前有没有配置过下载器。我们要做的是把选择改成左侧的Use Simulator。选完Simulator之后下方有两个输入框在Dialog DLL那一栏需要填DARMSTM.DLLParameter那一栏填-pSTM32F103C8。这里要注意后面的芯片型号参数必须跟你的实际芯片对应比如你用STM32F103C8T6参数就是-pSTM32F103C8如果你用的是STM32F407VGT6参数就是-pSTM32F407VG。填错了仿真可能起不来。配置项值说明UseSimulator选择纯软件仿真模式Dialog DLLDARMSTM.DLLSTM32仿真设备动态库Parameter-pSTM32F103C8指定仿真芯片型号按实际改Run to main()可选勾选进入调试后自动跑到main函数填好之后点OK保存然后点击工具栏上的Start Debug Session按钮那个带“D”的放大镜图标Keil就会启动仿真。如果工程配置正确几秒钟后就会进入调试界面代码停在main函数入口处。第一次进入仿真时如果芯片支持包没装好或者DLL设置不对会弹出错误提示最常见的是提示找不到device或者仿真启动失败这时候回去检查芯片型号和DARMSTM.DLL是否填对就行。1.3 仿真模式下哪些外设能用、哪些不能用进入仿真环境以后首先得搞清楚什么能玩、什么不能玩。GPIO访问完全没问题直接读IDR、写ODR都能反映到引脚状态上这也是我们后面用逻辑分析仪看波形的基础。定时器TIM基本上都能模拟计数器递增、比较匹配、PWM输出这些寄存器行为都跟真实芯片一致。USART串口也能模拟而且还能配合Keil的虚拟串口窗口看数据这部分后面细讲。SysTick、NVIC中断、外部中断EXTI的软件触发也都能用。但有些东西在仿真里就“失真”了。ADC虽然可以配置和读取寄存器但不会有真实电压输入寄存器值往往是一个固定初始值或者你自己强写进去的值。DAC也是同理没有真实模拟电压输出。看门狗IWDG在仿真环境下的时钟和复位行为不太靠谱经常不是你想测就能测的。外部引脚输入信号也没法用真实硬件触发想模拟外部脉冲得自己通过修改寄存器或者用信号激励的方式去搞。所以软件仿真最合适的场景是什么是验证GPIO翻转时序、PWM输出频率/占空比、串口初始化与数据收发逻辑、延时函数精度、状态机跳转这类纯逻辑或者纯软件层面的东西。把这些在仿真里跑通一遍再上板做硬件验证会省掉大量反复烧录、拔插杜邦线的时间。2. 逻辑分析仪窗口Keil自带的“示波器”怎么用2.1 打开逻辑分析仪并添加观察信号Keil的软件仿真模式里内置了一个逻辑分析仪窗口这是全篇最核心的功能。进入调试模式后在菜单栏找到View然后点开Analysis Windows里面有一项就是Logic Analyzer。不同版本可能菜单位置略有区别有些版本直接在View菜单下就有Logic Analyzer但本质是一样的。打开之后逻辑分析仪窗口是空白的默认没有信号。需要手动添加想要观察的引脚或变量。点击窗口左上角的Setup按钮会弹出一个配置面板里面有个信号输入框。这里输入信号名的格式有讲究观察GPIO引脚的时候最常用的格式是“PORT 端口字母 . 引脚号”比如想看PA6的波形就输入PORTA.6想看PB15的波形就输入PORTB.15。输入完点Add信号就加进来了。如果信号名输入错误Keil会直接报错提示当前设备不支持这个信号所以要仔细检查拼写和大小写。除了GPIO引脚还能添加变量名。比如你定义了一个全局变量想看它的变化趋势直接在信号框里输入变量名逻辑分析仪就会像画曲线一样把这个变量的值随时间变化的轨迹画出来。这个功能特别适合查看PID调节的输出量、温度采样的数值变化这类会缓慢变化的量。信号添加进来以后默认是以bit的方式显示只有0和1两种电平。如果想要看连续变化的模拟量可以右键信号把显示类型改成analog。时间轴的操作也需要注意。逻辑分析仪窗口的下方有缩放条和滚动条可以拉伸时间范围。刚添加完信号全速运行的时候波形可能飞快地闪可以等程序暂停下来再仔细看细节。暂停之后鼠标左键拖拽可以框选一段波形松开就能放大看右键拖拽可以移动显示窗口。这些操作跟电脑上的波形查看软件差不多摸索两下就熟了。2.2 用LED翻转程序验证第一张波形图光说不练容易忘先写一个最简单的GPIO翻转程序用逻辑分析仪看能不能画出方波。以常见的STM32F103系列为例用标准外设库写代码很短#include stm32f10x.h void delay(void) { uint32_t i; for (i 0; i 1000000; i); } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_2MHz; GPIO_Init(GPIOB, GPIO_InitStructure); while (1) { GPIO_WriteBit(GPIOB, GPIO_Pin_15, Bit_SET); delay(); GPIO_WriteBit(GPIOB, GPIO_Pin_15, Bit_RESET); delay(); } }编译通过后启动软件仿真在逻辑分析仪里添加PORTB.15然后点击全速运行。当程序跑起来以后你就能看到逻辑分析仪窗口里出现了一串方波高电平和低电平来回切换。点击暂停滚动时间轴可以看到一个完整的高电平和低电平周期。这里有个小技巧通过逻辑分析仪测量高电平的持续时间和完整周期可以反过来验证你的延时函数到底延了多久。如果你在delay函数里改不同的循环次数波形宽度会肉眼可见地变化这就是逻辑分析仪最基础的用途验证时序。2.3 波形不出来的常见原因用逻辑分析仪的时候不少人会碰到波形出不来或者波形一动不动的情况下面这些坑我都踩过现象常见原因排查方法波形一直平在高或低电平程序里的引脚没初始化检查GPIO时钟和模式配置确认已经配置为输出波形完全一条直线信号名写错或格式不对检查PORTA.6/PORTB.15这种格式别把A写成字母结尾波形不动程序处于暂停状态点击全速运行按钮让程序跑起来有波形但频率和预期差得多仿真时钟配置不同检查SystemInit是否把时钟配置成功PLL参数是否生效变量信号看不到优化级别把变量优化掉了在魔术棒里把优化等级调到-O0波形刷新太快看不清时间轴范围太小暂停后拖动缩放条或框选波形这里特别提一下优化的问题。Keil默认的优化级别是-O0但如果你之前为了体积改成了-O2或者-O3一些不使用的变量或者看似“无效”的代码可能被编译器直接删掉那逻辑分析仪里自然就观察不到变化。遇到这种情况最简单的办法就是把优化级别重新调回-O0等调试完了再调回去。3. 实战在仿真模式下观察PWM波形3.1 写一个定时器PWM输出程序GPIO翻转只是开胃菜用定时器产生PWM波然后通过逻辑分析仪观察才是真正的实战。这里用TIM3的通道1来输出PWM对应的引脚是PA6。#include stm32f10x.h void PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Prescaler 71; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period 99; TIM_TimeBaseStructure.TIM_ClockDivision 0; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse 49; TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC1Init(TIM3, TIM_OCInitStructure); TIM_Cmd(TIM3, ENABLE); } int main(void) { PWM_Init(); while (1); }为什么要这样配置这里面的每个参数都可以通过计算来验证。假设系统时钟是72MHzTIM3挂在APB1上因为APB1预分频器不是1所以定时器时钟是APB1的两倍也就是72MHz。预分频器TIM_Prescaler设为71分频之后计数时钟是72MHz / (71 1) 1MHz。自动重载值TIM_Period设为99所以计数从0计数到99一共100个计数周期PWM频率 1MHz / 100 10kHz。比较值TIM_Pulse设为49意味着计数器值小于等于49的时候输出高电平大于49的时候输出低电平占空比约等于50%。3.2 添加定时器通道引脚并观察波形代码写好之后启动软件仿真在逻辑分析仪里添加信号PORTA.6然后全速运行。正常情况下你会看到PA6上出现一个频率为10kHz的PWM方波。这里有个容易踩的坑如果程序里用了SystemInit并且里面配置了PLL把系统时钟倍频到72MHz但仿真环境下HSE外部晶振的启动可能不是那么真实有时候SystemInit会卡在等待HSE稳定那个环节。如果遇到这种现象要么修改SystemInit或者在main里重新配置时钟树要么直接将SystemCoreClock设为8MHzHSI内部时钟然后按照8MHz重新计算PWM分频参数。总之仿真时系统时钟到底是多少直接决定你看到的PWM频率。添加信号后如果PA6一直没有波形先检查GPIO是否配置成了复用推挽模式GPIO_Mode_AF_PP再检查TIM3的PWM输出通道是否正确。TIM3_CH1对应PA6如果你用的是TIM3_CH2那就得看PB5了。另外还要确保TIM_OCInitStructure里的TIM_OCMode确实设成了PWM1否则定时器可能只是普通比较输出波形表现完全不同。3.3 用波形反推频率和占空比是否正确看到波形之后暂停仿真利用逻辑分析仪的测量功能来验证参数对不对。逻辑分析仪窗口下方会显示鼠标当前位置的时间坐标通过拖拽测量游标可以框选一个完整周期的宽度。如果测量出的周期是100微秒也就是0.1毫秒那频率就是1 / 0.0001s 10kHz和理论计算完全一致。再测量高电平的持续时间假设测出来是50微秒占空比就是50 / 100 50%也完全对得上。这时候你可以在代码里把TIM_Pulse从49改成29重新编译、重新仿真观察波形PWM周期保持不变但高电平宽度明显变窄占空比约30%。这个实验能让你非常直观地理解占空比这个概念比死记公式记得牢多了。以后碰到实际问题比如调舵机角度、调电机转速、调屏幕背光亮度你都会下意识地想到这个波形变化的过程。4. 串口调试避坑指南从硬件到软件的问题排查4.1 接线和驱动串口调不通的第一道坎串口调试是嵌入式开发里最常用的调试手段但也是新手最容易卡壳的地方。很多人的代码逻辑没问题最后发现是接线错了或者驱动没装好白白折腾大半天。先说USB转TTL模块。市面上常见的CH340、CP2102、FT232芯片的USB转串口模块都需要安装对应驱动。驱动没装好设备管理器里就看不到正确的COM口串口助手自然连不上。驱动装好之后还要确认端口号。打开设备管理器找到端口COM和LPT记下实际的COM号然后在串口助手里选择对应的COM口。这里有个常见坑有些电脑插同样的USB口COM号会变每次插拔之后都要重新确认。接线是另一个大坑。STM32的TX要接外部设备的RXSTM32的RX要接外部设备的TX这个叫交叉连接。很多人按“同名相连”的习惯把TX接TX、RX接RX结果当然收不到。还有GND必须共地不接GND的话参考电平不同数据根本没法正常解析。如果你发现串口助手完全收不到数据优先检查这三个点TX和RX是否交叉、GND有没有接、共地是否可靠。还有一个电平问题要注意。STM32是3.3V的TTL电平如果你的USB转TTL模块只支持5V电平虽然很多模块标称兼容3.3V但稳妥起见最好用带3.3V电平输出的模块或者单独做电平转换。用RS232接口的设备就必须经过MAX3232这类电平转换芯片不能直接拿RS232线去怼STM32的引脚否则可能烧芯片。4.2 波特率和乱码数据能收到但不对如果你确认接线没问题、串口助手也选对了COM口但收到的数据是乱码或者数据内容不对那问题大概率出在波特率或者参数配置上。波特率不匹配会产生两种典型现象一种是完全乱码数据像外星文一样另一种是偶尔能看懂几个字符但中间夹着错码。前者往往是因为两边波特率差太多后者往往是波特率有微小偏差比如理论上应该配9600实际配成了9608符号率差一点点短时间还能勉强对上长时间就错位了。还有时钟配置的问题。STM32串口波特率是从外设时钟经过分频得到的如果系统时钟本身就不对波特率怎么配都是错的。比如你的开发板外部晶振实际是8MHz但代码里HSE_VALUE却定义成了12MHzPLL倍频出来的系统时钟就偏了串口波特率自然也跟着偏。最典型的现象就是程序里配的是9600串口助手也选9600但收到的还是乱码这时候去查晶振频率和HSE_VALUE是否一致多半能发现端倪。数据位、停止位、校验位也需要统一。STM32串口默认配置一般是8位数据、1位停止位、无校验串口助手也要选对应的8N1。如果你程序里配置了奇校验串口助手却选的是无校验收发就会出现间歇性错误。大流量数据收不全的坑也值得一提。如果发送端不停地发数据接收端的程序里又没有及时把数据读走串口接收缓冲区就会溢出数据直接丢掉。解决办法是提高接收处理效率或者启用硬件流控或者降低发送频率。另外一个高频问题是用printf发中文串口助手显示乱码这不一定是波特率的锅而是PC端的编码方式和你的源码编码不一致换成UTF-8或者GBK显示再试。4.3 Keil里用软件仿真调试串口输出的特殊姿势这部分是很多人不知道的骚操作。Keil的软件仿真模式下串口输出可以显示在一个虚拟串口终端窗口里不需要接任何真实的USB转TTL模块。进入仿真模式后在菜单栏找到View点开Serial Windows里面会有UART #1、UART #2等多个窗口。如果你的代码用的是USART1就打开UART #1窗口。当你运行程序代码执行到USART_SendData或者printf之后输出内容就会显示在这个窗口里。这个功能在没有开发板、没有串口模块的情况下依然可以学习串口初始化和数据发送逻辑。这里注意仿真模式下的串口数据是Keil的模拟器模拟的不是真实的物理串口所以电脑上打开XCOM、SSCOM这类串口调试助手指望它接收是不行的。虚拟串口窗口里的数据本质上是模拟器“画”出来的而不是真实电平转换出来的。这是一个很容易误解的地方但反过来也说明Keil仿真只负责验证你程序逻辑是否正确不负责跟真实硬件通信。用这个虚拟串口窗口调试时要特别留意窗口是否打开。如果窗口没打开模拟器可能不会缓存输出数据或者只是简单丢弃导致你打开窗口后也没看到之前的内容。正确操作是先打开UART #1窗口再让程序运行这样才能实时看到printf的输出。4.4 printf重定向与MicroLIB的坑串口调试里最常用的输出手段就是printf但STM32工程里默认的printf是往标准输出写的并不会自动走串口必须做重定向。重定向的代码一般在main.c里加#include stdio.h int fputc(int ch, FILE *f) { while (USART_GetFlagStatus(USART1, USART_FLAG_TC) RESET); USART_SendData(USART1, (uint8_t)ch); return ch; }这段代码的作用是每次printf要输出一个字符时其实是调用了fputc而我们改写fputc让它通过USART1把这个字符发送出去。注意fputc的返回值不能漏否则编译可能报错。重定向之后还要在魔术棒 → Target选项卡里勾选Use MicroLIB。这个选项使用精简版C库可以避免半主机模式引发的问题。很多人在没有勾选MicroLIB的情况下程序一执行到printf就死机或者直接跳进HardFault就是因为标准C库printf默认依赖半主机模式而STM32没有实现半主机环境。勾选MicroLIB是省事最有效的方案。但MicroLIB本身也有坑。用ARM Compiler 6的时候某些旧工程的重定向代码会跟新编译器产生兼容性问题编译报错或者运行不符合预期。我的习惯是如果某个工程从旧版本Keil迁移过来保持ARM Compiler 5编译稳定性更高。如果用AC6可能需要在重定向函数里做调整。另外一个常见问题是调用printf之前必须确保串口已经完成初始化和使能否则程序会卡在fputc里的while循环中死等现象就是程序好像停了。这个在仿真模式里很容易排查打开UART #1窗口如果卡住不动立刻检查串口初始化代码是不是没执行到。5. 进阶操作用逻辑分析仪“看”串口波形验证波特率5.1 添加串口TX引脚观察发送波形学会了逻辑分析仪和串口的基本调试现在就可以把它们结合起来用逻辑分析仪去观察串口的TX引脚波形从物理时序层面确认串口通信是否正确。以USART1为例TX默认映射在PA9RX在PA10。先写一个简单的串口发送程序初始化USART1以及PA9、PA10引脚然后通过printf发送一个字节0x55#include stm32f10x.h #include stdio.h void UART1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); USART_InitStructure.USART_BaudRate 9600; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART1, USART_InitStructure); USART_Cmd(USART1, ENABLE); } int fputc(int ch, FILE *f) { while (USART_GetFlagStatus(USART1, USART_FLAG_TC) RESET); USART_SendData(USART1, (uint8_t)ch); return ch; } int main(void) { UART1_Init(); printf(Hello); while (1); }进入仿真模式打开UART #1窗口可以看到Hello字符串输出。同时在逻辑分析仪里添加PORTA.9全速运行几秒钟后暂停你就能看到PA9上出现了一串复杂的脉冲波形。5.2 从波形上数出波特率的实操方法串口的波形是有固定格式的空闲状态是高电平发送开始时先拉低一个位的时间作为起始位然后依次发送数据位最后拉高一整个位的时间作为停止位。标准的8N1格式就是1个起始位 8个数据位 1个停止位。我们特意发送0x55这个字节它的二进制是0101 0101。串口发送数据时是低位先送所以真正在数据线上看到的顺序是1、0、1、0、1、0、1、0。配合起始位是低电平、停止位是高电平整个波形会呈现非常规律的方波切换。此时在逻辑分析仪里暂停仿真用鼠标测量相邻两个边沿之间的时间宽度。如果程序配置的是9600波特率那么每一位的时间宽度应该是1/9600秒约等于104微秒。如果你量到的位宽度是104微秒左右说明波特率正确程序里的USART_BaudRate确实生效了。如果你量出来的位宽度是52微秒那实际波特率就是19200如果是8.7微秒那就大约是115200。这里有一个完整的小计算假设逻辑分析仪里量到的位宽度是104us波特率 1 / (104 × 10^-6) ≈ 9615考虑到测量误差和9600的目标值基本吻合判定波特率配置正确。反过来如果你的系统时钟配置有问题比如HSE_VALUE和实际晶振不一致那么即使程序里写的USART_BaudRate是9600逻辑分析仪量出来的位宽度也会明显偏离104微秒这时候问题就指向时钟初始化和HSE_VALUE宏定义。5.3 这套方法还能用来查哪些问题学会了用逻辑分析仪看串口波形之后其实可以迁移到很多其他场景。比如你怀疑串口引脚是不是配置错了直接把对应引脚加进逻辑分析仪看看有没有数据翻转如果没有说明引脚配置和代码执行的路径可能有问题。再比如你要验证某个延时函数到底准不准可以让一个GPIO在延时前后翻转用逻辑分析仪量高电平持续的时间立刻就能看出偏差大小。这套方法还能用来观察外部中断的触发频率。假如定时器中断里翻转了一个引脚逻辑分析仪就能把这个引脚的翻转周期测出来对照定时器的中断周期迅速确认中断配置是否正确。SPI、I2C这类协议也能通过观察引脚波形来辅助理解时序比如I2C的起始条件就是SDA在SCL高电平时拉低这个波形在逻辑分析仪里看得一清二楚。不过要提醒一句软件仿真对I2C、SPI这类外设的模拟程度不如GPIO和USART那么完善有些外设在仿真环境里不一定能输出非常真实的波形。所以仿真逻辑分析仪主要用于验证GPIO时序、PWM输出、串口数据位宽度这类基础信号。真正复杂的外设时序还是需要真实硬件配合示波器或者实体逻辑分析仪来确认。仿真能帮你排查七八成逻辑问题剩下两三成硬件的坑交给实体设备去填。我在实际使用中发现用软件仿真逻辑分析仪最爽的场景其实是学习阶段。很多概念比如PWM占空比、波特率、起始位停止位看书上一堆文字解释不如亲眼在波形图上看一眼来得通透。调PWM的时候改一个参数波形立刻变这种反馈速度是真实硬件调试很难比的。所以我强烈建议初学者养成一个习惯写一个小功能先在软件仿真里跑一遍用逻辑分析仪看看波形用UART窗口看看输出确认逻辑没问题了再烧到板子上。这样做既安全又高效还能帮你把底层协议的细节吃透。
阅读完成 · 觉得有帮助?
咨询建站