Arduino定时中断

Arduino定时中断

  • 定时器的作用
  • Arduino中的定时器
    • 具体使用
    • 操作定时寄存器
      • 寄存器
      • 频率的计算
      • 三种模式
      • 代码
  • 随笔
  • 参考文献

对于Arduino新手来说,刚开始使用实例的Blink亮灯代码,其实就开始进入了定时器的世界,因为其中的delay()函数就是通过定时定时器实现的,不过这些都被Arduino的封装库隐藏起来了,为了让使用者更快更便捷地开发项目,除了delay()函数,millis() ,micros() ,delayMicroseconds() ,PWM波生成的analogWrite()和tone() ,同时Servo库里面也使用了定时器。

接下来就进入Arduino定时器的世界,我同为新手,整理一下我的一些认识。

定时器的作用

定时器对于单片机来说就类似我们现实生活中的时钟,记录很多和时间相关的事件。

Arduino中的定时器

我主要使用的Arduino单片机为UNO,NANO和MEGA 2560。

UNO和NANO都使用的是ATmega328芯片,这款芯片有3个定时器,Timer0,Timer1,
Timer2,其中Timer0和Timer2都是8位寄存器(256),Timer1是16位寄存器(65536),意味着更高的分辨率。

mege2560使用的是ATmege2560芯片,这款芯片有6个定时器,在328的基础上,增加了Timer3,Timer4,Timer5。这三个定时器都是16位的寄存器。

用表格整理如下

定时器 位数 封装函数 mega2560引脚对应
Timer0 8bit delay() , millis() 和 micros()等 4,13
Timer1 16bit UNO的servo库 11,12
Timer2 8bit tone()等 9,10
Timer3 16bit 2,3,5
Timer4 16bit 6,7,8
Timer5 16bit mega2560的servo库 46,45,44

具体使用

可以到网上下载TimerOne, TimerThree等库文件,TimerOne.h就对应为timer1定时器。

TimerOne.h的下载链接:
https://www.arduinolibraries.info/libraries/timer-one

附上代码

#include<TimerOne.h>
#define state digitalRead(13)  //读出引脚13的状态
int i=1; //记录次数
void setup() 
{
	Timer1.initialize(100000);  //设置中断速度 1s
	Timer1.attachInterrupt(tongxun);  //关联中断函数
	Serial.begin(115200); //设置串口波特率
	
	interrupts(); //开启中断
}

void tongxun()
{
	i++;
	digitalWrite(13,!state); //亮灭交替
	if(i>=10)
	{
	  i=1;
	  digitalWrite(13,!state); //第十次亮灭灯时,事件多进行一次
	}
}

void loop() 
{
}

此时loop函数里面什么的没有写,但是烧录进单片机的时候每隔1s会进行亮灭灯,每隔10s停顿一次,这些完全依靠定时中断来完成,意味着你可以运行你的loop程序时,每隔一段时间就会进入中断函数中执行一次任务,在某种意义上让Arduino可以进行“多”线程的工作。

其他Timer的使用基本一样,只要找到合适的库函数就能够使用,注意使用的定时器不要和你已使用的封装函数冲突,比如对于UNO来说,你在使用Servo.h的时候,就不能再使用timer1了,此时IDE会给你编译报错。

操作定时寄存器

接下来可以来些高阶的定时器使用,之前使用的定时器库是别人已经给你封装好了的,你直接调用一些简单的函数就可以便捷地实现功能,如果想一探究竟,就可以操作寄存器来更深入地了解,更灵活地使用。

虽然Arduino成熟的封装极力避免用户进行寄存器的操作,让用户更专注于功能的实现。

寄存器这边我也知之甚少,搬运一些网上的内容吧。

寄存器

寄存器列表如下,x代表0,1,2,3,4,5这6种定时器

寄存器 作用
TCNTx 定时器/计数器寄存器。实际的计时器值存储在此处。
OCRx 输出比较寄存器
ICRx 输入捕捉寄存器(仅适用于16位定时器)
TIMSKx 定时器/计数器中断屏蔽寄存器。启用/禁用定时器中断。
TIFRx 定时器/计数器中断标志寄存器。表示挂起的定时器中断。

频率的计算

以timer2定时器50Hz为例
Arduino晶振16MHz,CPU分频(16000000/256=62500),产生10Hz频率(62500/50Hz=125),同8位256比较(125<256),可行
如果是10Hz,最后6250>256,不可行,就只能换分辨率更大的timer1了,16位,65536。

三种模式

x代表定时器编号0,1,2,3,4
y代表输出编号A,B,C

定时器溢出:
定时器溢出意味着定时器已达到限制值。发生定时器溢出中断时,定时器溢出位TOVx将在中断标志寄存器TIFRx中置1。当中断屏蔽寄存器TIMSKx中的定时器溢出中断使能位TOIEx置1时,将调用定时器溢出中断服务程序ISR(TIMERx_OVF_vect)。

输出比较匹配:
当输出比较匹配中断发生时,OCFxy标志将在中断标志寄存器TIFRx中置1。当中断屏蔽寄存器TIMSKx中的输出比较中断使能位OCIExy置1时,将调用输出比较匹配中断服务ISR(TIMERx_COMPy_vect)例程。

定时器输入捕获:
当发生定时器输入捕捉中断时,输入捕捉标志位ICFx将被设置在中断标志寄存器TIFRx中。当中断屏蔽寄存器TIMSKx中的输入捕捉中断使能位ICIEx置1时,将调用定时器输入捕捉中断服务程序ISR(TIMERx_CAPT_vect)。

代码

代码我涂涂改改了几次,可能会有问题,如果运行失败,你们再找别的代码试试吧,基本的配置和使用都在里面了。

boolean toggle1=0;

void setup() 
{
	cli(); //停止中断
	//设置2kHz的timer0中断
	TCCR0A = 0; //将整个TCCR0A寄存器设置为0
	TCCR0B = 0; // TCCR0B相同
	TCNT0 = 0; //将计数器值初始化为0
	//设置比较匹配寄存器2khz增量
	OCR0A = 124; // =(16 * 10 ^ 6)/(?Hz * 64) -  1(必须<256)   //比较匹配寄存器= [16,000,000Hz /(预分频器*所需中断频率)] - 1 
	//打开CTC模式                                                     // timer0 min 1kHz
	TCCR0A|=(1 << WGM01);
	//为64预分频器设置CS01和CS00位
	TCCR0B|=(1 << CS01)| (1 << CS00);   
	//启用定时器比较中断
	TIMSK0|=(1 << OCIE0A);
		
	//设置1Hz的timer1中断
	TCCR1A = 0; //将整个TCCR1A寄存器设置为016
	TCCR1B = 0; // TCCR1B相同
	TCNT1 = 0; //将计数器值初始化为0
	//设置比较匹配寄存器1hz的增量
	OCR1A = 15624; // =(16 * 10 ^ 6)/(?Hz* 1024) -  1(必须<65536)      //timer1 min //10hz
	//打开CTC模式
	TCCR1B|=(1<<WGM12);
	//为1024预分频器设置CS10和CS12位
	TCCR1B|=(1<<CS12)|(1<<CS10);  
	//启用定时器比较中断
	TIMSK1|=(1<<OCIE1A);
	
	//设置8kHz的timer2中断
	TCCR2A = 0; //将整个TCCR2A寄存器设置为0
	TCCR2B = 0; // TCCR2B相同
	TCNT2 = 0; //将计数器值初始化为0
	//设置比较匹配寄存器为8khz增量
	OCR2A = 249; // =(16 * 10 ^ 6)/(?Hz* 8) -  1(必须<256)      //timer2 min 8kHz
	//打开CTC模式
	TCCR2A |=(1 << WGM21);
	//将CS21位设置为8个预分频器
	TCCR2B |=(1 << CS21);   
	//启用定时器比较中断
	TIMSK2 |=(1 << OCIE2A);

	pinMode(13,OUTPUT);
	
	sei(); //允许中断
}

//Timer0中断函数
ISR(TIMER0_COMPA_vect){
  
}

//Timer1中断函数
ISR(TIMER1_COMPA_vect){// timer1中断1Hz切换引脚13(LED)
//产生频率为1Hz / 2 = 0.5kHz的脉冲波(全波切换为两个周期,然后切换为低)
 if(toggle1){
    digitalWrite(13,HIGH);
    toggle1 = 0;
  }
  else
  {
    digitalWrite(13,LOW);
    toggle1 = 1;
  }
 
}

void loop() 
{
}

随笔

初写博客,诸多问题还请各位包涵,有疑问欢迎留言,我们再继续谈论。

参考文献

[1] https://www.robotshop.com/community/forum/t/arduino-101-timers-and-interrupts/13072

你可能感兴趣的:(Arduino定时中断)