【全文大纲】 : https://blog.youkuaiyun.com/Engineer_LU/article/details/135149485
1 . 前言总结
当中断中操作了变量,回到后台判断变量时有时候会判断不过是因为编译器优化在判断时不从ram区域地址取值判断,而是从寄存器变量中取值判断
2 . 问题现象
timer_Interrupt() 定时器中断里会一直执行,value会执行到100,但是有时候后台判断value仍然一直小于50,原因是后台判断中编译器优化,把value变量放到R0,R1这些寄存器变量里,因为寄存器变量运行速度会很快,但也因此,当值已经给R0,R1这些寄存器变量后,判断就只判断R0,R1这些寄存器变量,而此时ram区域的value变量改变了,却仍然在判断R0,R1这些寄存器变量,因此一直判断不到value>=50
unsigned int value = 0;
unsigned int ram = 0;
int main() {
while (1) {
if (value >= 50) {
ram = 1;
}
}
return 0;
}
void timer_Interrupt()
{
if (++value >= 100) {
value = 100;
}
}
3 . 解决思路
为了解决以上问题,可在需要在中断与后台同时操作的变量定义时加 volatile 修饰,以保证编译不会把变量放到寄存器变量里执行逻辑
volatile unsigned int value = 0;
unsigned int ram = 0;
int main() {
while (1) {
if (value >= 50) {
ram = 1;
}
}
return 0;
}
void timer_Interrupt()
{
if (++value >= 100) {
value = 100;
}
}
4 . 细节扩展
除了上述变量,还有指针指向中断操作的变量,也应加volatile修饰定义指针,以保证指针取值不会取向寄存器变量,另外MDK平台若开启 O 1 O_1 O1以上优化,此问题暴露的几率比较大
5 . 总结
优秀的代码,在任何优化下,基本很少影响正常运行 (不排除极端优化导致的逻辑问题),其实单片机里中断可以理解为开了一个线程,这就相当于后台为主线程,中断为另一个线程,当多线程交互时,单片机在没有系统加持管理情况下,纯粹靠编译决定行为,因此一般建议在中断后台都有同一变量写入的行为情况下,加响应完成的“互斥锁”,如果不加,系统框架也尽量满足即使中断打断操作了变量也不至于系统崩溃,最后就是优化问题,对寄存器变量深入研究可发现目前编译器是不够完美的,用户尽量避免该问题出现
技术交流群 : 745662457
群内专注 - 问题答疑,技术研究