ndfweb.cn

Arduino uno定时器1的精确定时


2020-02-22 21:06:00 (6638)


Arduino uno r3(atmega 328p), Arduino IDE 1.0.5环境

目的是使板子上的13管脚的LED灯隔一秒亮一次。
原理是计数器1/(晶振频率*分频数) 秒会自加1,最后从初值加到65535(0xFFFF)再加一就溢出,计数器清零,计数器一溢出就可以调用溢出中断程序,程序里来改变管脚状态。
开始:

1) 初始化,需要配置相关的寄存器,使用定时器1(Timer/Counter1),因为只有它是16位的定时器,能定时超过一秒。
代码如下:

cli();关全局中断
TCCR1A=0; //寄存器A是配置PWM的,这里我们只是使用定时功能,其实不需要配置
TCCR1B=(1<<CS12)|(1<<CS10);//寄存器B是配置定时功能的,现在配置的是1024分频
TCNT1=0XC2F6; //计数器初值,1s定时
TIMSK1=(1<<TOIE1); //溢出中断使能

DDRB|=(1<<DDB5); //13管脚对应的是芯片上PB5,设置为输出
PORTB|=(0<<PORTB5); ////设置为低电平输出
sei(); //开全局中断 

大家的疑问是这个计数器TCNT1怎么设置?
根据技术文档是这样计算的: TCNT1=0Xffff - 定时时间/(分频数* (1/晶振频率))
分频数是调整计数的,越大计数越慢,一般有1、8、64、256、1024分频。
晶振频率就是板子上那个晶振,我的是16M,虽然这里说的是内部晶振,但这里不是这个实验的重点所以有疑问的请查看技术文档。
所以:TCNT1= 0XFFFF - 1 / (1024 *(1/16000000))= 0xFFFF –0x3D09=0XC2F6;

2) 接下来就是中断程序,网上很多写中断的例子,我都试过但失败了,最后去查看interrupt.h才找到中断程序的定义使用(仅限Arduino IDE),格式:

ISR(中断向量){

中断程序;

}

代码如下:
ISR(TIMER1_OVF_vect){ // TIMER1_OVF_vect是中断溢出向量,不同芯片具体定义还是要去头文件定义和技术文档查看,执行溢出中断程序后,溢出标志位自动清零,不需要置零

TCNT1=0XC2F6; //设置计数器为初值重新技术
PORTB=(~PORTB)&(1<<PORTB5); //改变PB5的电平,高变低,低变高

}

3) 试编译,修改语法错误。
完整程序代码:
#include <interrupt.h>
#include <iom328p.h>
#define FOCS 16000000

void DEVICE_INIT(void){
cli();
TCCR1A=0;
TCCR1B=(1<<CS12)|(1<<CS10);
TCNT1=0XC2F6;
TIMSK1=(1<<TOIE1);
DDRB|=(1<<DDB5);
PORTB|=(0<<PORTB5);
sei();
}

ISR(TIMER1_OVF_vect){
TCNT1=0XC2F6;
PORTB=(~PORTB)&(1<<PORTB5);
}

void setup(){
DEVICE_INIT();

}
void loop(){

}

注意:
1)#include<interrupt.h>,要的,不然ISR就提示出错!
2)不同的模式计算计数器TCNT1值有不同,需要查询技术文档!
3)中断程序不执行的情况先看第一条,否则就是你晶振频率弄错或者分频数太小,导致灯闪频率太快,看不出变化,其实已经执行。

了解更多请访问:http://www.ndfweb.cn/news-776.html
  NDF俱乐部
  国际域名注册
  建站咨询
合作伙伴:万网 | 新网 | 新网互联 NDF网站建设淘宝店 | 实用工具 | 外貿網站建設 | 联系我们
鲁公网安备 37110202000336号 鲁ICP备2021027697号-1 Sitemap - RSSRSS订阅