关注Arduino程序中micros()值的漂移

时间:2014-03-25 22:07:02

标签: arduino interrupt isr

我有一个利用伺服库和外部中断程序的程序。根据我的理解,伺服库使用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();
}

1 个答案:

答案 0 :(得分:2)

甚至tachometer()和更新millis()的函数都是从中断调用的,所以即使它会“破坏”你的代码。

这会毁了你的演讲多少钱?不是很多。 Arduino 2009,使用16 MHz的晶体,每天漂移很多秒。使用不太精确的振荡器的Arduino Uno会漂移得更多。

所以,除非你在中断程序中做了很多计算,否则你很好。还记得micros()调用花费你4μs(实际上你会看到它增长4乘4 ...或者这是让Timer0每秒溢出一次?看看定时器预分频器;你可以改变它它不会破坏Servo lib。它会破坏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的教程。