gpt4 book ai didi

c - 微 Controller 编程中ISR函数中 volatile 关键字的使用

转载 作者:行者123 更新时间:2023-11-30 20:00:38 27 4
gpt4 key购买 nike

作为一般概念,ISR 函数中使用的全局变量(“值”)应声明为 volatile,以避免编译器优化。但我的疑问是在ISR中调用的子函数“ISR-SUB”中使用了全局变量,在ISR中调用的子函数中使用的全局变量是否也需要声明为 volatile ?

unsigned int STATUS;  // -----> needs to be declared as volatile ?

void ISR-SUB()
{
STATUS = 1; -->accessed in sub function invoked in ISR which will be optimized or not
}

void ISR ()
{
ISR-SUB();
}

void main()
{

/* interrupt occurred and ISR called */

if (1 == STATUS)
{
code part
}
}

最佳答案

当然可以。
volatile 不是 ISR 的特权,它在 C11 standard 中有具体定义。 :

An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects.
Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3.

Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously.
What constitutes an access to an object that has volatile-qualified type is implementation-defined.

因此,每当您以无法从源推断出的方式控制流程时(例如发生中断时),编译器无法知道变量同时可能已更改。
您必须使用 volatile 来告诉它该变量随时可能发生变化。

<小时/>

如果这太抽象了,考虑 AVR 微 Controller 的玩具代码:

unsigned char STATUS;

void ISR_SUB()
{
STATUS = 0x80;
}

void ISR ()
{
ISR_SUB();
}

int main()
{
unsigned char i=1;

while (STATUS & 0x80)
{
STATUS |= i;
}

return 0;
}

这个gets compiled into这段汇编代码

main:
lds r24,STATUS ;r24 = STATUS
sbrs r24,7 ;Skip next inst if bit7 of r27 is set
rjmp .L4 ;Jump to the end
.L6:
ori r24,lo8(1) ;OR r24 with 1
sbrc r24,7 ;Do the test again, break loop if bit7 set
rjmp .L6 ;Jump back to the loop

sts STATUS,r24 ;STATUS = r24
.L4:
ldi r24,lo8(0)
ldi r25,hi8(0)
ret

如您所见,变量STATUS被读取一次并在寄存器r24中更新,因此循环永远不会结束!
现在看what happens when we use volatile

main:
rjmp .L8
.L6:
lds r24,STATUS ;Now status is load in r24 at each iteration ...
ori r24,lo8(1) ;... updated and ...
sts STATUS,r24 ;... stored back
.L8:
lds r24,STATUS
sbrc r24,7
rjmp .L6
ldi r24,lo8(0)
ldi r25,hi8(0)
ret

这次,STATUS 会根据请求在每次迭代中读取和更新。

同步注意事项

非常感谢@Olaf 指出本节的必要性。

我上面没有声明 volatile 是 OP 试图实现的任何内容的充分条件(根本没有足够的上下文来做出任何声明)。< br/>这个答案的解释方式是, volatile 是一个必要条件(如上面的简单反例所示)。

如前所述,所示代码是一个玩具示例,旨在展示一个在没有 volatile 的情况下可能出现的简单问题。
它并不意味着是工作代码,因为实际上我不会工作。

处理并发执行流时 synchronisation是强制性的,对于 C,这可以使用 stdatomic.h header 和函数来实现。

这是一个 uC 问题,stdatomic.h 可能不存在,或者可能不需要同步(这种情况很少见)。
只是为了避免任何误解:如果您有 stdatomic.h,那么使用它(它最终会编译为空,但它使代码可移植)。

上面的示例包含非原子 RMW 操作(|=),因此可以取消 ISR 所做的更新。

<小时/>

所以,是的,您确实需要(至少) volatile

关于c - 微 Controller 编程中ISR函数中 volatile 关键字的使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41502926/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com