Arduino Uno 定时器中断 timer 0,1, 2 (自定义配置、MsTimer2、TimerOne库)

Arduino Uno 定时器中断 timer 0,1, 2 (自定义配置、MsTimer2、TimerOne库)

定时器简介

Arduino UNO有三个定时器,

timer0:一个被Arduino的delay(), millis()和micros()使用的8位定时器
timer1:一个被Arduino的Servo()库使用的16位定时器
timer2:一个被Arduino的Tone()库使用的8位定时器

"Arduino Mega"板有另外三个可使用的timer(3,4,5)

每个定时器都有一个计数器,在计时器的每个时钟周期递增。当计数器达到存储在比较匹配寄存器中指定值时触发CTC(Clear Timer on Compare Match)定时器中断

一旦定时器计数器达到该值,它将在定时器时钟的下一个定时器上清零(复位为零),然后它将继续再次计数到比较匹配值。

通过选择比较匹配值并设置定时器递增计数器的速度,你可以控制定时器中断的频率。

根据定时周期的大小以及时钟使用情况(是否与已使用库冲突)来选择不同的定时器。

相关数值计算

Arduino时钟以 16MHz 运行。计数器的一个刻度值表示1 / 16,000,000秒(~63ns),跑完1s需要计数值16,000,000。

1、Timer0和timer2是8位定时器,可以存储最大计数器值255。

2、Timer1是一个16位定时器,可以存储最大计数器值65535。

一旦计数器达到其最大值,它将回到零(这称为溢出)。
因此,需要对时钟频率进行分频处理,即预分频器。通过预分频器控制定时计数器的增量速度

预分频器(prescaler)与定时器的计数速度如下:

定时器速度(HZ) = Arduino时钟速度(16MHz) / 预分频器系数

因此,1预分频器将以16MHz递增计数器,8预分频器将在2MHz递增,64预分频器= 250kHz,依此类推。

由中断频率公式:

中断频率(Hz)=(Arduino时钟速度16MHz)/(预分频器*(比较匹配寄存器+ 1)

可以计算一定中断频率下,比较匹配寄存器的预设值为:

比较匹配寄存器 = [16,000,000Hz / (预分频器*所需的中断频率)] - 1

当你使用定时器0和2时,这个数字必须小于256,对于timer1小于65536。

如果你想每秒一次中断(频率为1Hz),采用最大预分频器为1024,此时,比较匹配寄存器 = [16,000,000 /(1024 * 1)] -1 = 15624,因为256 <15624 <65536,你必须使用timer1来实现这个中断。

1. 自定义配置 timer0, 1, 2

Arduino定时器配置(Timer0,Timer1,Timer2)
Arduino-Timer-Interrupts

//https://www.instructables.com/id/Arduino-Timer-Interrupts/

void setup(){

	noInterrupts();//stop interrupts
	
	//set timer0 interrupt at 2kHz
	TCCR0A = 0;// set entire TCCR0A register to 0
	TCCR0B = 0;// same for TCCR0B
	TCNT0  = 0;//initialize counter value to 0
	// set compare match register for 2khz increments
	OCR0A = 124;// = (16*10^6) / (2000*64) - 1 (must be <256)
	// turn on CTC mode
	TCCR0A |= (1 << WGM01);
	// Set CS01 and CS00 bits for 64 prescaler
	TCCR0B |= (1 << CS01) | (1 << CS00);   
	// enable timer compare interrupt
	TIMSK0 |= (1 << OCIE0A);
	
	//set timer1 interrupt at 1Hz
	TCCR1A = 0;// set entire TCCR1A register to 0
	TCCR1B = 0;// same for TCCR1B
	TCNT1  = 0;//initialize counter value to 0
	// set compare match register for 1hz increments
	OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
	// turn on CTC mode
	TCCR1B |= (1 << WGM12);
	// Set CS10 and CS12 bits for 1024 prescaler
	TCCR1B |= (1 << CS12) | (1 << CS10);  
	// enable timer compare interrupt
	TIMSK1 |= (1 << OCIE1A);
	
	//set timer2 interrupt at 8kHz
	TCCR2A = 0;// set entire TCCR2A register to 0
	TCCR2B = 0;// same for TCCR2B
	TCNT2  = 0;//initialize counter value to 0
	// set compare match register for 8khz increments
	OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
	// turn on CTC mode
	TCCR2A |= (1 << WGM21);
	// Set CS21 bit for 8 prescaler
	TCCR2B |= (1 << CS21);   
	// enable timer compare interrupt
	TIMSK2 |= (1 << OCIE2A);
	
	interrupts();//allow interrupts

}//end setup
 
// timer0 callback
ISR(TIMER0_COMPA_vect){
	
}
 
// timer1 callback 
ISR(TIMER1_COMPA_vect){

}
 
// timer2 callback  
ISR(TIMER2_COMPA_vect){

}
 
void loop(){
  
}
  • OCR#A 表示 timer# 的比较匹配寄存器值;

  • TCNT# 表示 timer# 的当前的计数值,可在任意时刻自定义赋值

  • TCCR0A |= (1 << WGM01);//for timer0
    TCCR1B |= (1 << WGM12);//for timer1
    TCCR2A |= (1 << WGM21);//for timer2
    针对三个不同的定时器打开CTC模式;

  • TCCR#B 进行 CS#0 , CS#1 , CS#2 移位配置预分频器系数(1, 8, 64, 256, 1024)
    请注意,在最后一步中,不同的计时器有不同的预分频系数。 例如,timer2 没有 1024 预分频器。
    定时器预分频系数配置表:
    在这里插入图片描述

  • TIMSK# |= (1 << OCIE#A); 启用 timer# 定时器比较中断。

  • 最后编写定时器 timer# 溢出执行的中断服务函数:ISR(TIMER#_COMPA_vect){ }
    此外,尽量使中断函数尽可能短,尤其是在以高频率中断时。
    甚至可以直接对ATMEL芯片的端口/引脚进行寻址,而不是使用digitalWrite() 和 digitalRead()功能。

2. MsTimer2 库

MsTimer2库github
arduino官方手册

该库在 timer2 上“硬编码”了分辨率为 1毫秒 的定时中断。

example:

// Toggle LED on pin 13 each second
#include <MsTimer2.h>

void flash() {
  static boolean output = HIGH;
  digitalWrite(13, output);
  output = !output;
}

void setup() {
  pinMode(13, OUTPUT);
  MsTimer2::set(500, flash); // 500ms period
  MsTimer2::start();	// enables the interrupt.
  // MsTimer2::stop();	// disables the interrupt.
}

void loop() {
}

3. TimerOne 库

github
arduino官方手册

该库使用 timer1 产生自定义载波频率下不同 pwm 占空比输出 和 定时器中断

#include <TimerOne.h>

void setup()
{
pinMode(10, OUTPUT);
Timer1.initialize(500000); // initialize timer1, and set a 1/2 second period
Timer1.pwm(9, 512); // setup pwm on pin 9, 50% duty cycle
Timer1.attachInterrupt(callback); // attaches callback() as a timer overflow interrupt
}

void callback()
{
digitalWrite(10, digitalRead(10) ^ 1);	// 状态翻转
}

void loop()
{
// your program here...
}
  • 注意事项:

(1)如果你使用了 MsTimer2 库, 则 pin11 和 pin3 就不能再用做 PWM 输出了! 因为该 pin3 和 pin11 的 PWM 是靠 timer2 帮忙的! (tone()也是)
(2)注意 Servo.h 库与 TimerOne 都是使用内部定时器 timer1 会影响pin 9, pin 10 的 PWM
(3)tone() 使用 timer2 定时器; 若使用 Tone 库的 Tone 对象(Tone 变量)也是优先使用 timer2 定时器,若用两个 Tone 变量则 timer1 也会被用掉, 用三个 Tone 则连控制 millis( )的 timer0 也会被用掉。
(4)别忘了, timer0 负责帮忙控制 pin 5 和 pin 6 的 PWM 输出。只要不去改变 timer 的 Prescaler 就不会影响其控制的 PWM pin, 但MsTimer2 库与 tone( )都会改变 Prescaler ! !

  • 15
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值