2011年7月14日 星期四

4.2) Timer as a Counter

實驗目的

練習把 Timer1 當成 Counter 使用。

材料
  • Arduino 主板 x 1
  • Pushbutton x 1
  • 10K 歐姆電阻 x 1
  • 麵包板 x 1
  • 單心線 x N
接線
  • 把 pushbutton 一支腳接到 +5V,另一支腳接到 pin 2 同時接一顆 10K 電阻連到 GND

image

程式碼

image
▲ Atmega168/328 腳位對應圖,圖片來源: arduino.cc

Timer1 會在 T1/PD5 腳位(亦即 Arduino pin 5) 轉換電位時遞增。

image

至於要在什麼時候讓 Timer1 遞增呢? 我們有兩種選擇:

  1. FALLING: 當 pin 狀態從 HIGH 到 LOW 時遞增 ,稱為下降緣遞增 (clock on falling edge)
  2. RISING: 當 pin 狀態從 LOW 到 HIGH 時遞增,稱為上升緣遞增 (clock on rising edge)

我們也可以打開 Timer overflow 中斷,讓計數器溢位時觸發中斷 (以 Timer1 而言,超過 65535 時即溢位)。

底下這支程式示範把 Timer1 當成計數器使用,讓 Timer1 在 T1/PD5 腳位狀態為上升緣時遞增:

上傳這支程式到 Arduino,打開 Serial Monitor,然後按幾下按鍵測試,我得到底下的結果:

image
▲ Arduino 每秒會印出一次 TCNT1 的內容

請注意!在測試的時候,按鍵一次我只按一下,但是 TCNT1 的值有時候遞增 1,有時候卻遞增 3 (3 –> 6),有時了甚至遞增 7 (6 –> 13),並不是每一次都是遞增 1,這不是程式有問題,而是按鍵接觸彈跳 (contact bounce) 造成的,這是一個機械開關常見的問題,當按鍵接觸點碰撞在一起的時候,它們的動力和彈性會造成彈跳,結果是腳位電位會有如下圖的變化:

 

image
▲ 圖片來源: Button Debouncing

也就是說,腳位訊號並不是很乾淨的從 HIGH 到 LOW 的電位轉換。這個彈跳發生的時間非常短暫,可能只有幾微秒,不過這根本逃不過微控制器的慧眼,因為微控制器實在太敏銳了,因此雖然按鍵只按了一下,可是在發生彈跳時,腳位上會有好幾次電位轉換的事件,於是就全部被微控器計數到 TCNT1 中。這個問題的解法是去抖動 (Button Debouncing),不過這不在本文的討論範例內,請你參考延伸閱讀的資料。

計數紅外線訊號

Timer 也可以用來計數紅外線訊號。

你需要一個 38 kHz 的紅外線接收器 (如 TSOP2438,TSOP4438, PNA4602, FM-8038TM2-5DN),然後照下表把紅外線接收器跟 Arduino 連接起來:

紅外線接收器接腳 Arduino 接腳
GND(-) 接到 GND
Vcc(+ 或 V+) 接到 +5V 電源
Vout(或 OUT) 接到 pin 5

image

接著拿個遙控器就可以測試了,程式碼不用調整。

底下是隨手拿起一支電視遙控器測試得到的結果:

 image
▲ 每按遙控器一下,TCNT1 就遞增 34

可以看見,我每按一下遙控器,TCNT1 數值就遞增 34。

我遙控器講的是 NEC IR Protocol,它的訊號波形如下:

image

NEC IR Protocol 的 code 是 32 bits,再加上 Start bit (Leader Code) 和 Stop bit 總共是 34 bits,所以遙控器每按一下 TCNT1 就會遞增 34。

延伸閱讀

8 意見:

Sven Wang 提到...

請問Cooper

你在紅外線遙控原理那篇有提到

Pulse 是由很多 on/off 交替的訊號所組成:

Carrier frequency = 38kHz
duty factor = 1/3
period = 26.5us

請問為什麼這些560us寬的小pulse為什麼沒有被計算到count裡面呢?

coopermaa 提到...

在 mark 狀態,IR LED 會用特定的頻率送出 on/off 脈衝 (Pulse)

我們可以把 mark 狀態的 pulse 稱做 modulation,當紅外線接收器收到 modulated 的訊號時,接收器自己會把 demodulation 的動作

在 MCU/Arduino 這邊看到的是 demodulation 的結果,如果是 mark (有很多 pulse,但是已被接收器瀘掉) 就是 low level 訊號,而 space 則是 high level 訊號

Sven Wang 提到...

謝謝~~瞭解拉!!!

coopermaa 提到...

不客氣!
話說我去寫的 From Arduino To AVR 這系列單晶片教學,你是目前回應最多的一位。應該頒個獎給你才對,哈哈~

Sven Wang 提到...

頒發:最有問題獎XDDD
你的回覆才是給我們最棒的獎勵拉!! :))

coopermaa 提到...

謝謝!
讀書就是要懂得問問題啊!

xichiou 提到...

FALLING: 當 pin 狀態從 LOW 到 HIGH 時遞增 ,稱為下降緣遞增 (clock on falling edge)
RISING: 當 pin 狀態從 LOW 到 HIGH 時遞增,稱為上升緣遞增 (clock on rising edge)

以上是您文章內提到的,好像有問題?

coopermaa 提到...

我寫錯了:

「FALLING: 當 pin 狀態從 LOW 到 HIGH 時遞增 ,稱為下降緣遞增 (clock on falling edge)」

這句應該是這樣才對:

「FALLING: 當 pin 狀態從 HIGH 到 LOW 時遞增 ,稱為下降緣遞增 (clock on falling edge)」

謝謝你的訂正。 :)