目录
一、定时器中断库函数方式说明
1、定时器中断编号和引脚说明
2、库文件安装
3、MsTimer2库文件使用
4、TimerOne库文件使用
5、注意事项
二、定时器的寄存器配置说明
1、定时器寄存器列表说明
2、Timer0寄存器说明
3、预分频系数与比较匹配器
4、定时器模式
Arduino种关于定时器中断和PWM讲解的一些博客教程
https://blog.csdn.net/xq151750111/article/details/114885341
https://blog.csdn.net/weixin_51055384/article/details/124114222
https://blog.csdn.net/linZinan_/article/details/127832771
Arduino 定时器中断_arduino定时器中断-CSDN博客
Arduino不同开发板对应的定时器编号和对应引脚
项目-加载库-库管理器,搜索和安装MsTimer2库文件
使用MsTimer2库文件,实现定时器中断实现Led输出500毫秒闪烁
代码
#include
#define Led 22
//自定义中断响应函数
void MyTimerFlash()
{
static boolean output = HIGH;
digitalWrite(Led, output);
output = !output;
}
void setup()
{
pinMode(Led, OUTPUT);
MsTimer2::set(500, MyTimerFlash); // 500ms period
MsTimer2::start(); // enables the interrupt.
// MsTimer2::stop(); // disables the interrupt.
}
void loop()
{
}
使用TimerOne库文件, timer1 产生自定义载波频率下不同 pwm 占空比输出 和定时器中断。
实现功能:使用TimerOne库文件,实现定时器中断实现Led输出500毫秒闪烁
库文件安装
代码
#include
#define Led 22
void callback()
{
static boolean output = HIGH;
digitalWrite(Led, output); // 状态翻转
output = !output;
}
void setup()
{
pinMode(Led, 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----UNO开发板定时器1引脚9、10
Timer1.pwm(11, 512); // setup pwm on pin 9, 50% duty cycle----MEGA开发板定时器1引脚11、12
Timer1.attachInterrupt(callback); // attaches callback() as a timer overflow interrupt
}
void loop()
{
}
(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( )都会改变 Prescale
定时器对于单片机来说就类似我们现实生活中的时钟,记录很多和时间相关的事件。在我们平时经常使用的 delay() millis() ,micros() ,delayMicroseconds() ,PWM 波生成的 analogWrite() 和 tone() 函数都是通过定时器实现的,不过这些都被 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位的寄存器。
寄存器列表如下,x代表0,1,2,3,4,5这6种定时器。
Timer0 的寄存器。其它的寄存器参见:https://download.csdn.net/download/xq151750111/15867135
Arduino UNO 时钟以16MHz运行。计数器的一个刻度值表示 1 / 16,000,000秒(~63ns),跑完1s需要计数值16,000,000。
(1)Timer0 和 Timer2 是8位定时器,可以存储最大计数器值255。
(2)Timer1 是一个16位定时器,可以存储最大计数器值65535。
一旦计数器达到其最大值,它将回到零(这称为溢出)。因此,需要对时钟频率进行分频处理,即预分频器。通过预分频器控制定时计数器的增量速度。预分频器与定时器的计数速度如下:
定时器速度(HZ) = Arduino UNO时钟速度(16MHz) / 预分频器系数
因此,1预分频器将以16MHz递增计数器,8预分频器将在2MHz递增,64预分频器= 250kHz,依此类推。
定时器 Timer0 的预分频系数配置如表:
定时器可以配置为不同的模式。
(1)PWM模式。 纸浆宽度调制模式。 OCxy输出用于生成PWM信号
(2)CTC模式。 比较匹配时清除计时器。 当定时器计数器到达比较匹配寄存器时,定时器将被清除。
定时器 Timer0 的模式选择配置如表:
5、 不同型号的开发定时器的配置
int toggle0,toggle1,toggle2;
void setup(){
cli();关闭全局中断
//设置定时器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 = 1999;// = (16*10^6)/(1000*8) - 1 (must be <65536)
TCCR1B |= (1 << WGM12);//打开CTC模式
TCCR1B |= (1 << CS11);//设置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();//打开全局中断
}
//中断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)
//产生频率为2Hz / 2 = 1Hz的脉冲波
if(toggle1>=500)
digitalWrite(13,HIGH);
if(toggle1<=500)
digitalWrite(13,LOW);
toggle1 += 1;
if(toggle1 >= 1000)
toggle1 = 0;
}
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(){
}