itterrupt index
参考文档
1. 如何每隔几次才做某事(教程)与定时器无关+外部中断太快?
原文地址:https://www.arduino.cn/thread-12405-1-1.html
1.1 利用静态变量和随机数
常常有人问说在 loop( ) 内太快做到我要做的事, 可否做少一点次数?
例如可不可以每隔几次才做 Serial.print( ) 等等 ?
所以我也来写一个简单教程 :-)
以下的范例是每隔最少三次最多25次会做一次 !
// 每隔 3 到 25 次 (Random 决定) 做一次 --- by tsaiwn
const int FIRST_RUN = 0; // 一开始前 0 次不做!(改 3 就是前 3 次不做!)
const int MIN_RUN = 3; // 最少每3次
const int MAX_RUN = 26; // 最久每25次, 26 -1 = 25, 因 random( ) 是这样规定
//...
void setup( ) {
randomSeed(analogRead(0)*7 + analogRead(5)); // 把随机数打乱 !
//...
}
void loop( ) {
//..
myPrint( );
//..
}
void myPrint( ) {
static unsigned long gg = 0;
static unsigned long yy = FIRST_RUN;
if( ++gg < yy) return; // 每次把 gg 加 1
yy = gg + random(MIN_RUN, MAX_RUN); // 下次 gg 要比这 yy 大才下来做事
//... 做你原先要做的事
// Serial.print(
//...
}
程序说明
- 如果每两次要做一次,就设定 MIN_RUN = 2; 以及 MAX_RUN = 3;这是因 random(2, 3) 是得到 2 … (3-2) 之间 int 就一定是 2
- 如果要前面 38次不做, 就设定 FIRST_RUN = 38;
- 如果你是要每隔固定次数做一次, 例如每隔 33 次才做一次, 那不需用到 yy 变量也不需用到 random( ), 只要在 myPrint( ) 函数内第一句写如下这句:
if( ++gg % 33 != 0 ) return;
1.2 利用中断
1.2.1 说明
那如果是透过外部中断做事,但外部中断来得太快, 快到只做 ++ 都严重影响呢? 很简单:
- 在 loop( ) 内必要时才把中断ISR( ) 做 attach 上去,
- 在 ISR( ) 内把中断 detach
1.2.2 具体做法:
- before setup( )
int intInt = 200; // 每隔大约 200 millis 再处理一次中断
unsigned long nextInt = 0; // 下一次该接受中断的时间
-
in setup( )
不要做 attachInterrupt !!! -
in loop( ) {
if(millis( ) > nextInt) {
nextInt = millis( ) + intInt; // 下次过这时间才可中断
/// 允许外部中断
noInterrupts(); // 禁止任何中断
attachInterrupt(0, yourISR, CHANGE);
attachInterrupt(1, yourISR, CHANGE);
interrupts(); // 允许任何中断
}// if(millis(
//.. 其他在 loop( ) 的事
//...
- in yourISR( ) {
detachInterrupt(0); // 取消外部中断 0 (Pin 2)
detachInterrupt(1); // 取消外部中断 1 (Pin 3)
//... do your 中断 Job
- 如果 0 号中断与 1 号中断要做不同的 ISR( ) 也是 Ok
仍可在 ISR( ) 内把两个中断都 detach 掉,
或是各自 detach 自己的中断也 OK, 看你如何应用 !
2. 不使用 Timer 库要定时做某事或做两三件事(教程)定时器相关
不使用 Timer 库要定时做某事或做两三件事(教程)定时器相关
https://www.arduino.cn/thread-12408-1-1.html
(出处: Arduino中文社区)
虽然 Timer 库和 SimpleTimer 库已经很简单:
http://playground.arduino.cc/Code/Timer
http://playground.arduino.cc/Code/SimpleTimer
2.1 利用millis()定时
但对于有些只是想"定时"做一件事或两三件事的,会觉得还要研究如何用库有点麻烦, 那要如何做呢? 就用 millis( ) 啊!
其实 Timer 与 SimpleTimer 都是偷用 millis( )检查时间到了没 !? 不用该些库, 自己写也很简单 !
2.1.1 利用milis()定时做一件事
以下就用每隔 0.543 秒会做一次 myJobOne( ) 来举例说明 !
注意
-
原则上在 myJobOne( ) 内不要用 delay( )
-
不过如果只是 delay( ) 很少很少例如 delay(2); 也还勉强可以 !
原理很简单, 就是用 aaUp 记住下次该做 myJobOne( )的时间,
透过 tryAA( ) 检查是否时间到了该做 myJobOne( ) ?
如果该做,则先设定下次该做时间,并立即做一次 myJobOne( )
用 tryAA( ) 而不直接展开写在 loop( ) 内,是让 loop( ) 简洁易懂!
程序:·
//Super Simple Timer
const long aaEvery = 543; // 543 milli seconds
unsigned long aaUp; // 最后刚做过 myJobOne( ) 的时间
//...
void setup( ) {
//...
myJobOne( ); // 第一次不想立即做, 就写注释掉这句 comment out
aaUp = millis( ); // 最后刚做过 myJobOne( ) 的时间
//...
}
void loop( ) {
tryAA( ); // 看看该吃药了没 ?
//... 其他事
//...
}
void tryAA( ) {
if(millis( ) - aaUp < aaEvery) return; // 时间还没到
aaUp = millis( );
myJobOne( ); // 该吃药啰 !
}
void myJobOne( ) {
//... your Job 吃药 :-)
}
2.1.2 那如果有两件事各自不同间隔要做呢?
很简单, 仿照一下, 多用一个类似 aaUp 的 bbUp,然后也写一个类似 tryAA( ) 的 tryBB( ) 与要做事的 function 就可以啦:
程序
//Super Simple Timer, 2 jobs
const long aaEvery = 543; // 543 milli seconds
const long bbEvery = 1357; // 1.357 seconds
unsigned long aaUp; // 最后刚做过 myJobOne( ) 的时间
unsigned long bbUp;
//...
void setup( ) {
//...
aaUp = millis( ); myJobOne( );
bbUp = millis( ); myJobTwo( );
//...
}
void loop( ) {
tryAA( ); // 看看该吃药了没 ?
tryBB( );
//... 其他事
//...
}
void tryAA( ) {
if(millis( ) - aaUp < aaEvery) return; // 时间还没到
aaUp = millis( ) ;
myJobOne( ); // 该吃药啰 !
}
void myJobOne( ) {
//... your Job 吃药 :-)
}
void tryBB( ) {
if(millis( ) - bbUp < bbEvery) return; // 时间 2 还没到
bbUp = millis( );
myJobTwo( );
}
void myJobTwo( ) {
//... your Job 2
}
程序说明
请注意, 如果你的 myJobOne( ) 或 myJobTwo( )做太久,则可能影响做另一件事的时间, 就是会稍微延后一点点,但这也是没办法的事, 即使使用 Timer 库 这问题仍然存在 !
那建议你还是把 Timer 库研究一下以免你的程序太长看了不爽 ! 如果要在更准确时间做事呢 ?
那你要改用硬件中断的 Timer1 或 MsTimer2 库
http://playground.arduino.cc/Code/Timer1
http://playground.arduino.cc/Main/MsTimer2
Servo库导致 pin 9, pin 10 无法使用 PWM
但请注意它们会用到内部的 timer1 或 timer2 定时器,可能会影响到其他库的使用, 例如 Servo 库使用内部 timer1 定时器,
**这也是为何用了 Servo 库则你的 pin 9, pin 10 就无法使用 PWM 的原因,**因为 pin 9, pin 10 的 PWM 是靠内部 timer1 用定时中断帮忙做的!
MsTimer2 库导致 pin 11, pin 3 无法使用 PWM
如果你使用 MsTimer2 库,则 pin 11 和 pin 3 的 PWM 就有问题啰
因为 timer2 控制 pin 3 和 pin 11 的 PWM
当然, 你也可以自己控制硬件 timer 定时器并写对应的 ISR( ),不过这比较难,很容易出错
参考:
- http://forum.arduino.cc/index.php?topic=122065.0
- http://blog.oscarliang.net/arduino-timer-and-interrupt-tutorial/
- http://maxembedded.com/2011/07/avr-timers-ctc-mode/
- http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/
- http://www.instructables.com/id/Arduino-Timer-Interrupts/