Atmel Tiny88 16-bit Timer
Introduction
計時器是一個簡單的計數器 ,它的優點是系統程式在執行時,也不會影響到它的準確度。當然要有準確的系統時脈,才能讓計時器的時間是準確的。AVR 會有兩種計時器,分別為 8-bit 計時器和 16-bit 的計時器,這篇文章僅介紹 16-bit 計時器。
16-bit 計時器的特性:
- 16 位元的設計
- 兩個計數值比較單位的獨立輸出
- 兩個資料緩衝區給輸出比較暫存器
- 一個輸入取樣單位
- 輸入取樣單位有消除雜訊功能
- 比較暫存器達標後自動清除(自動重新載入)
- 無鋸齒,正確相位脈波寬度調整器(PWM)
- 多種週期的脈波調整器
- 頻率產生器
- 外部事件計數器
- 四個獨立的中斷向量,分別為 TOV1 / OCF1A / OCF1B / ICF1
16位元計時器的方塊圖
相關的暫存器說明
- Timer/Counter 1 (TCNT1) - 計數器/計時器 #1
- Output Compare Register (OCR1 A/B) - 比較器暫存器 #1 A/B 輸出,計數值和目標值相同時輸出。
- Input Capture Register (ICR1) - 取樣暫存器
- Timer Interrupt Flag Register (TIFR1) - 紀錄中斷旗標暫存器
- Interrupt Mask Register (TIMSK1) - 中斷的開關
Timer/Counter Clock Source
Timer/Counter 的時脈來源 -
- 外部的時脈產生器
- 內部的 System Clock - 內部的 System Clock 可以設定經除頻器後再送到 Timer/Counter 模組。由暫存器 Timer/Counter Control Register B(TCCR1B) 的 Clock Select (CS1[2:0]) 來決定時脈的來源。
Counter Unit
Timer/Counter 是一個雙向(可以上數/下數)計數器,其方塊圖如下:
方塊圖中訊號的說明 -
- CLKTn - Timer/Counter 時脈輸入
- Count - 計數加/減 1
- Clear - 清除計數器
- Direction - 計數方向
- TOP - 設定計數器的最大值
- BOTTOM - 設定計數器的最小值
16-bit 的 Counter
- 由兩個 8 bit 的計數暫存器(Counter High (TCNTH) 和 Counter Low (TCNTL) 所組合而成。
- CPU 可以透過間接定址的方法由暫存的暫存器取得 16-bit Counter 的數值,在存取TCNTL 暫存器時,TCNTH 就會放到 TEMP 暫存器,所以只需要一個 CPU Clock 就可以取得計數器的值。
- 可以用來產生不同週期/寬度的脈波,需要設定 Timer/Control Control Register A/B (TCCR1A/B) 的 Waveform Generation Mode (WGM1[3:0]),再由 Output Compare (OC1x) 輸出波形。
- 當計數器達到目標值時,會產生中斷,並設定 Timer/Counter Overflow Flag (TOV1)。關於 TOV1 的工作模式由 WGM1[3:0] 來設定。
- 除了計數系統的時脈外,也可以用來計數外部的事件,並且可以配合內部的計時器,取得事件發生的頻率/事件的時間等。事件的取樣可以來自 ICP1接腳或是類比比較接腳。事件取樣的方塊圖如下:
Input Capture Unit
計數信號的來源
- Input Capture Pin (ICP1)
- Analog Compare Output (ACO)
- 取樣線路就會取得觸發事件後,TCNT1 就會寫入 Input Capture Register (ICR1),並設定 Input Capture Flag (ICF1) 就會被設定。如果 Input Capture Interrupt Enable (ICIE1) 是 Enable 的話,就會產生中斷。直到中斷服務程式執行後,ICF1 就會被清除。
- ICR1 和 TCNT1 一樣,在存取 ICR1L 暫存器時,ICR1H 就會放到 TEMP 暫存器中,程式可以在一個 CPU Clock 中取出 ICR1 的數值。ICR 暫存器可使用 WGM1[3:0] 來產生脈波的輸出。
- Noise Canceler 用於減少雜訊的影響,採樣連續 4 個都相同時,認定觸發事件是有效的,Noisr Cancleer 的功能,設定在 Timer/Capture Control Register B (TCCR1B) 的 Input Capture Noise Canceler (ICNC1) 的位元。
Output Compare Unit
- 當內部的計數器和 Output Compare Register (OCR1x) 相等時,下一個時脈時,將設定 Output Compare Flag (OCF1x)。
- 如果 Output Compare Interrupt Enable (OCIE1x) 是 Enable 的話,將會產生 Output Compare Interrupt。
- 當 Interrupt Service 完成後,OCF1x 就會目動清除。16-bit Counter 的 OCR1x 搭配 Waveform Generator Mode (WGM1[3:0]),Compare Output Mode (COM1x[1:0]) 位元,TOP 和 BOTTON 產生不同的脈波。
Output Compare Unit 的方塊圖如下:
- Douboe Buffered 使用於 Pulse Width Modulation (PWM) 的 12 個工作模式,Normal and Clear Timer on Compare (CTC) mode 工作模式並不會使用 Double Buffered。Doubled Buffered 只在 TOP/BOTTON 時,才會同步來避免鋸齒波的產生。
- 當 Doubled Buffer Enable 的時侯,CPU 讀取 OCR1x Buffer Register 而不是 OCR1x Register。
- 在讀取 OCR1x 時,建議先讀 OCR1xL,在寫入 OCR1x 時,必須透過 TEMP 暫存器,先填入 OCR1xH。
- 工作模式
- Force Output Compre
在這個模式下,需設定Force Output Compare 位元,計數到目標值時,OC1x 會根據COM1[1:0] 的設定變動。
- Compare Match Blocking by TCNT1 Write
當 CPU 要變更 TCNT1 暫存器,暫存器將被鎖住 1 個時脈期間,即使下一個時脈將達到目標值或計數器的停止的。如果 TCNT1 寫入的值和 OCR1x 是相同的,在啟動後,並不會發出中斷。
- Using the Output Compare Unit
當 CPU 要變更 TCNT1 暫存器,暫存器將被鎖住 1 個時脈期間。如果 TCNT1 寫入的值和 OCR1x 是相同的,將會錯過達到目標值的觸發。也不要等於 TOP/BOTTON 值,也會錯過觸發。
OC1x 必須在 Data Direction Register 設定前,先完成設定。最簡單的設定方法,在 Normal Mode,設定 Force Output Compare 位元;其他的模式就不需要改變。
Compare Match Output Unit
Compare Output Mode (COM1x[1:0]) 有兩個功能 -
- 第一個功能是在 Waveform Generator 的功能下,當計數到目標值時,用來設定 Output Compare (OC1x) 狀態。
- 第二個功能是直接操控 OC1x 的狀態。
Compare Match Output Unit 的方塊圖如下:
由方塊圖得知,OC1x 的輸出腳由 OC1x 和 GPIO 共同控制,當 Waveform Generator 開啟後,OC1x 的輸出就由 OC1x 暫存器控制。當系統 reset 時,OC1x 暫存器就會被清為 0。
Mode of Operation
16-bit Timer/Couter 的工作模式是由 Waveform Generation Mode (WGM1[3:0]) 位元和 Compare Output Mode (COM1[1:0]) 位元所組合而成。
WGM1[3:0] 位元定義 -
COM1[1:0] 位元定義 -
- non-PWM Mode -
- Fast PWM Mode -
- Phase Correct and Phase & Frequency Correct PWM
Normal Mode
- WGM1[3:0] = 0
- 計數器只能上數,由 BOTTOM (0x0000) 計數到 MAX (0xFFFF) 再由 BOTTOM 重新計數。
- 計數器計數到最大值時,會在同一個時脈中,會同時設定 Timer/Counter Overflow Flag (TOV) 和把 TCNT1 清為 0。任何時刻都可以修改計數器的值。
- Input Capture Unit 來當計數來源的話,需要考量到事件發生的時間,可以使用 pre-scaler 取得最符合的計時器。
- Output Compare Unit 用來產生中斷,並不建設在這個模式來產生 Waveform。
Clear Timer on Compare Match Mode (CTC)
- WGM1[3:0] = 4 / 12
- 當 TCNT1 的計數值等於 OCR1A / ICR1 時,產生中斷,計數器就會清除為 0。
- 當發生中斷時,程式在中斷服務程式中,修改 OCR1A / ICR1 時,就會產生如下的 Timer Diagram 圖形。
- 將 Compare Output Mode 設定為 Toggle Mode (COM1A[1:0]=1) 來產生脈波。脈波的頻率為
N : prescale factor (1 / 8 / 64 / 256 / 1024 )
Fast PWM Mode
- WGM1[3:0] = 5 / 6 / 7 / 14 / 15
- 用於產生高速的 PWM 波形
- 單斜率計數,由 BOTTOM 計數到 TOP 後,再由 BOTTOM 重新計數。當 TCNT1 等於 OCR1x 時,設定 OC1x 接腳,之到 TCNT1 等於 TOP 時,才會清除。
- PWM 可以使用 8 / 9 / 10 位元,最小為 2 位元 (0x03),最大為 16 位元。
- 計數目標值 -
WGM1[3:0]
|
Target
|
WGM1[3:0]
|
Target
|
5
|
0x0FF
|
14
|
ICR1
|
6
|
0x1FF
|
15
|
OCR1A
|
7
|
0x3FF
|
- 當程式使用 OCR1A / ICR1 來設定 TOP 值,當 TCNT1 等於 OCR1A / ICR1 的值就會一個中斷。在中斷服務程式中,變更較高的 OCR1A / ICR1 值,TCNT1計數到新的 OCR1A / ICR1,就會產生中斷;如果變更較低的 OCR1A / ICR1值,比較將無法成立,也不會產生中斷。Timer Diagram 如下:
- Timer/Counter Overflow Flag(TOV1) - 當計數器計到 TOP,TOV1 就會設定,若中斷有開啟,就會產生中斷。
- OCR1A 是 Doubled Buffer 暫存器,修改 OCR1A 的值時,需把修改的值放到 Buffer OCR1A 暫存器,等到 TCNT1 達到 TOP 值,Buffer OCR1A 的值會自動變更到 OCR1A。
- PWM 的頻率為
N : prescale factor (1 / 8 / 64 / 256 / 1024 )
Phase Correct PWM Mode
- WGM1[3:0] = 1 / 2 / 3 / 10 / 11
- 雙斜率計數,由 BOTTOM 上數到 TOP,再由 TOP 下數到 BOTTOM。
- PWM 可以使用 8 / 9 / 10 位元,最小為 2 位元 (0x03),最大為 16 位元。
- 計數目標值 -
WGM1[3:0]
|
Target
|
WGM1[3:0]
|
Target
|
1
|
0x0FF
|
10
|
ICR1
|
2
|
0x1FF
|
11
|
OCR1A
|
3
|
0x3FF
|
- OCR1A 是 Doubled Buffer 暫存器,修改 OCR1A 的值時,需把修改的值放到 Buffer OCR1A 暫存器,等到 TCNT1 達到 TOP 值,Buffer OCR1A 的值會自動變更到 OCR1A。Timer Diagram 如下:
- Timer/Counter Overflow Flag(TOV1) - 當計數器計到 BOTTOM,TOV1 就會設定,若中斷有開啟,在計數器等於 TOP 及 BOTTOM,就會產生中斷。
- PWM 的頻率為
N : prescale factor (1 / 8 / 64 / 256 / 1024 )
Phase and Frequency Correct PWM Mode
- WGM1[3:0] = 8 / 9
- 雙斜率計數,由 BOTTOM 上數到 TOP,再由 TOP 下數到 BOTTOM。
- 適合用於馬達控制
- 僅支援 ICR1 / OCR1A 來設定 TOP 的值
- OCR1A 是 Doubled Buffer 暫存器,修改 OCR1A 的值時,需把修改的值放到 Buffer OCR1A 暫存器,等到 TCNT1 達到 BOTTOM 值,Buffer OCR1A 的值會自動變更到 OCR1A。Timer Diagram 如下:
- Timer/Counter Overflow Flag(TOV1) - 當計數器計到 BOTTOM,TOV1 就會設定,若中斷有開啟,在計數器等於 TOP 及 BOTTOM,就會產生中斷。
- PWM 的頻率為
N : prescale factor (1 / 8 / 64 / 256 / 1024 )
Note
因為 Timer/Counter 是 16 位元的資料,需要兩次的指令才能完成,擔心在兩資指令中,若有中斷產生,容易產生資料錯誤,所以在存取時,建議關閉中斷。程式範例如下:
Sample Code
16-bit Timer CTC mode 的範例,在 2MHz 的 Tiny 88 MCU 上,建立一個 5ms 的 timebase 用來檢視週系統裝置的狀態。
- 16-bit Timer 的初始化
static volatile uint8_t s1secTimer=0; /* ! \brief timer #1 initialize * this function will initialize 16-bit timer #1 form timer base * for timing sharing system. * \note * None * \return * None */ void TIMER1_init(void) { /* setup timer1 CTC working mode and pre-scale /1024 core clock 1MHz , tick is 1024/1M = 1ms */ TCNT1 = 0x0000; TCCR1A = (1 << COM1A0); TIMER1_SET_CTC_MODE_B(); TCCR1B = (1 << WGM12); /* setup to 10 ms */ TIFR1 |= (1 << OCF1A); /* Clear Interrupt Flag */ TIMSK1 |= (1 << OCIE1A); /* Force Output Compare for Channel A */ OCR1A = 0x0009; /* 10 ms */ TCCR1B |= ((1 << CS12) | (1 << CS10)); s1secTimer = 0; }
16-bit Timer 的中斷服務程式
static volatile uint8_t s1secTimer=0; volatile uint8_t b5ms_TIMER=0; volatile uint8_t b10ms_TIMER=0; /* ! \brief TIMER1 Interrupt Service Routine * This function use to service TIMER1 interrupt * \note * None * \return * None */ ISR(TIMER1_COMPA_vect) { DISABLE_TIMER1_INTERRUPT(); /* Disable Timer #1 Interrupt */ s1secTimer ++; b5ms_TIMER = 1; if((s1secTimer % 2) == 1) { s1secTimer = 0; b10ms_TIMER = 1; } }
16-bit Timer 的主迴圈內的服務程式 - 縮短中斷服務程式所花的時間,把大部分的事情移到主迴圈內再執行。
volatile uint8_t b5ms_TIMER=0; /* ! \brief 5ms timer routine * this function will service 5ms timer event * \note * None * \return * None */ void T5msRoutine(void) { if(b5ms_TIMER) { PORTB ^= (1 << 7); } }
Reference Document
- doc8008.pdf - ATtiny 88 datasheet
- doc2505.pdf - AVR130 : Using the timers on tinyAVR and megaAVR devices
留言
張貼留言