3

我有一个利用伺服库和外部中断例程的程序。据我了解,伺服库使用 Timer1 中断向伺服发送脉冲以保持位置。我想知道对 micros() 计数有什么影响,因为它在中断期间不会增加。

我的代码中的外部中断例程用于转速计。它使用 micros() 确定脉冲之间的时间。我担心 Servo 库会导致 millis() 和 micros() 计数器的漂移并使速度不准确。转速计可能必须感应 10,000 RPM 的速度,因此大约为 167 Hz。最终我将使用伺服和转速计实现 PID 控制。

volatile unsigned long period;
unsigned long microseconds;

void setup(){
    Serial.begin(9600);
    pinMode(tachometerPin, INPUT);

    pinMode(led, OUTPUT);

    attachInterrupt(0, tachometer, RISING); // set external interrupt

    throttle.attach(throttlePin); // attach servo objects to pins
    fuel.attach(fuelPin);
    throttle.writeMicroseconds(throttle_idle); // set servo positions
    fuel.writeMicroseconds(fuel_neutral);
}
void loop(){
    Serial.println(calculateSpeed());
}

float calculateSpeed(){
    /* Calculate speed of engine in RPM */
    float s = 60.0/(period*0.000001);
    return(s);
}
void tachometer() {

    /* Determine time between rotations of engine (pulses from tachometer) */
    period = micros() - microseconds;
    microseconds = micros();
}
4

1 回答 1

3

甚至从中断调用tachometer()更新的函数millis(),因此即使它会“破坏”您的代码。

这会对你的演讲造成多大的破坏?不是很多。Arduino 2009 使用 16 MHz 的晶体,每天有几秒的漂移。使用不太精确的振荡器的 Arduino Uno 会漂移更多。

因此,除非您在中断例程中进行大量计算,否则没问题。还请记住,调用 micros() 会花费您 4 µs(实际上您会看到它以 4 x 4 的速度增长……或者这是让 Timer0 每秒溢出?看看计时器预分频器;如果它不会破坏伺服库。它会破坏millis()和micros(),你可以使用Timer1或Timer2,但Timer0是唯一的16位定时器,所以这取决于你),所以这是你真正的精度杀手。

我建议消除中断中的函数调用:

unsigned long tmpTime;
void tachometer() {

    /* Determine time between rotations of engine (pulses from tachometer) */
    tmpTime = micros();
    period = tmpTime - microseconds;
    microseconds = tmpTime;
}

甚至 attachInterrupt 调用一个调用你的函数的 ISR。您可以自己实现 attachInterrupt,这样您就可以直接实现 ISR(少了一个函数调用,并且函数调用相对昂贵,因为您必须使用堆栈和寄存器)。

也不要使用 micros(),它会做很多事情(读取 Timer0 实际计数,并将计数计算到 µs,并且是一个函数调用);只需直接读取定时器寄存器并与该值进行差异,然后将 count 转换为 µs 到loop(). 这样应该会快很多。

我不是在编写代码,因为您只需要打开 Arduino 的库并查看它们的功能,然后自己复制即可。这很容易,因为您有一个工作示例、一个 ATmega 数据表和许多关于定时器、中断甚至 PWM 的教程。

于 2014-03-26T09:50:22.373 回答