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

电器工程 Arduino 微控制器 中断
2022-01-09 02:56:31

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

示例:假设我想让灯闪烁,只有中断的时间。

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

4个回答

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 草图(或 .cpp 文件,如果您使用 eclipse,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
};

attachInterrupt ()函数实际上是将中断附加到引脚上的外部状态更改,它没有任何其他选项。

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

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

  • 低电平触发中断,只要引脚为低电平,
  • CHANGE在引脚改变值时触发中断
  • 当引脚从低电平变为高电平时,RISING触发,
  • 当引脚从高电平变为低电平时为FALLING 。

很抱歉成为坏消息的承担者,这也是我首先寻找的东西之一。

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

Arduino 正在使用 ATMega328 中的所有三个计时器。Timer1(16 位)用于引脚 5 和 6 上的 PWM 输出等功能delay()另外millis()两个定时器用于引脚 3、9、10、11 上的 PWM 输出。Timer0Timer2

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

ISR(TIMER2_OVF_vect) {
  // Interrupt routine.
}

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

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

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

如果要更改定时器频率(预分频器),只需更改 register TCCR2A有关更多信息,请查看数据表第 153 页。但是,如果您更改定时器的频率,您也会更改两个输出引脚上 PWM 信号的频率!