Atmel Tiny88 16-bit Timer

  1. 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 位元的資料,需要兩次的指令才能完成,擔心在兩資指令中,若有中斷產生,容易產生資料錯誤,所以在存取時,建議關閉中斷。程式範例如下:

  1. 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 &lt< COM1A0);    
        TIMER1_SET_CTC_MODE_B();    
        TCCR1B = (1 &lt< WGM12);
        /* setup to 10 ms */
        TIFR1 |= (1 &lt< OCF1A);  
        /* Clear Interrupt Flag */
        TIMSK1 |= (1 &lt< OCIE1A);   
        /* Force Output Compare for Channel A */
        OCR1A = 0x0009;    
        /* 10 ms */
        TCCR1B |= ((1 &lt< CS12) | (1 &lt< 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 &lt< 7);
        }
    }
    
    1. Reference Document

    • doc8008.pdf - ATtiny 88 datasheet
    • doc2505.pdf - AVR130 : Using the timers on tinyAVR and megaAVR devices







留言

這個網誌中的熱門文章

EC 所需知識 - SMBUS

EC 所需知識 - KBC

EC 所需知識 - LPC