由main()修改并由ISR()访问的全局变量

这是我的c代码

char global_variable = 0; ISR(){ PORTA = global_variable; toggle_led;//to make sure that the interrupt is triggered } int main(){ while(1){ _delay_ms(500); gobal_variable++; PORTB = global_variable; } return 0; } 

底线是我有一个由main函数修改的全局变量,并由main和ISR – 中断处理程序读取。
当main读取全局变量时,我得到期望的值,但在ISR中,我得到第一次分配给全局变量的值。
我知道这是一个优化问题,但我不明白是什么让编译器看到主要的正确值和ISR中的初始值

注意:当我在ISR中修改变量时,我在ISR中读取它,但在主要中我得到了初始值。

ISR没有正确的声明。 你真的应该习惯使用原型风格的声明。 使用C99或C11编译,您将收到警告。 类似于main:

 void ISR(void) int main(void) 

main的签名取决于您的环境,假设您使用的是裸机嵌入式系统,即独立式环境

根据目标,您必须使用特定于编译器的属性将该函数标记为中断处理程序。

说,你缺少声明global_variable volatile 。 你应该知道,因为你已经添加了标签。

编译器无法知道无论如何都要调用ISR,并且该变量在其控制流之外被修改。 因此它可以假定它具有默认值,即0 。 使用volatile限定符可以准确地告诉它它不能并且变量实际上是在外部修改的。

请注意,由于所有这些,编译器不能优化对volatile对象的接受。 因此,您应该将对这些对象的访问限制到最小。 在main中,最好使用辅助变量进行计数,然后将更新的值一次写入volatile对象和计数器。 这样就可以避免一次读取和一次写入:

 volatile unsigned char global_variable; ... int main(void) { unsigned char counter; while ( 1 ) { _delay_ms(500); gobal_variable = counter++; PORTB = counter; } return 0; } 

请注意,我将类型更改为unsigned char这是至关重要的,因为char可以是有符号或无符号的,并且有符号整数溢出会调用C中的未定义行为 。无符号溢出定义为简单换行(即:MAX + 1 == 0)。 要使用的更好的数据类型是uint8_t因为C99(强烈推荐)明确声明您正在使用8位变量( char不保证这一点)。

注意:根据您在下面的评论,您使用的是AVR MCU。 这是单核的,甚至不支持内存障碍。 所以绝对没有必要这样做。 此外,由于您有一个写入器并且写入是primefaces的 (即更新变量的全部或全部),因此也不需要更复杂的同步。

但是 ,如果增加计数器的大小,则必须采用ISRmain条款来确保一致地读取值。 这是因为AVR是8位机器,因此更新和读取不是primefaces的。

注意:由于受欢迎的需求,您应该检查目标是否实际执行写入primefaces。 对于8位值也是如此。 如果您不确定,请检查生成的汇编代码。 但是,对于AVR,PIC,MSP430,ARM-Cortex-M( 如果总线寄存器支持字节写入),除非在其中一个变量上使用DMA,否则上述代码是安全的。

在这种情况下,您应插入一个内存屏障来断言所有写入将在您阅读之前完成。 在用户空间中,您应该将此变量声明为volatile

 volatile char global_variable = 0;