https://arduino-info.wikispaces.com/Timers-Arduino
什么是timer 计时器?
是内置在 控制器中的硬件。它就像一个时钟, 可以用来测量时间事件。定时器可以由一些寄存器编程。可以为定时器配置分频器, 或操作模式。
Arduino 的控制器---- Atmel AVR ATMega 168 或 ATmega328。这些芯片是 pin 兼容的, 只有内部内存大小不同。两者都有3个定时器, 叫做 timer0、timer1 和 timer2。Timer0 和 timer2 是8bit 定时器, 其中 timer1 是16bit 定时器。8bit 和16bit 定时器之间最重要的区别是定时器分辨率。8bits 表示256值, 其中16bit 表示65536值, 用于更高的分辨率或更长的计数。
Arduino maga 控制器---- Atmel AVR ATmega1280 或 ATmega2560。内存大小不同。这些控制器有6个定时器。定时器 0, timer1 和 timer2 与ATmega168/328一样。timer3、timer4 和 timer5 都是16bit 定时器, 类似于 timer1。
还有,Leonard 控制器,32u4。
计时器依赖于 Arduino 系统的系统时钟。通常系统时钟是 16MHz,。
但为 Arduino Pro 3.3V 它是8Mhz。因此, 在编写计时器功能时要小心。
定时器硬件可以配置一些特殊的定时器寄存器。在 Arduino 固件中,
----所有计时器都配置为1kHz 频率,
----通常会启用中断。
Timer0: 8bit 定时器。pin 5,pin 6
在 Arduino 世界中, timer0 被用于软件素描定时器功能, 如 __delay (), __millis () 和 __micros ()。如果更改 timer0 寄存器, 这可能会影响 Arduino 计时器函数。所以你应该知道你在做什么。
Timer1: 16bit 定时器。pin 9, pin 10
在 Arduino 世界, __Servo library__ 使用 timer1 Arduino (timer5)。
Timer2: 8bit 定时器。 pin 11, pin 3
在 Arduino 中, __tone () 函数使用 timer2。
Timer3, Timer4, Timer5: 16bit 定时器
定时器 3,4,5 只在 Arduino maga板上可用。
定时器寄存器
您可以通过计时器寄存器更改计时器的行为。最重要的计时器寄存器是:
TCCRx 定时器/计数器控制寄存器。可配置分频。
TCNTx 计时器/计数器寄存器。实际的计数值存储在此,计数从小到大(或者从小到大,再到小)。
OCRx-输出比较寄存器。计数到达此数时,输出中断。
ICRx 输入捕获寄存器 (仅用于16bit 定时器)
TIMSKx 定时器/计数器中断掩码寄存器。启用/禁用计时器中断。
TIFRx-计时器/计数器中断标记寄存器。指示挂起的计时器中断。
时钟选择和定时器频率
可以单独为每个计时器选择不同的时钟源。要计算定时器频率 (例如, 使用 timer1 的 2Hz), 您将需要:
Arduino 的 CPU 频率16Mhz
最大定时器计数器值 ( 8bit 为 256, 16bit 为 65536)
将 CPU 频率除以所选的分频 (16000000/256 = 62500)
通过所需频率除以结果 (62500/2Hz = 31250)
根据最大定时器计数器值验证结果 (31250 <65536 可行) 如果失败, 选择更大的分频。
定时器模式
可以用不同的模式配置计时器。
正常模式(普通溢出中断模式),
PWM 模式。(脉宽调制模式): OCxy 输出用于产生 PWM 信号
TCT模式。在比较匹配时清除计时器。当计时器计数器到达比较匹配寄存器时, 计时器将被清除
(下面一小段来自 https://stackoverflow.com/questions/26599618/avr-timer-programming-ctc-mode-vs-normal-mode)
普通中断模式下, 计时器触发中断处理程序。可执行任何功能, 但中断程序在 CPU 上运行时, 这会阻止其他进程。
在TCT模式下, 可以不使用中断(也可以触发中断), 直接输出 到pin。使用这种方式, 输出pin会与 CPU 同时运行, 不会中断CPU进程。
PWM 模式下同样在后台运行, 但在 pin 输出的时间是不同的。它更适合像舵机这样以脉宽调制作为输入的设备。
如果您只想切换输出pin引脚状态,请使用 CTC 或 PWM。如果您想做更多,请使用普通模式(或 CTC 或 PWM,取决于时序要求)。
不建议 在正常模式下,使用输出比较生成波形, 因为这将占用过多的 CPU 时间。
在TCT模式下生成波形输出, 可以将 OC1A 输出设置为:通过将比较输出模式位设置为切换模式 (COM1A1:0 = 1) 来切换每个比较匹配的数值大小。??
什么是中断?
运行在控制器上的程序通常按指令运行顺序指令。中断是中断正在运行的程序并运行特殊中断服务例程 (ISR) 的外部事件。在 ISR 完成后, 运行程序将继续执行下一指令。指令指的是单台机器指令, 而不是 c 或 c++ 代码行。
在挂起的中断可以调用 ISR 之前, 必须满足以下条件:
中断必须一般启用
必须启用根据中断掩码
全局 启用/禁用 中断, 功能 __interrupts () __noInterrupts () _。默认情况下, Arduino 固件中断被启用。
通过在中断掩码寄存器 (TIMSKx) 中设置/清除位来启用/禁用中断掩码。
发生中断时, 将设置中断标志寄存器 (TIFRx) 中的标志。在输入 ISR 或手动清除中断标志寄存器中的位时, 将自动清除此中断。
Arduino 函数 __attachInterrupt () ___ 和 __detachInterrupt () 只能用于外部中断针脚。这些是不同的中断源, 这里没有讨论。
定时器中断
计时器可以生成不同类型的中断。寄存器和位定义可以在处理器数据表中找到 (Atmega328 __or Atmega2560) 和 i/o 定义头文件 (iomx8. h 用于 Arduino, iomxx0_1. h 用于在硬件/工具/avr/包括/avr 文件夹中 Arduino maga位)。
后缀 x 代表计时器编号 (0.. 5),
后缀 y 代表输出数字 (A、B、C),
例如 TIMSK1 (timer1 中断掩码寄存器) 或 OCR2A (timer2 输出比较寄存器 A)。
定时器溢出:
定时器溢出意味着定时器已达到极限值。当发生计时器溢出中断时, 将在中断标记寄存器 TIFRx 中设置计时器溢出位 TOVx。在设置中断掩码寄存器 TIMSKx 中的计时器溢出中断启用位 TOIEx 时, 将调用计时器溢出中断服务例行 ISR (TIMERx_OVF_vect)。
输出比较匹配:
当发生输出比较匹配中断时, 将在中断标志寄存器 TIFRx 中设置 OCFxy 标志。如果设置了中断掩码寄存器 TIMSKx 中的输出比较中断启用位 OCIExy, 则将调用输出比较匹配中断服务 ISR (TIMERx_COMPy_vect) 例程。
定时器输入捕获:
当出现计时器输入捕获中断时, 输入捕获标志位 ICFx 将在中断标记寄存器 TIFRx 中设置。当输入捕获中断启用中断掩码寄存器 TIMSKx 中的位 ICIEx 时, 将调用计时器输入捕获中断服务例行 ISR (TIMERx_CAPT_vect)。
PWM 和定时器:
定时器和 PWM 能输出之间有固定的关系。当您查看数据表或处理器的引线时, 这些 PWM 功能针脚的名称如 OCRxA、OCRxB 或 OCRxC (其中 x 表示计时器编号 0... 5)。PWM 功能通常与其他 pin 功能共享。
Arduino 有3Timers 和 6 PWM 输出引脚。定时器和 PWM 输出的关系是:
引脚5和 6: 由 timer0 控制
引脚9和 10: 由 timer1 控制
引脚11和 3: 由 timer2 控制
Arduino maga 中 有6个定时器和 15个 PWM 输出:
pin 4 和 13: 由 timer0 控制
pin 11和 12: 由 timer1 控制
pin 9 和 10: 由 timer2 控制
Pin 2、3和 5: 由定时器3控制
Pin 6、7和 8: 由定时器4控制
Pin 46、45和 44:: 由计时器5控制
有用的第三方库:
存在一些非常有用的第三方库, 使用计时器:
__Ken Shirrifs 红外 library__。使用 timer2。发送和接收任何类型的红外远程信号, 如 RC5, RC6, 索尼
Timer1 和 Timer3 library__。使用 timer1 或 timer3。编写自己的计时器中断服务例程的简单方法。
RoboFreak 已经将这些库移植到了 Arduino 兆的不同计时器中。所有移植库都可以在该页顶部链接的库中找到。
debug 陷阱,隐患
在编程 Arduino 和使用使用计时器的函数或库时, 可能会遇到一些隐患。
舵机库使用 Timer1。在 Arduino 上使用舵机库时, 不能在 Pin 9 10 上使用 PWM。对于 Arduino 特大, 这是一个有点困难。需要的定时器取决于舵机的数量。每个定时器可以处理12舵机。为前12舵机定时器5将使用 (丢失 PWM 在别针 444546)。24舵机定时器5和1将使用 (失去 PWM 在 Pin 1112444546)。对于36舵机定时器 5, 1 和3将使用 (失去 PWM 在 Pin 2,3, 5,11,12,44,45,46)。对于48舵机所有16bit 定时器 51, 3 和4将使用 (失去所有 PWM pin)。
Pin 11 具有共享功能 PWM 和MOSI 。spi 接口需要MOSI, 在 Arduino 上不能同时使用 Pin 11 和 SPI 接口上的 PWM。在 Arduino maga, SPI 针脚在不同的针脚上。
音调 () 函数使用 timer2。你不能在 Pin 3,11 使用 PWM, 当你使用音调 () 函数的 Arduino 和针9,10在 Arduino mega。
例子:
一些例子的时间。
(1) 闪烁 LED 与比较匹配中断。
第一个示例使用 CTC 模式中的 timer1 和比较匹配中断来切换 LED。计时器配置为2Hz 的频率。在中断服务例程中 切换了指示灯。
......
(2) 带定时器溢出中断的闪烁指示灯
像以前一样的例子, 但现在我们使用定时器溢出中断。在这种情况下, timer1 在正常模式下运行。每次在中断服务例程中, 计时器都必须预先加载。
......
(3) 用定时器读取正交编码器
下一个示例是 RobotFreak 的 Ardubot 项目的一部分。它使用 timer2 和比较匹配中断来读取编码器输入。默认情况下, Timer2 初始化为 1kHz (1ms 句点) 的频率。在中断服务例程中, 读取所有编码器针脚的状态, 并使用状态机消除错误读数。使用计时器中断比使用4输入更改中断更容易处理。
正交编码器的信号是2bit 灰度代码。只有1位正在从状态更改为状态。状态机是完善的检查信号和计数编码器刻度。计时器必须足够快, 才能识别每个状态的变化。对于这里使用的 正交编码器, 1ms 定时器足够快了。
......
http://www.arduino.cn/thread-12815-1-1.html
timer 有 A 和 B 兩個通道,
通常第一个中断函数 ISR(TIMER1_COMPA_vect)会按你期望的 work,
而另一個ISR(TIMER1_COMPB_vect)不 Work 的原因
8位定时器
16位定时器