ndfweb.cn

Arduino uno定時器1的精確定時


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



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网站建设淘宝店 | ICO图标在线生成 | 外贸网站建设 | 联系我们
©2007-2025 NDF Corporation 鲁ICP备08005967号 Sitemap - RSSRSS订阅