查看: 1083|回复: 1
打印 上一主题 下一主题

atmega 328p的定时器1的精确定时

[复制链接] qrcode

32

主题

37

帖子

110

积分

注册会员

Rank: 2

积分
110
楼主
跳转到指定楼层
发表于 2014-10-22 01:14 PM | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我花了一个星期在学习使用atmega 328p的定时器来精确定时,最后成功学会使用。下面我将给大家总结一下我的经验:
使用的材料就只有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< TCNT1=0XC2F6; //计数器初值,1s定时
TIMSK1=(1<
DDRB|=(1< PORTB|=(0< 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<
}

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

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

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

void setup(){
DEVICE_INIT();

}
void loop(){

}

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

1

主题

87

帖子

25

积分

新手上路

Rank: 1

积分
25
沙发
发表于 2014-10-22 08:37 PM | 只看该作者
谢谢分享          很不错 
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表