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