如何使用Arduino创建计时器中断?


9

我试图用Arduino创建一个延时中断。我想使用interrupts()函数,因为它是一个内部中断。

示例:假设我想让灯光闪烁,并且只显示中断时间。

有示例代码,但是它使用外部中断(attachInterrupt())。我想继续使用内部中断。


2
我认为,科尔特克(Kortuk)也表明的一点是,attachInterrupt是抽象的东西,您没有附加任何外部组件:)
clabacchio

本文可能会为您提供帮助。engblaze.com/…–
塞斯·阿切尔·布朗

Answers:


10

Noah Stahl的博客中有一个使用Timer2使LED闪烁的示例。有了该手册和数据手册,您应该能够使其适应于要使用的任何中断,即您最有能力放弃或愿意修改其正常功能的中断。Timer2通常用于某些PWM功能。

他的例子引用了ATmega2560。我可以确认它也可以与ATmega328p一起使用。在他的站点周围查看更多有用的Arduino中断示例。

编辑:

这是我经过稍微编辑的-大部分是在注释中-挪亚代码的版本。初始化任何相关的数据结构或硬件后,请从Arduino setup()函数调用Timer2init(),因为计时和中断将在您执行后立即开始。

F / ex,我用它来多路复用3位7段显示器,所以在初始化计时器之前,我初始化了显示I / O寄存器,并在ISR寻找它的地方清空了显示数据。

数据表中的一些有用的时序数据和我自己的计算的注释中有一个表格,供您参考以建立另一个时序方案。

ISR()宏负责为ISR创建中断入口和出口代码,而不是正常函数的入口和出口,并将其与适当的中断向量链接。该功能的其余部分是1)在每个中断处运行的代码,以及2)为下一个中断重置计时器的代码。

如所写,这应放入.pde或.ino草图(如果使用eclipse,则为.cpp文件,f / ex)。草图需要#define LEDPIN,而setup()需要调用Timer2init()。循环功能可以为空或不为空;LED应该在下载时开始闪烁(好吧,从字面上看,在调用Timer2init()之后)。

/*
 * From sample interrupt code published by Noah Stahl on his blog, at:
 * http://arduinomega.blogspot.com/p/arduino-code.html
 * 
 */


/*** FUNC

Name:           Timer2init

Function:       Init timer 2 to interrupt periodically. Call this from 
                the Arduino setup() function.

Description:    The pre-scaler and the timer count divide the timer-counter
                clock frequency to give a timer overflow interrupt rate:

                Interrupt rate =  16MHz / (prescaler * (255 - TCNT2))

        TCCR2B[b2:0]   Prescaler    Freq [KHz], Period [usec] after prescale
          0x0            (TC stopped)     0         0
          0x1                1        16000.        0.0625
          0x2                8         2000.        0.500
          0x3               32          500.        2.000
          0x4               64          250.        4.000
          0x5              128          125.        8.000
          0x6              256           62.5      16.000
          0x7             1024           15.625    64.000


Parameters: void

Returns:    void

FUNC ***/

void Timer2init() {

    // Setup Timer2 overflow to fire every 8ms (125Hz)
    //   period [sec] = (1 / f_clock [sec]) * prescale * (255-count)
    //                  (1/16000000)  * 1024 * (255-130) = .008 sec


    TCCR2B = 0x00;        // Disable Timer2 while we set it up

    TCNT2  = 130;         // Reset Timer Count  (255-130) = execute ev 125-th T/C clock
    TIFR2  = 0x00;        // Timer2 INT Flag Reg: Clear Timer Overflow Flag
    TIMSK2 = 0x01;        // Timer2 INT Reg: Timer2 Overflow Interrupt Enable
    TCCR2A = 0x00;        // Timer2 Control Reg A: Wave Gen Mode normal
    TCCR2B = 0x07;        // Timer2 Control Reg B: Timer Prescaler set to 1024
}



/*** FUNC

Name:       Timer2 ISR

Function:   Handles the Timer2-overflow interrupt

Description:    Maintains the 7-segment display

Parameters: void

Returns:    void

FUNC ***/

ISR(TIMER2_OVF_vect) {
    static unsigned int led_state = 0; // LED state

    led_state = !led_state;         // toggles the LED state
    digitalWrite(TOGGLE_PIN, led_state);

    TCNT2 = 130;     // reset timer ct to 130 out of 255
    TIFR2 = 0x00;    // timer2 int flag reg: clear timer overflow flag
};

(@Kortuk:您所指的评论是我对这里的几位评论员的观察,并不针对您个人,这是不必要的。我很抱歉,我已将其删除。)我按照您的建议扩大了回答的范围,我希望它是现在不仅具有示范性,而且具有启发性。它包括我自己编写的代码注释(表示:如果我能在6个月后理解它们,其他人也可以),以及其中的一些“使用方法”说明。回答。感谢您的建议。
JRobert 2012年

请注意,timer0和timer1不能使用32和128的预分频比(atmega328至少与此相对)。
tuupola'2

很高兴知道-谢谢。我将它用于Timer2(到目前为止),它基本上是一个插件。
JRobert

5

所述attachInterrupt()函数实际上是附着中断到管脚上的外部状态的变化,它不具有任何其他选项。

同一页面上,模式选项列出为:

模式定义何时触发中断。预定义了四个常量作为有效值:

  • 低电平,只要引脚为低电平就触发中断,
  • 更改以在引脚更改值时触发中断
  • RISING当引脚从低到高来触发,
  • 了当引脚从高电平变为低电平。

很抱歉成为坏消息的承担者,这也是我寻找的第一件事。


我认为他的意思是他想使用内部计时器而不是外部设备...但是我不太了解Arduino,所以我不能说这是否可能
clabacchio

@clabacchio,我是说唯一的选择是使用外部触发器,没有内部计时器功能。
Kortuk

啊,很好:)但是,至少Arduino板有定时器吗?
clabacchio

是的,这就是他们完成延迟等事情的方式。
2012年

1
@ icarus74 ATMega328实际上有3个计时器(一个是16b,两个是8b),但是它们都被Arduino使用。其中一个用于delay()和millis()之类的函数,所有三个用于PWM(您可以在Arduino IDE中的函数“ init()”和文件“ wiring.c”中找到更多信息)。
vasco 2012年

2

关于PWM的这篇文章将消除您对Arduino定时器的使用的许多疑问。Arduino上有两个8位定时器和一个16位定时器。没有高级SDK将ISR函数直接连接到计时器,这是Arduino SDK附带的(即作为标准库),但是设置特殊功能寄存器和位算术/对它们的操作。但是,有一个用户贡献的库称为Timer one


实际上,取决于所指的Arduino,有几种可能的计时器组合。答案具有误导性。
看来如此

@SeeminglySo,要详细说明吗?如果您在谈论Arduino硬件,请注意,答案是在问题的上下文中以及提出问题的时间。
icarus74

Arduino Mega(基于ATmega1280)于2009年3月26日发布,Mega 2560(ATmega2560)于2010年9月24日发布,两者均在提出该问题之前就已经存在。这两个微控制器都具有答案中指定的2x 8位和1x 16位定时器/计数器。
看来如此

到目前为止,我所看到的大多数交互都对Arduino有明确的引用,以表示Duemilanove或Uno之类的东西,即基于328系列的开发板。其他电路板始终已通过uP系列编号明确认证。或Mega,Nano,Micro等。无论如何,我会虚心接受更正。在这种情况下,澄清会更好。
icarus74

1

Arduino正在ATMega328中使用所有三个计时器。Timer1(16位)用于诸如delay()millis()等功能,以及在引脚5和6上的PWM输出。其他两个定时器,Timer0并且Timer2用于引脚3、9、10、11上的PWM输出。

因此,没有用于中断定时器的Arduino功能。但是有办法。您可以使用以下代码在以下位置启用计时器中断Timer2

ISR(TIMER2_OVF_vect) {
  // Interrupt routine.
}

void setup() {
  // Enable Timer2 interrupt.
  TIMSK2 = (0<<OCIE2A) | (1<<TOIE2);
}

void loop() {
  // Your main loop.
}

我编写此代码时没有进行测试,所以有可能我犯了一个错误。在这种情况下,请检查数据表,第156页

如果要更改定时器频率(预分频器),只需更改寄存器TCCR2A。欲了解更多信息,请参见第153页的数据表。但是,如果您更改定时器的频率,则还要更改两个输出引脚上的PWM信号的频率!


据我所知在ATmega328 Timer0Timer28位,仅Timer1是16位。
tuupola'2

不,这是不正确的。它是Timer0而不是Timer1,用于delay()和millis()以及引脚5和6上的PWM输出。Timer0是一个8位定时器。参见例如Arduino定时器和中断
彼得·莫滕森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.