常见软件调试问题及技巧
程序跑飞 / 死循环判断方式:
程序运行一段时间后无响应;
逻辑异常,变量值异常突变。
解决方法:
开启中断向量表定位 HardFault:在 HardFault_Handler 中添加调试代码打印栈地址;
设置断点或添加 watchdog,快速发现程序卡住的位置;
使用 Map 文件分析函数占用,查找堆栈是否溢出;
确认中断优先级配置是否合理,避免中断嵌套导致不可预期行为。
2️⃣ 外设初始化无效 / 配置错误
常见场景:
Timer 没有触发中断;
UART 无法发送接收;
GPIO 无电平变化。
调试建议:
打印调试信息(如 printf("UART Init Done\r\n"))验证代码走到;
检查 RCC 时钟是否开启相应外设;
用断点逐步调试,确保各初始化函数返回值正确;
检查是否调用 HAL/LL 驱动函数顺序错误。
3️⃣ 数据通信异常(SPI / I2C / UART)
调试重点:
波形分析:逻辑分析仪或示波器抓波形是最直接的方法;
SPI 是否配置正确时序模式(CPOL/CPHA);
UART 波特率是否一致,是否开启校验位;
是否存在 DMA 溢出 / 缓冲区冲突问题。
程序运行异常问题有死机/卡死,跑飞,硬件错误异常触发,数据异常
GPIO异常定时器不准通信故障中断异常
可以使用指示灯调试法:HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // 在关键位置插入LED翻转
可以合理使用断点与单步执行
如果内存不足的话会导致栈溢出或堆分配失败
非特权模式下禁止的操作:修改 NVIC、SCB 等系统寄存器
执行 MSR 修改特殊寄存器(如 PRIMASK)
访问被 MPU 保护的内存区域
// 使用DWT周期计数器
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
uint32_t start = DWT->CYCCNT;
// 被测代码
uint32_t end = DWT->CYCCNT;
uint32_t cycles = end - start;
我们可以采用预防性的措施比如认为注入错误信息看软件的反应
HardFault分析:
void HardFault_Handler(void) {
__asm volatile (
"tst lr, #4 \n"
"ite eq \n"
"mrseq r0, msp \n"
"mrsne r0, psp \n"
"ldr r1, \n"
"b HardFault_Dump \n"
);
while(1);
}
// 通过特定串口指令触发调试功能
if(strcmp(cmd, "DEBUG_DUMP") == 0) {
dump_internal_state();
}
页:
[1]