极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 10995|回复: 1

用示波器“看” arduino (4) ----Timer0

[复制链接]
发表于 2015-11-17 10:33:20 | 显示全部楼层 |阅读模式
Arduino 默认使用了 Timer0 【参考1】,在 \arduino-1.6.3\hardware\arduino\avr\cores\arduino\wiring.c 有

  1. #if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  2. ISR(TIM0_OVF_vect)
  3. #else
  4. ISR(TIMER0_OVF_vect)
  5. #endif
  6. {
  7.         // copy these to local variables so they can be stored in registers
  8.         // (volatile variables must be read from memory on every access)
  9.         unsigned long m = timer0_millis;
  10.         unsigned char f = timer0_fract;

  11.         m += MILLIS_INC;
  12.         f += FRACT_INC;
  13.         if (f >= FRACT_MAX) {
  14.                 f -= FRACT_MAX;
  15.                 m += 1;
  16.         }

  17.         timer0_fract = f;
  18.         timer0_millis = m;
  19.         timer0_overflow_count++;
  20. }
复制代码


简单的说,设置Timer0 1ms触发一次,然后其中的计数器会自动加1。同样的文件中还能看到millis( ) micros() 和delay() 函数都用到这个计数值。所以有如下结论:
1.        如果修改了Timer0的计时频率,这些函数都会受到影响
2.        如果你关闭了Timer0,那么这些函数都会失效
3.        如果你是编写中断服务,进入你的服务程序之后,关闭了中断,那么不可以使用这些函数

我们尝试修改这个文件,插入翻转pin的代码,可以看到,示波器上一直显示电平有变化
  1. #if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  2. ISR(TIM0_OVF_vect)
  3. #else
  4. ISR(TIMER0_OVF_vect)
  5. #endif
  6. {
  7.         // copy these to local variables so they can be stored in registers
  8.         // (volatile variables must be read from memory on every access)
  9.         unsigned long m = timer0_millis;
  10.         unsigned char f = timer0_fract;

  11.         m += MILLIS_INC;
  12.         f += FRACT_INC;
  13.         if (f >= FRACT_MAX) {
  14.                 f -= FRACT_MAX;
  15.                 m += 1;
  16.         }

  17.         timer0_fract = f;
  18.         timer0_millis = m;
  19.         timer0_overflow_count++;
  20.         //LABZ_Debug_Start
  21.         digitalWrite(9,LOW);
  22.         digitalWrite(9,HIGH);
  23.         digitalWrite(9,LOW);       
  24.         //LABZ_Debug_End
  25. }
复制代码


验证的代码非常简单:
  1. void setup() {
  2.   // put your setup code here, to run once:
  3.   pinMode(9,OUTPUT);
  4. }
  5. void loop() {
  6. }
复制代码


运行结果


放大之后可以看出间隔在1ms左右


同样的程序我们在主程序中使用noInterrupts关掉中断,显示出来始终为低电平,因为Timer0也被关掉了。
  1. void setup() {
  2.   // put your setup code here, to run once:
  3.   pinMode(9,OUTPUT);
  4.   noInterrupts();
  5. }

  6. void loop() {
  7.   // put your main code here, to run repeatedly:

  8. }
复制代码


运行结果


当然,某些时候我们只需要关闭Timer0的中断,可以用屏蔽溢出中断的方法,设置TOIE0为0即可。
  1. cbi (TIMSK0, TOIE0);

  2. #define OutPin 8
  3. #ifndef cbi
  4. #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
  5. #endif
  6. #ifndef sbi
  7. #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
  8. #endif

  9. void setup() {
  10.   // put your setup code here, to run once:
  11.   pinMode(OutPin,OUTPUT);
  12.   digitalWrite(OutPin,LOW);
  13.   cbi (TIMSK0, TOIE0);
  14. }

  15. void loop() {
  16.   // put your main code here, to run repeatedly:
  17.   
  18. }
复制代码


和上图没差别。

直接关闭Timer0的source也能达到关闭TImer0的效果,设置CS00==CS01==CS02
bitWrite(TCCR0B, CS00, 0);
bitWrite(TCCR0B, CS01, 0);
bitWrite(TCCR0B, CS02, 0);

  1. #define OutPin 9

  2. void setup() {
  3.   // put your setup code here, to run once:
  4.   pinMode(OutPin,OUTPUT);
  5.   digitalWrite(OutPin,LOW);

  6. }

  7. void loop() {
  8.   delay(1000);
  9.   bitWrite(TCCR0B, CS00, 0);
  10.   bitWrite(TCCR0B, CS01, 0);
  11.   bitWrite(TCCR0B, CS02, 0);  
  12.   delayMicroseconds(10000);
  13.   digitalWrite(OutPin,HIGH);   
  14. }
复制代码


进入 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
回复

使用道具 举报

发表于 2015-11-17 14:40:37 | 显示全部楼层
深度好文章
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-23 17:23 , Processed in 0.041461 second(s), 19 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表