微控制器编程中ISR功能中的易失性关键字用法 [英] volatile keyword usage in ISR function in micro-controller programing

查看:200
本文介绍了微控制器编程中ISR功能中的易失性关键字用法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

As a general concept Global variable ("value") used in ISR function should be declared as volatile to avoid compiler optimization. but my doubt is a global variable is used in sub-function "ISR-SUB" which is invoked in ISR, whether the global variable used sub-function which is invoked in ISR also needs to be declared as 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标准:

Of course you do.
volatile isn't a prerogative of an ISR, it has a specific definition in the C11 standard:

具有volatile限定类型的对象可能会以实现方式未知的方式修改或具有其他未知的副作用.
因此,任何表达指 必须严格按照抽象机的规则对此类对象进行评估, 如5.1.2.3中所述.

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.

此外,在每个序列点,最后存储在变量中的值 对象应与抽象机器所规定的一致,除非由 前面提到的未知因素.
什么构成对对象的访问, 具有volatile限定类型的是实现定义的.

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告诉它该变量随时可能更改.

So whenever you control flows in a manner that cannot be deduced from the sources (like when an interrupt occurs), the compiler cannot know that a variable may have changed meanwhile.
You have to use volatile to tell it that such variable is subject to change at any moment.

如果那太抽象了, 为AVR微控制器考虑以下玩具代码:

If that's too abstract, consider this toy code for the AVR microcontroller:

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;
}

被编译为此汇编代码

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中更新,因此循环永远不会结束! 现在看看使用volatile

As you can see, the variable STATUS is read once and updated in the register r24, so the loop will never end!
Now look at 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会在每次迭代时根据要求进行读取和更新.

This time STATUS is read and updated at every iteration, as requested.

同步注意

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

Many thanks to @Olaf for pointing out the necessity of this section.

对于OP尝试实现的任何条件,我没有提出volatile是一个足够条件的声明(根本没有足够的上下文可以提出任何声明).
解释此答案的方式是volatile必要条件(如上面的简单反例所示).

I made no claims above that volatile is a sufficient condition for whatever the OP is trying to implement (there is simply not enough context to made any claim).
The way this answer is to be interpreted is that volatile is a necessary condition (as the simple counter-example above shows).

所显示的代码是一个玩具示例,旨在显示一个简单的问题,如果没有volatile,可能会出现该问题.
它并不是要工作的代码,因为实际上我将工作.

The code shown, as said, is a toy example meant to show a simple issue that can arise without volatile.
It is not meant to be working code because actually I will not work.

在处理并发执行流时,同步是强制性的,对于C可以使用stdatomic.h标头和函数来实现.

When dealing with concurrent flows of execution synchronisation is mandatory and for C this can be achieved using the stdatomic.h header and functions.

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

Being this a uC question, stdatomic.h may not be present or no synchronisation may be required (this is rare).
Just to avoid any misunderstanding: if you have stdatomic.h then use it (it will eventually compile to nothing but it made the code portable).

上面的示例包含一个不是原子的RMW操作(|=),因此可以取消ISR进行的更新.

The example above contains a RMW operation (the |=) that is not atomic can thus cancel the update made by the ISR.

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

So yes, you do need (at least) volatile.

这篇关于微控制器编程中ISR功能中的易失性关键字用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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