我应该在这个库中使用volatile(以及在哪里)?

时间:2014-08-06 21:49:13

标签: c arduino volatile

我正在使用Arduino PID library,我想在ISR中使用它,如:

ISR(TIMER1_COMPA_vect) {
  myPID.compute();
}

但是,我可以说这是错误的主意,因为ISR中使用的变量需要使用volatile关键字。好的,所以我这样声明PID:

PID myPID(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);

我宣布inputoutputsetpointvolatile。但是,库不接受volatile变量。

我首先想到的是将其转换为无处不在。但是我应该添加它:

  • 在内部变量之前
  • 在课堂之前(如上所述声明)或在头文件中?
  • 在我的库中的变量参数的变量类型?

我该怎么办?

1 个答案:

答案 0 :(得分:1)

  

我该怎么办?

如图所示使用你的代码,没有任何易变的东西,并且开心:)

volatile关键字只是对编译器的一个暗示,即变量可能会被看不见的路径改变。如果一个简单的变量只被ISR修改,那么标记volatile就不会有什么坏处。这样的标记可能会阻止编译器使用以下代码执行错误的操作:

volatile int n = 0;

ISR(TIMER1_COMPA_vect) {
    n = 1;
}


void loop() {

    n = 0;

    // At this point the tricky compiler might think 
    // "n must be zero, why do this comparison?"
    // it might also think,
    // "hey, I've got the value of n still sitting in a
    // register, I don't even have to read it from memory
    // The volatile keyword says "stop thinking"

    if(n == 1) {
      // do something when ISR() occurred just before if()
      // a very small window, but it would eventually happen
      n = 0;
    }

 }

对于您的对象,仅关于ISR引入的更改是否会导致对象的其他用户可能看不到的变量更改。如果PID对象通过compute()消耗输入和输出的唯一驱动程序,则不存在问题。换句话说,compute()中的更改不会影响主循环()

更大的问题应该是一致性,而不是用 volatile 来解决。如果设定值是32位整数,则内存中的值不能以原子方式更改。主循环()可能有一条无辜的行

setpoint = setpoint + 20;

但这涉及将内存中的值传入寄存器,执行数学运算并将其写回。在该过程中的任何时钟周期,可能发生中断。正好在将设定点的新值存储到存储器的过程中,可能会发生中断(最终会发生)。

通过在访问共享对象时禁用主循环()中的中断来保护它。

nointerrupts()
setpoint = setpoint + 20;
interrupts()

现在你可以确保中断不会在最糟糕的时刻发生,并在破坏的设定值上执行compute()。