Arduino的定时器功能

Arduino的定时器功能

引言:

在开发Arduino的过程中,我们往往使用已经封装好的API,对于一些延时或定时器的操作,也有一些封装好的API可供使用,比如millis()、delay(ms)、analogWrite(pin, value)、pulseIn(EchoPin, HIGH)等等,但这些都是写死的API,无法做到像51和32单片机那样自己定义中断服务函数的内容!这些API的底层其实也是操作定时器相关的寄存器来实现的,自己去配置好寄存器,即可自己定义中断服务函数的内容(自定义了指定的定时器相关的配置,原本Arduino的一些API将不能使用,后面将给出对应关系)。

Arduino Uno的定时器:time0(8位)、time1(16位)、time2(8位)

Arduino Mega 2560的定时器:time0(8位)、time1(16位)、time2(8位)、time3(16位)、time4(16位)、time5(16位)

MsTimer2(定时器2)、TimerOne(定时器1)库的使用

定时器对应的API:

定时器0:delay()|、millis()、micros();

定时器1:Servo库(Mega 2560为定时器5);

定时器2:tone() ;

定时器对应Arduino Uno的PWM口:

定时器0:PWM口:5、6(默认976Hz)

定时器1:PWM口:9、10(默认490Hz)

定时器2:PWM口:11、3(默认490Hz)

注意:Uno板子的11脚不能同时使用PWM和SPI协议的功能

定时器对应Arduino Mega 2560的PWM口:

定时器0:PWM口:4、13

定时器1:PWM口:11、12

定时器2:PWM口:9、10

定时器3:PWM口:2、3、5

定时器4:PWM口:6、7、8

定时器5:PWM口:44、45、46

申明:本博客参考的其他博客:arduino 定时器、定时中断与PWM使用以及注意事项、[arduino 计时器和中断](arduino 计时器和中断_arduino timer-CSDN博客)、[【Arduino学习笔记】系列1 - 定时器配置](【Arduino学习笔记】系列1 - 定时器配置_tccr0b-CSDN博客)、[Arduino Uno 定时器中断 timer 0,1, 2 (自定义配置、MsTimer2、TimerOne库)](Arduino Uno 定时器中断 timer 0,1, 2 (自定义配置、MsTimer2、TimerOne库)-CSDN博客)、[AVR定时计数器1的控制寄存器说明](AVR定时计数器1的控制寄存器说明 - 百度文库 (baidu.com))。如有侵权,请联系删除

1.定时器相关的寄存器

8/16位的T/C 可以实现精确的程序定时( 事件管理) 、波形产生和信号测量。其主要特点如下:

  • 真正的16位设计( 即允许16位的PWM)
  • 2 个独立的输出比较单元
  • 双缓冲的输出比较寄存器
  • 一个输入捕捉单元
  • 输入捕捉噪声抑制器
  • 比较匹配发生时清除寄存器( 自动重载)
  • 无干扰脉冲,相位正确的PWM
  • 可变的PWM 周期
  • 频率发生器
  • 外部事件计数器
  • 4 个独立的中断源(TOV1 、 OCF1A 、OCF1B与ICF1)
1.1 T/C1 控制寄存器 - TCCR1A、TCCR1B

在这里插入图片描述

在这里插入图片描述

Bit 7:6 – COM1A1:0: 通道A 的比较输出模式

Bit 5:4 – COM1B1:0: 通道B 的比较输出模式

COM1A1:0 与COM1B1:0 分别控制OC1A 与OC1B 状态。如果COM1A1:0 (COM1B1:0 )的一位或两位被写入"1”,FOC1A( FOC1B) 输出功能将取代 I/O 端口功能。此时 FOC1A(FOC1B)相应的输出引脚数据方向控制必须置位以使能输出驱动器。

OC1A(OC1B) 与物理引脚相连时, COM1x1:0 的功能由WGM13:0的设置决定。下表给出当WGM13:0设置为普通模式与CTC模式( 非PWM) 时COM1x1:0 的功能定义。

比较输出模式,非PWM

在这里插入图片描述

WGM11、WGM10及WGM13、WGM12:配置定时器工作模式;CS12、CS11、CS10:配置定时器的分频系数

WGM13:0设置为快速PWM 模式时COM1x1:0 的功能定义。比较输出模式,快速 PWM。比较输出模式,相位修正及相频修正 PWM 模式

在这里插入图片描述
Bit 3 – FOC1A: 通道A 强制输出比较

Bit 2 – FOC1B: 通道B 强制输出比较

FOC1A/FOC1B 只有当WGM13:0指定为非PWM模式时被激活。为与未来器件兼容,工作

在PWM 模式下对TCCR1A写入时,这两位必须清零。当 FOC1A/FOC1B 位置1 ,立即

强制波形产生单元进行比较匹配。COM1x1:0 的设置改变 OC1A/OC1B 的输出。注意FOC1A/FOC1B 位作为选通信号。COM1x1:0 位的值决定强制比较的效果。

在CTC模式下使用OCR1A 作为TOP值,FOC1A/FOC1B 选通即不会产生中断也不好清除定时器。FOC1A/FOC1B 位总是读为0。

波形产生模式的位描述

在这里插入图片描述

注: 1. CTC1 和 PWM11:0 的定义已经不再使用了,要使用WGM12:0 。但是两个版本的功能和位置是兼容的。

CNC1: 入捕捉噪声抑制器

置位ICNC1 将使能输入捕捉噪声抑制功能。此时外部引脚ICP1 的输入被滤波。其作用

是从ICP1 引脚连续进行4 次采样。如果4 个采样值都相等,那么信号送入边沿检测器。因此使能该功能使得输入捕捉被延迟了4 个时钟周期。

ICES1: 输入捕捉触发沿选择

该位选择使用ICP1 上的哪个边沿触发捕获事件。ICES 为"0” 选择的是下降沿触发输入捕捉;ICES1 为"1” 选择的是逻辑电平的上升沿触发输入捕捉。

按照ICES1 的设置捕获到一个事件后,计数器的数值被复制到 ICR1 寄存器。捕获事件还会置为ICF1。如果此时中断使能,输入捕捉事件即被触发。

当ICR1 用作TOP值(见TCCR1A与TCCR1B寄存器中WGM13:0位的描述 ) 时,ICP1

与输入捕捉功能脱开,从而输入捕捉功能被禁用。

时钟选择位描述

在这里插入图片描述

2.TCNT1H 与 TCNT1L寄存器

在这里插入图片描述

TCNT1H 与TCNT1L 组成了T/C1的数据寄存器TCNT1。通过它们可以直接对定时器/计数器单元的16位计数器进行读写访问。为保证CPU对高字节与低字节的同时读写,必须使用一个8 位临时高字节寄存器TEMP 。TEMP 是所有的16位寄存器共用的,在计数器运行期间修改TCNT1的内容有可能丢失一次TCNT1与OCR1x的比较匹配操作。写TCNT1寄存器将在下一个定时器周期阻塞比较匹配。

3.输出比较寄存器 1A - OCR1AH与 OCR1AL

在这里插入图片描述

4.输出比较寄存器 1B - OCR1BH与OCR1BL

在这里插入图片描述

该寄存器中的16位数据与TCNT1寄存器中的计数值进行连续的比较,一旦数据匹配,将产生一个输出比较中断,或改变OC1x 的输出逻辑电平。输出比较寄存器长度为16位。为保证CPU对高字节与低字节的同时读写,必须使用一个8 位临时高字节寄存器TEMP 。

5.输入捕捉寄存器 1 - ICR1H 与ICR1L

在这里插入图片描述

当外部引脚ICP1(或 T/C1的模拟比较器)有输入捕捉触发信号产生时,计数器TCNT1中的值写入ICR1 中。ICR1 的设定值可作为计数器的TOP值。输入捕捉寄存器长度为16位。为保证CPU对高字节与低字节的同时读写,必须使用一个8 位临时高字节寄存器TEMP 。

6.中断屏蔽寄存器- TIMSK

在这里插入图片描述

OCIE为比较匹配中断允许标志位,TOIE为溢出中断允许标志位。

OCIE1A、OCIE1B:比较匹配中断允许;TOIE1:溢出中断允许

7. 中断标志寄存器- TIFR

在这里插入图片描述

OCF为比较匹配中断标志位,TOV为溢出中断标志位

ICF1: T/C1 输入捕捉标志位

外部引脚ICP1 出现捕捉事件时ICF1 置位。此外,当ICR1 作为计数器的TOP值时,一旦计数器值达到TOP,ICF1 也置位。执行输入捕捉中断服务程序时ICF1 自动清零。也可以对其写入逻辑"1” 来清除该标志位。

实验程序:
1.time1的匹配模式(CTC)实现定时器的功能
#define ledPin 13
void setup()
{
  pinMode(ledPin, OUTPUT);
  // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;  //先将整个TCCR0A寄存器设置为0
  TCCR1B = 0;  //先将整个TCCR0B寄存器设置为0
  TCNT1  = 0;  //将计数器值初始化为0
  OCR1A = 31250;            // compare match register 16MHz/(256*31250)= 2Hz   每0.5s执行一次中断服务函数
  TCCR1B |= (1 << WGM12);   // CTC mode
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
  interrupts();             // enable all interrupts
}


ISR(TIMER1_COMPA_vect)          // timer compare interrupt service routine
{
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);   // toggle LED pin
}

void loop()
{
  // your program here…
}
2.time1的普通模式实现定时器的功能
#define ledPin 13
void setup()
{
  pinMode(ledPin, OUTPUT);
  // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 34286;            // preload timer 65536-16MHz/256/2Hz
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
}

ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  TCNT1 = 34286;            // preload timer
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);
}

void loop()
{
  // your program here...
}
3.通过time0/1/2输出PWM波(软件PWM,频率高了会波形不稳定)
  int toggle0,toggle1,toggle2;
  void setup(){

  cli();//noInterrupts();           // disable all interrupts  关闭全局中断
/*
  //设置定时器0为10kHz(100us)
  TCCR0A = 0;//将整个TCCR0A寄存器设置为0
  TCCR0B = 0;//将整个TCCR0B寄存器设置为0
  TCNT0  = 0;//将计数器值初始化为0
  //设置计数器为10kHZ,即100us
  OCR0A = 24;//比较匹配寄存器= [16,000,000Hz /(预分频器*所需中断频率)] - 1
             //比较匹配寄存器=24,中断间隔=100us即中断频率10khz
  TCCR0A |= (1 << WGM01);//打开CTC模式
  TCCR0B |= (1 << CS01) | (1 << CS00); //设置CS01位为1,CS00位为1(64倍预分频)   
  TIMSK0 |= (1 << OCIE0A);//启用定时器比较中断
*/

  //设置定时器1为1kHz
  TCCR1A = 0;//将整个TCCR1A寄存器设置为0
  TCCR1B = 0;//将整个TCCR1B寄存器设置为0
  TCNT1  = 0;//将计数器值初始化为0
  //设置计数器为1kHZ,即1ms
  OCR1A = 156;// = (16*10^6)/(1000*8) - 1 (must be <65536)       100hz/2
  TCCR1B |= (1 << WGM12);//打开CTC模式
  TCCR1B |= (1 << CS12)| (1 << CS10);// 1024分频                 设置CS11位为1(8倍预分频)
  TIMSK1 |= (1 << OCIE1A);

 /*
  //设置定时器2为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);//打开CTC模式
  // Set CS21 bit for 8 prescaler
  TCCR2B |= (1 << CS21);   
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);
*/

  sei();//interrupts();             // enable all interrupts  //打开全局中断

}

/*
//中断0服务函数
ISR(TIMER0_COMPA_vect){// timer0中断2Hz切换引脚13(LED)
//产生频率为10kHz / 2 = 5kHz的脉冲波
  if(toggle0){
    digitalWrite(8,HIGH);
    toggle0 = 0;
  }
  else{
    digitalWrite(8,LOW);
    toggle0 = 1;
  }
}
*/

ISR(TIMER1_COMPA_vect){// timer1中断2Hz切换引脚13(LED)  //中断优先级相同 3个中断中基本轮不到 执行不了
//产生频率为2Hz / 2 = 1Hz的脉冲波

/*
  if(toggle1>=500)
    digitalWrite(13,HIGH);
  if(toggle1<=500)
    digitalWrite(13,LOW);
  toggle1 += 1;
  if(toggle1 >= 1000)
    toggle1 = 0;
*/    
    if(toggle1){
    digitalWrite(13,HIGH);
    toggle1 = 0;
  }
  else{
    digitalWrite(13,LOW);
    toggle1 = 1;
}

}
 /* 
ISR(TIMER2_COMPA_vect){// timer2中断8kHz切换引脚9
//产生频率为8kHz / 2 = 4kHz的脉冲波
  if(toggle2){
    digitalWrite(9,HIGH);
    toggle2 = 0;
  }
  else{
    digitalWrite(9,LOW);
    toggle2 = 1;
  }
}
*/
//loop function
void loop()
{
  // your program here...
}
4.MsTimer2库的使用
#include <MsTimer2.h>
 
int led = 8;
 
void onTimer()
{
  digitalWrite(LED_BUILTIN, HIGH);
  delay(300);
  digitalWrite(LED_BUILTIN, LOW);
  delay(300);
}
 
void setup() {
 
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  MsTimer2::set(1000, onTimer); //设置中断,每1000ms进入一次中断服务程序 onTimer()
  MsTimer2::start(); //开始计时_开启定时器中
}
 
void loop() {
 
  digitalWrite(led, HIGH);
  delay(1000);
  digitalWrite(led, LOW);
  delay(1000);
}
5.TimerOne的使用
#include <TimerOne.h>
# 使用 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));	// 状态翻转
}

void loop()
{
// your program here...
}

6.Mega 2560板的time3
#define ledPin 13
void setup()
{
  pinMode(ledPin, OUTPUT);
  // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR3A = 0;
  TCCR3B = 0;
  TCNT3  = 0;
  OCR3A = 31250;            // compare match register 16MHz/256/2Hz
  TCCR3B |= (1 << WGM32);   // CTC mode
  TCCR3B |= (1 << CS32);    // 256 prescaler 
  TIMSK3 |= (1 << OCIE3A);  // enable timer compare interrupt
  interrupts();             // enable all interrupts
}


ISR(TIMER3_COMPA_vect)          // timer compare interrupt service routine
{
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);   // toggle LED pin
}

void loop()
{
  // your program here…
}
7.Mega 2560板的time4
#define ledPin 13
void setup()
{
  pinMode(ledPin, OUTPUT);
  // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR4A = 0;
  TCCR4B = 0;
  TCNT4  = 0;
  OCR4A = 31250;            // compare match register 16MHz/256/2Hz
  TCCR4B |= (1 << WGM42);   // CTC mode
  TCCR4B |= (1 << CS42);    // 256 prescaler 
  TIMSK4 |= (1 << OCIE4A);  // enable timer compare interrupt
  interrupts();             // enable all interrupts
}


ISR(TIMER4_COMPA_vect)          // timer compare interrupt service routine
{
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);   // toggle LED pin
}

void loop()
{
  // your program here…
}
8.Mega 2560板的time5
#define ledPin 13
void setup()
{
  pinMode(ledPin, OUTPUT);
  // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR5A = 0;
  TCCR5B = 0;
  TCNT5  = 0;
  OCR5A = 31250;            // compare match register 16MHz/256/2Hz
  TCCR5B |= (1 << WGM52);   // CTC mode
  TCCR5B |= (1 << CS52);    // 256 prescaler 
  TIMSK5 |= (1 << OCIE5A);  // enable timer compare interrupt
  interrupts();             // enable all interrupts
}


ISR(TIMER5_COMPA_vect)          // timer compare interrupt service routine
{
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);   // toggle LED pin
}

void loop()
{
  // your program here…
}
  • 18
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值