我试图用Arduino创建一个延时中断。我想使用interrupts()函数,因为它是一个内部中断。
示例:假设我想让灯光闪烁,并且只显示中断时间。
有示例代码,但是它使用外部中断(attachInterrupt())。我想继续使用内部中断。
我试图用Arduino创建一个延时中断。我想使用interrupts()函数,因为它是一个内部中断。
示例:假设我想让灯光闪烁,并且只显示中断时间。
有示例代码,但是它使用外部中断(attachInterrupt())。我想继续使用内部中断。
Answers:
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
};
所述attachInterrupt()函数实际上是附着中断到管脚上的外部状态的变化,它不具有任何其他选项。
在同一页面上,模式选项列出为:
模式定义何时触发中断。预定义了四个常量作为有效值:
- 低电平,只要引脚为低电平就触发中断,
- 更改以在引脚更改值时触发中断
- RISING当引脚从低到高来触发,
- 降了当引脚从高电平变为低电平。
很抱歉成为坏消息的承担者,这也是我寻找的第一件事。
关于PWM的这篇文章将消除您对Arduino定时器的使用的许多疑问。Arduino上有两个8位定时器和一个16位定时器。没有高级SDK将ISR函数直接连接到计时器,这是Arduino SDK附带的(即作为标准库),但是设置特殊功能寄存器和位算术/对它们的操作。但是,有一个用户贡献的库称为Timer one。
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信号的频率!
Timer0
和Timer2
8位,仅Timer1
是16位。