00:00
在STM3、2的中断函数里写一句printer f, 程序有时候会卡死,有时候会丢数据,还有时候看起来完全正常。那中断里到底能不能用printer f? 答案不是绝对不能,而是不能随便用。我也给大家准备了嵌入式自学路线、硬核实战项目、大场面试真题、简历模板等技术干货,有需要的同学66领取先弄明白一件事,中断的本质是CPU正在执行正常任务时,突然来了一个更紧急的事件,CPU要先保存当前现场,跳进中断处理函数,把紧急事情处理完,再回去继续执行原来的代码。所以中断处理函数有一个基本原则,能多快就多快。但Print f恰恰不是一个简单操作,你写一行print f, 背后可能要解析格式字符串,处理整数或者浮点数,把数据转换成字符,然后再通过串口一个字节一个字节的发送出去。假设串口波特率是115200,发送一个字符通常需要大约10个比特打印。
01:00
几十个字符看起来只是一句话,实际可能占用好几毫秒。对人来说,几毫秒很短,但对运行几十兆赫兹的单片机来说,已经足够执行大量指令了。如果你在中断里使用主设式串口发送,CPU就可能一直等着每个字节发完。在这段时间里,低优先级中断得不到响应,主循环也无法继续运行。严重时,新的数据已经来了,旧的数据还没处理完,于是就出现丢数据。第二个问题是print f可能不可重入。所谓不可重入,你可以简单理解为这个函数还没执行完,又被另一个地方调用,他们可能会同时修改同一份内部状态。比如主循环正在printer f突然进入中断,中断里又调用一次printer f, 如果底层实现使用了共享缓冲区,输出可能混乱,严重时甚至破坏内存。如果系统跑了free rt OS问题会更复杂。Print f的底层可能涉及锁而中断环境不能像普通任务一样等待锁。
02:00
任务拿着锁的时候被中断打断,中断用来申请,同一把锁就可能直接卡住。还有些工程为了支持浮点格式化,会让print的F占用较多站空间。中断站本来就有限,再来一次复杂格式化就有可能引发站一出。那调试中断时怎么打印?最简单的原则是中断里只记录,不做复杂输出。比如中断触发后,只把错误码、时间戳或者关键变量写入一个环形缓冲区,然后立即退出,等主循环或者日志任务有空时再慢慢格式化,并通过串口发送。也可以在中段里只设置一个标志位,IR q flag=1,然后在主循环里检测这个标志,再执行print f. 如果数据量比较大,可以配合串口DNA把发送工作交给硬件。但即使使用DNA,也要注意缓冲区、生命周期和并发访问,不能启动完发送就立刻修改原来的数据。面试时可以这样回答,中断里不建议调用print f, 因为它耗时长,可能阻塞,可能不可重入,还会增加。
03:00
加站和实时性风险,更合理的做法是中断里快速采集信息,通过标志位、队列或者环形缓冲区把打印工作推迟到主循环或任务中执行。好了,今天的分享就到这里,如果觉得有用,记得点赞关注,咱们下期见。
我来说两句