|
Arduino 默认使用了 Timer0 【参考1】,在 \arduino-1.6.3\hardware\arduino\avr\cores\arduino\wiring.c 有
- #if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
- ISR(TIM0_OVF_vect)
- #else
- ISR(TIMER0_OVF_vect)
- #endif
- {
- // copy these to local variables so they can be stored in registers
- // (volatile variables must be read from memory on every access)
- unsigned long m = timer0_millis;
- unsigned char f = timer0_fract;
- m += MILLIS_INC;
- f += FRACT_INC;
- if (f >= FRACT_MAX) {
- f -= FRACT_MAX;
- m += 1;
- }
- timer0_fract = f;
- timer0_millis = m;
- timer0_overflow_count++;
- }
复制代码
简单的说,设置Timer0 1ms触发一次,然后其中的计数器会自动加1。同样的文件中还能看到millis( ) micros() 和delay() 函数都用到这个计数值。所以有如下结论:
1. 如果修改了Timer0的计时频率,这些函数都会受到影响
2. 如果你关闭了Timer0,那么这些函数都会失效
3. 如果你是编写中断服务,进入你的服务程序之后,关闭了中断,那么不可以使用这些函数
我们尝试修改这个文件,插入翻转pin的代码,可以看到,示波器上一直显示电平有变化 - #if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
- ISR(TIM0_OVF_vect)
- #else
- ISR(TIMER0_OVF_vect)
- #endif
- {
- // copy these to local variables so they can be stored in registers
- // (volatile variables must be read from memory on every access)
- unsigned long m = timer0_millis;
- unsigned char f = timer0_fract;
- m += MILLIS_INC;
- f += FRACT_INC;
- if (f >= FRACT_MAX) {
- f -= FRACT_MAX;
- m += 1;
- }
- timer0_fract = f;
- timer0_millis = m;
- timer0_overflow_count++;
- //LABZ_Debug_Start
- digitalWrite(9,LOW);
- digitalWrite(9,HIGH);
- digitalWrite(9,LOW);
- //LABZ_Debug_End
- }
复制代码
验证的代码非常简单: - void setup() {
- // put your setup code here, to run once:
- pinMode(9,OUTPUT);
- }
- void loop() {
- }
复制代码
运行结果
放大之后可以看出间隔在1ms左右
同样的程序我们在主程序中使用noInterrupts关掉中断,显示出来始终为低电平,因为Timer0也被关掉了。 - void setup() {
- // put your setup code here, to run once:
- pinMode(9,OUTPUT);
- noInterrupts();
- }
- void loop() {
- // put your main code here, to run repeatedly:
- }
复制代码
运行结果
当然,某些时候我们只需要关闭Timer0的中断,可以用屏蔽溢出中断的方法,设置TOIE0为0即可。 - cbi (TIMSK0, TOIE0);
- #define OutPin 8
- #ifndef cbi
- #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
- #endif
- #ifndef sbi
- #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
- #endif
- void setup() {
- // put your setup code here, to run once:
- pinMode(OutPin,OUTPUT);
- digitalWrite(OutPin,LOW);
- cbi (TIMSK0, TOIE0);
- }
- void loop() {
- // put your main code here, to run repeatedly:
-
- }
复制代码
和上图没差别。
直接关闭Timer0的source也能达到关闭TImer0的效果,设置CS00==CS01==CS02
bitWrite(TCCR0B, CS00, 0);
bitWrite(TCCR0B, CS01, 0);
bitWrite(TCCR0B, CS02, 0);
- #define OutPin 9
- void setup() {
- // put your setup code here, to run once:
- pinMode(OutPin,OUTPUT);
- digitalWrite(OutPin,LOW);
- }
- void loop() {
- delay(1000);
- bitWrite(TCCR0B, CS00, 0);
- bitWrite(TCCR0B, CS01, 0);
- bitWrite(TCCR0B, CS02, 0);
- delayMicroseconds(10000);
- digitalWrite(OutPin,HIGH);
- }
复制代码
进入 loop函数之后 delay 1s 持续有中断产生,之后关闭了中断就出现一直为低的情况,接下来是10ms的delay,最后再拉高(这样只是为了让波形清晰可辩)。
特别注意:如果用delay替换delayMicroseconds,那么看到的波形将会是一直为低。读者可以思考一下原因。
参考:
1. http://letsmakerobots.com/node/28278 Arduino 101: Timers and Interrupts
2. \arduino-1.6.3\hardware\arduino\avr\cores\arduino\Arduino.h
#define interrupts() sei()
#define noInterrupts() cli()
3. https://arduinodiy.wordpress.com/2012/02/28/timer-interrupts/
Clock Select bit description
CS12 CS11 CS10 Description
0 0 0 No clock source (Timer/Counter stopped)
0 0 1 clki/o/1 (No prescaling)
0 1 0 clki/o/8 (From Prescaler)
0 1 1 clki/o/64 (From Prescaler)
1 0 0 clki/o/256 (From Prescaler)
1 0 1 clki/o/1024 (From Prescaler)
1 1 0 External clock source on T1 pin. Clock on falling edge
1 1 1 External clock source on T1 pin. Clock on rising edge
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
|