我正在使用Arduino PID library,我想在ISR中使用它,如:
ISR(TIMER1_COMPA_vect) {
myPID.compute();
}
但是,我可以说这是错误的主意,因为ISR中使用的变量需要使用volatile
关键字。好的,所以我这样声明PID:
PID myPID(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);
我宣布input
,output
和setpoint
,volatile
。但是,库不接受volatile变量。
我首先想到的是将其转换为无处不在。但是我应该添加它:
我该怎么办?
答案 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()。