由main()修改并由ISR()访问的全局变量 [英] Global variables modified by main() and accessed by ISR()

查看:400
本文介绍了由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和ISR - 中断处理程序读取。

当main读取全局变量时,我得到期望的值,但是在ISR中,我得到了首先分配的值到全局变量。

我知道这是一个优化问题,但是我不明白什么使得编译器在ISR中的主要值和初始值中看到正确的值。

The bottom line is that I have a global variable modified by the main function and read by both the main and ISR -interrupt handler.
When the global variable is read by main I get the expected values, but in ISR I get the value that was first assigned to the global variable.
I know this is an optimization issue but I don't understand what makes the compiler see the right value in the main and the initial value in the ISR

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

Note: when I modified the variable in the ISR, I read it right in the ISR but in the main I got the initial value.

推荐答案

ISR 没有正确的声明。你真的应该习惯使用原型样式的声明。编译C99或C11,你会得到一个警告。类似于main:

ISR has no correct declaration. You really should get used to use prototype-style declarations. Compile with C99 or C11 and you will get a warning. Similar for main:

void ISR(void)

int main(void)

鉴于 main 的签名取决于您的环境,假设您在裸机嵌入式系统上,即独立环境。

Whereas the signature of main depends on your environment, assuming you are on a bare-metal embedded syetem, i.e. a freestanding environment.

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

Depending on the target, you have to att compiler-specific attributes to tag the function as interrupt handler.

表示,您无法声明 global_variable 易失性。您应该知道,因为您已经添加了标签。

Said that, you are missing to declare global_variable volatile. You should know, as you already added the tag.

编译器无法知道ISR是否被调用,并且变量在其控制流之外被修改。所以它可以假设它有默认值,它是 0 。使用 volatile 限定词可以准确地告诉它,它不能和变量实际上是在外部修改的。

The compiler cannot know the ISR is called anyway and that the variable is modified outside its control-flow. So it can presume it to have the default value, which is 0. Using the volatile qualifier tells it exactly that it cannot and the variable is in fact modified outside.

请注意,对于所有这些,编译器不得优化到 volatile 对象的访问。因此,您应该将对这些对象的访问限制在最小限度。主要的是,最好使用一个帮助变量来计算一次更新的值一次到 volatile 对象,否则反算。这样你就可以避免一次读写:

Note that due to all this, the compiler must not optimize acceses to volatile objects. Thus, you should limit accesses to such objects to the minimum. In main, it is better to use a helper variable to count and just write the updated value once to the volatile object and the counter otherwise. This way you avoid one read and one write:

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 不保证这一点)。

Notice that I changed the type to unsigned char this is vital, as char can be signed or unsigned and signed integer overflow invokes undefined behaviour in C. Unsigned overflow is defined to simply wrap (i.e.: MAX+1 == 0). A better datatype to use would be uint8_t since C99 (strongly recommended) to explicitly state you are using an 8 bit variable (char does not guarantee this).

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

Note: According to your comment below, you use an AVR MCU. This is single-core and does not even support memory barriers. So there is absolutely no need for such. Also, as you have a single writer and the writes are atomic (i.e. all-or-nothing of the variable is updated), there is also no need for more complex synchronisation.

但是,如果您增加柜台的大小,则必须在 ISR main 以确保一致地读取值。这是因为AVR是一个8位机器,因此更新和读取不是原子的。

However, if you increase the size of the counter, you have to take provisions in ISR or main to ensure reading the value consistently. This because the AVR is an 8 bit machine, thus the update and reads are not atomic.

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

Note: Due to popular demand, you should check your target if it actually performs the writes atomic. This is also true for 8 bit values. If you are not sure, check the generated assembler code. However, for the AVR, PIC, MSP430, ARM-Cortex-M (iff the busses and registers support byte-writes), the code above is safe unless you use DMA on one of the variables.

这篇关于由main()修改并由ISR()访问的全局变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆