关于不用中断定时或每隔几次做某事

参考文档

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 说明

那如果是透过外部中断做事,但外部中断来得太快, 快到只做 ++ 都严重影响呢? 很简单:

  1. 在 loop( ) 内必要时才把中断ISR( ) 做 attach 上去,
  2. 在 ISR( ) 内把中断 detach

1.2.2 具体做法:

  1. before setup( )
   int intInt = 200; // 每隔大约 200 millis 再处理一次中断
   unsigned long nextInt = 0;  // 下一次该接受中断的时间
  1. in setup( )
    不要做 attachInterrupt !!!

  2. in loop( ) {

 if(millis( ) > nextInt) {
    nextInt = millis( ) + intInt;  // 下次过这时间才可中断
    /// 允许外部中断
    noInterrupts();  // 禁止任何中断
    attachInterrupt(0, yourISR, CHANGE);
    attachInterrupt(1, yourISR, CHANGE);
    interrupts();  // 允许任何中断
  }// if(millis(
  //.. 其他在 loop( ) 的事
  //...
  1. in yourISR( ) {
   detachInterrupt(0);  // 取消外部中断 0 (Pin 2)
   detachInterrupt(1);  // 取消外部中断 1 (Pin 3)
   //... do your 中断 Job
  1. 如果 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( ) 来举例说明 !
注意

  1. 原则上在 myJobOne( ) 内不要用 delay( )

  2. 不过如果只是 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( ),不过这比较难,很容易出错

参考:

猜你喜欢

转载自blog.csdn.net/acktomas/article/details/88140146