中断没进去,还是程序没运行?
在中断函数里设置标志位,主程序里检测标志位,然后执行相应的程序。这种模式用了好几年了,但是突然有问题了。
起因是调试程序时,发现有个功能模块功能异常,通过打印日志发现,该功能模块始终没有得到允许。那就看允许运行的条件喽。是在事件发生时,单片机产生中断,然后在中断服务程序里,设置一个标志位。在中断里打印日志,标志位确实被设置了。
这就奇怪了,中断服务运行了,标志位被设置了,功能程序为什么不运行呢?
变量是双面人?
通过打印日志暂时没找到问题根源,就上仿真大法吧。跟踪到中断服务程序里,单步运行,设置标志位,神奇的事情就出现了,在中断程序里标志位被设置了,离开中断会,标志位竟然被恢复了。难道这个标志位是双面人?
最终还是我错了。
这个编译器有bug,这种伟大想法也仅仅是想想,还是要继续找问题的。通过不断的努力(耗时间),终于在仿真界面的反汇编里发现一点异常。标志位定义成全局变量,而中断服务程序里,是用R寄存器代表这个标志位。(当时没有截图,就不上图了。见谅。)这就有问题了啊。说是迟,那是快,这时一个关键字“volatile”如同一颗流星一般划过我的思维。标志位被优化掉了啊。
赶紧用“volatile”修饰一下标志位,然后运行,OK。这就好了!!!好了!!!为这事忙了两天呢。
收获
在中断程序里使用的变量最好要使用“volatile”来修饰一下,防止被编译器优化。
volatile的介绍(AI创作助手)
volatile是Java中的关键字,用于声明变量。它的作用是告诉编译器该变量将被多个线程访问和修改,因此不应该进行编译器优化,需要每次从内存中读取最新的值。
具体来说,volatile的作用包括以下几个方面:
-
禁止指令重排序:编译器和处理器在进行指令优化时,有时会对指令进行重排序,但是对于volatile变量,编译器会保证不会对其指令进行重排序。
-
保证可见性:当一个线程修改了volatile变量的值时,其他线程可以立即看到最新的值,不需要等待缓存写回主存。
-
不保证原子性:volatile变量只能保证可见性,并不能保证原子性。例如,多个线程同时对同一个volatile变量进行自增操作,可能会导致结果不正确。
因此,volatile适用于以下场景:
-
标识状态的变量:如标识一个线程是否继续执行的变量。
-
控制停止的变量:如标识一个循环是否结束的变量。
-
状态标志变量:如标识一个操作是否完成的变量。
需要注意的是,虽然volatile能够保证可见性,但并不能保证线程安全。在多线程环境下,如果需要保证变量的原子性操作,可以使用synchronized或者Lock进行同步控制。
文章讲述了在单片机开发中遇到的问题,即中断服务程序设置的标志位在中断结束后被意外恢复。通过深入分析发现,编译器对全局变量进行了优化,导致标志位不一致。最终通过添加`volatile`关键字解决了问题,强调了在中断程序中使用volatile的重要性以及volatile的关键作用和适用场景。


被折叠的 条评论
为什么被折叠?



