2018-03-20 timer
https://arduino-info.wikispaces.com/Timers-Arduino
什么是timer 计时器?
定时器或更精确的计时器/计数器是内置在 Arduino 控制器中的硬件 (其他控制器也有定时器硬件)。它就像一个时钟, 可以用来测量时间事件。定时器可以由一些特殊的寄存器编程。您可以为定时器配置分频器, 或操作模式和许多其他事情。
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。
所有计时器都依赖于您的 Arduino 系统的系统时钟。通常系统时钟是 16MHz, 但为 Arduino Pro 3.3V 它是8Mhz。因此, 在编写自己的计时器功能时要小心。
定时器硬件可以配置一些特殊的定时器寄存器。在 Arduino 固件中, 所有计时器都配置为1kHz 频率, 通常会启用中断。
Timer0: 8bit 定时器。
在 Arduino 世界中, timer0 被用于软件素描定时器功能, 如 __delay (), __millis () 和 __micros ()。如果更改 timer0 寄存器, 这可能会影响 Arduino 计时器函数。所以你应该知道你在做什么。
Timer1: 16bit 定时器。
在 Arduino 世界, __Servo library__ 使用 timer1 Arduino (timer5)。
Timer2: 8bit 定时器。
在 Arduino 中, __tone () 函数使用 timer2。
Timer3, Timer4, Timer5: 16bit 定时器
定时器 3,4,5 只在 Arduino maga板上可用。
定时器寄存器
您可以通过计时器寄存器更改计时器的行为。最重要的计时器寄存器是:
TCCRx 定时器/计数器控制寄存器。可配置分频。
TCNTx 计时器/计数器寄存器。实际的计时器值存储在此。
OCRx-输出比较寄存器
ICRx 输入捕获寄存器 (仅用于16bit 定时器)
TIMSKx 定时器/计数器中断掩码寄存器。启用/禁用计时器中断。
TIFRx-计时器/计数器中断标记寄存器。指示挂起的计时器中断。
时钟选择和定时器频率
可以单独为每个计时器选择不同的时钟源。要计算定时器频率 (例如, 使用 timer1 的 2Hz), 您将需要:
Arduino 的 CPU 频率16Mhz
最大定时器计数器值 (256 为 8bit, 65536 为16bit 定时器)
将 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。使用这种方式, 输出会与 CPU 同时运行, 并且不会中断任何程序。
PWM 在后台运行, 如TCT, 但在 pin 输出的时间是不同的。它更适合于像伺服这样的设备, 以脉宽调制为输入。
如果你要做的是输出 pin, 使用TCT或 PWM。如果你想做的更多, 使用正常模式 (或TCT或 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 兆位)。后缀 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 兆我们有6定时器和 15 PWM 输出:
引脚4和 13: 由 timer0 控制
引脚11和 12: 由 timer1 控制
引脚 9 and10: 由 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 兆的不同计时器中。所有移植库都可以在该页顶部链接的库中找到。
陷阱:
在编程 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 23, 51112444546)。对于48伺服所有16bit 定时器 51, 3 和4将使用 (失去所有 PWM 针)。
Pin 11 具有共享功能 PWM 和莫西奥图尼亚。spi 接口需要莫西奥图尼亚, 在 Arduino 上不能同时使用 Pin 11 和 SPI 接口上的 PWM。在 Arduino 兆, SPI 针脚在不同的针脚上。
音调 () 函数使用至少 timer2。你不能在 Pin 311 使用 PWM, 当你使用音调 () 函数的 Arduino 和针910在 Arduino 兆。
例子:
一些例子的时间。
(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位定时器