2011年7月13日 星期三

4.1) Blink with Timer

實驗目的
使用 Timer 計算時間,讓一顆燈號閃爍,每隔一秒切換一次燈號。
材料
  • Arduino 主板 x 1
  • LED x 1
接線
  • 把 LED 接到 Arduino 板子上,LED 長腳 (陽極) 接到 pin13,短腳 (陰極) 接到 GND,如下圖:

image

程式碼

先來看 Arduino 版本的 Blink 程式:

這支程式是 Arduino 的入門程式,相信你應該很熟悉。

接下來我們改用 Timer 改寫程式,利用 Timer1 計算一秒鐘的時間:

以 Arduino UNO 或 Duemilanove 為例,它們的時脈頻率是 16 MHz,如果把 Timer1 的 prescaler 設成 CPU clock/1024,那麼 Timer1 的 clock 便是:

Timer1 的時脈 = 16 MHz/1024 = 15625Hz

所以 Timer1 從 0 數到 15625 就是一秒鐘的時間。Timer1 是 16-bit 的,最大值可以到 65535。

把 Prescaler 設成 CPU clock/1024 的方法是:

使用中斷

底下的程式是改用 Timer Overflow 中斷的版本:

這次 Prescaler 仍然使用 CPU clock/1024,所以,要算一秒鐘,一樣是讓 Timer1 從 0 數到 15625 就可算出。除了啟用 Timer overflow 中斷外,我們還得寫個 ISR:

當發生中斷跑到 ISR 時,代表時間已經經過 1 秒鐘,所以接著就切換燈號,然後再把 -15625 載入到 TCNT1,讓 Timer1 在一秒鐘後再次觸發中斷。

我們也可以不用 Prescaler,像這樣:

不用 Prescaler 的時候,Timer 的 clock 就是 16 MHz:

Timer1 overflow frequency =  16 MHz/65536 = 244 Hz

所以只要發生 244 次 Timer overflow 中斷,就代表已經過了 1 秒鐘的時間。

補充說明

因為 Timer0 已經被 Arduino 拿去用了,所以這篇教學使用 Timer1 示範。

延伸閱讀

3 意見:

Sven Wang 提到...

又要請教您了Cooper~~ 希望不會太麻煩你!

1.請問TCCR1A跟 TCNT1都是暫存器

為什麼TCCR1A的編輯方式使用16進位
而TCNT1使用十進位呢?
如下:
TCCR1A=0x00
TCNT1=0

2.請問當我們啟動TIMER1中斷後, TIMER1_OVF_vect中斷發生的條件是什麼呢?

ISR (TIMER1_OVF_vect)
{
PORTB ^= _BV(5);
TCNT1 = -15625;
}

請問是超過65535就發生中斷嗎?
如果是的話 為什麼不設定TCNT1=(65535-15625)呢?

麻煩Cooper解惑~~~真的很感謝!!

coopermaa 提到...

Hi, 不麻煩

1. TCNT1 = 0; 跟 TCNT1 = 0x00; 兩種寫法結果是一樣的,都是歸零,所以怎麼寫都沒差。

2. 沒錯,是超過 65535 就會發生中斷

TCNT1 = -15625,這行是利用二的補數 (負數表示法) 來設定 TCNT1。

這行

TCNT1 = -15625;

跟這行

TCNT1 = 65536 - 15625;

這兩行其實是異曲同工,作用是一樣的喔!

Sven Wang 提到...

Got it!! Thx~~~~ :))