完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
当单片机发生程序异常时,会进入到HardFault_Handler中断,相当于windows的蓝屏,我现在介绍的是如何获取中断位置,并自动记录异常位置(我的做法是将异常的时间,与代码地址存储到备份区,这样哪怕重启了依旧可以查询上一次发生异常的位置,这部分代码需要自己去实现,我现在实现的是获取异常代码位置)。
发现增加了OS后不一样,增加裸机与OS下的异常处理。 原理如下:当异常时,硬件会将一些CPU的寄存器保存到栈中,通过在异常时获取堆栈指针SP的值,通过SP获取当前栈的位置,然后获取异常之前的PC指针的值,就知道异常的位置了。 //这个就是CPU寄存器在栈中的排列 //栈数据定义 typedef struct { u32 R0; u32 R1; u32 R2; u32 R3; u32 R12; u32 LR; u32 PC; u32 xPSR; }STACK_DATA_TYPE; //获取当前CPU堆栈指针MSP __asm u32 getMSP(void) { mrs r0, msp bx lr } //获取当前CPU堆栈指针PSP __asm u32 getPSP(void) { mrs r0, psp bx lr } //没有操作系统时的异常处理 void NotOSHardFault_Handler(u32 msp_addr) { STACK_DATA_TYPE *p; //堆栈中存储的数据 msp_addr -= 4; //堆栈指针减去4,因为默认堆栈指针指向的是下一个空的地方-所以必须减去4 uart_printf_enable(); //开启串口调试信息 uart_printf("rn-----------------ERROR -----------------rnHardFault_Handlerrn"); if((msp_addr >> 20) != 0x200) //判断地址范围,必须是0x200xxxxx 范围 { uart_printf("警告:堆栈指针被破坏,无法记录现场!rn"); return; } msp_addr += 8; //进入中断后,堆栈又进入了2个u32数据,因此需要往后推 p = (STACK_DATA_TYPE *)msp_addr; p->PC -= 3; //PC指针要减去3 //BackupArea_RecordHardFault(RTC_GetSec(), p->PC); //记录异常pc指针信息到备份区 uart_printf("R0:0x%08Xrn", p->R0); uart_printf("R1:0x%08Xrn", p->R1); uart_printf("R2:0x%08Xrn", p->R2); uart_printf("R3:0x%08Xrn", p->R3); uart_printf("R12:0x%08Xrn", p->R12); uart_printf("LR:0x%08Xrn", p->LR); uart_printf("PC:0x%08Xrn", p->PC); uart_printf("xPSR:0x%08Xrn", p->xPSR); uart_printf("系统即将复位...rn"); } //有操作系统时的异常处理 void OSHardFault_Handler(u32 psp_addr) { STACK_DATA_TYPE *p; //堆栈中存储的数据 psp_addr -= 4; //堆栈指针减去4,因为默认堆栈指针指向的是下一个空的地方-所以必须减去4 uart_printf_enable(); //开启串口调试信息 uart_printf("rn-----------------ERROR -----------------rnHardFault_Handlerrn"); if((psp_addr >> 20) != 0x200) //判断地址范围,必须是0x200xxxxx 范围 { uart_printf("警告:堆栈指针被破坏,无法记录现场!rn"); return; } p = (STACK_DATA_TYPE *)psp_addr; p->PC -= 3; //PC指针要减去3 //BackupArea_RecordHardFault(RTC_GetSec(), p->PC); //记录异常pc指针信息到备份区 uart_printf("R0:0x%08Xrn", p->R0); uart_printf("R1:0x%08Xrn", p->R1); uart_printf("R2:0x%08Xrn", p->R2); uart_printf("R3:0x%08Xrn", p->R3); uart_printf("R12:0x%08Xrn", p->R12); uart_printf("LR:0x%08Xrn", p->LR); uart_printf("PC:0x%08Xrn", p->PC); uart_printf("xPSR:0x%08Xrn", p->xPSR); uart_printf("系统即将复位...rn"); } //硬件中断 void HardFault_Handler (void) { u32 msp_addr = getMSP(); //获取线程模式下堆栈指针位置 u32 psp_addr = getPSP(); //获取中断下的堆栈指针位置-用于OS启动后 #if(UCOS_II_EN) //使能了操作系统的一个宏定义,自己去定义 if(SYS_GetOsStartup()) //操作系统运行了-自己定义一个状态,可以获取操作系统是否启动 { OSHardFault_Handler(psp_addr); } else { NotOSHardFault_Handler(msp_addr); } #else //没有使能操作系统 NotOSHardFault_Handler(msp_addr); #endif //UCOS_II_EN Delay_MS(10); //延时一下,防止重启速度太快 SYSTEM_SoftReset(); //复位重启 } 可以自己将PC指针的值存储到备份区,这样可以查询到产品是否发生过异常,并且异常位置,通过代码仿真可以找到异常代码位置。 异常前CPU寄存器数据 异常后,通过堆栈指针获取到堆栈中的数据,存放有异常前的PC指针,也就是异常位置。 获取了PC指针就能定位位置了 串口输出的异常前CPU寄存器数据。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1559 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1500 浏览 1 评论
930 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
662 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1551 浏览 2 评论
1846浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
606浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
503浏览 3评论
507浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
487浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-9 02:30 , Processed in 0.774819 second(s), Total 49, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号